np.where结合pandas抽样赋值异常问题排查求助
问题根源
你的代码存在两个核心逻辑错误,直接导致结果不符合预期:
两次np.where的赋值覆盖问题
你先对Low_Valence行执行np.where赋值,紧接着又对High_Valence行执行第二次np.where。第二次赋值时,所有不满足High_Valence条件的行(也就是所有Low_Valence的行)都会被强制设为'High',直接覆盖了第一次的操作结果——这就是为什么你的示例里所有Low_Valence行的temp_selection都是'High'的原因。抽样范围错误+reindex导致NaN
你用df['valence_median_split'].sample(n=200)是从整个列随机抽样,而不是从Low_Valence或High_Valence的分组内抽样。之后用reindex(df.index)会把抽样得到的少量值放到原索引位置,其余位置都是NaN。当np.where把这些NaN赋值给Low_Valence行后,第二次np.where会把这些NaN行(属于Low_Valence)判定为不满足High_Valence条件,进而设为'High'。同时,抽样得到的High_Valence值会被错误地赋值给部分High_Valence行,导致出现不该有的'High_Valence'标记。
解决方法
正确的思路是:先分别从两个分组内抽取目标行数的索引,再基于索引给temp_selection赋值,避免覆盖和抽样范围错误。
步骤1:抽取分组内的目标索引
先从Low_Valence和High_Valence各自的行中随机选出200个(或示例中的2个)索引:
# 获取Low_Valence分组的所有索引 low_indices = df[df['valence_median_split'] == 'Low_Valence'].index # 随机选200个(示例中选2个),replace=False确保不重复抽样 selected_low = np.random.choice(low_indices, size=200, replace=False) # 同理处理High_Valence分组 high_indices = df[df['valence_median_split'] == 'High_Valence'].index selected_high = np.random.choice(high_indices, size=200, replace=False)
步骤2:基于索引赋值
先初始化temp_selection为默认值,再根据选中的索引修改对应位置的值,避免覆盖:
# 先给所有行设默认值:Low_Valence组默认'Low',High_Valence组默认'High' df['temp_selection'] = np.where(df['valence_median_split'] == 'Low_Valence', 'Low', 'High') # 把选中的Low_Valence行改为'Low_Valence' df.loc[selected_low, 'temp_selection'] = 'Low_Valence' # 把选中的High_Valence行改为'High_Valence' df.loc[selected_high, 'temp_selection'] = 'High_Valence'
测试你的可复现示例
用你的小例子测试(size改为2):
d = {'col1': [1, 2, 3, 4, 3, 3, 2, 2], 'col2': [1, 2, 3, 4, 3, 3, 2, 2]} df = pd.DataFrame(data=d) valence_median = df['col1'].median() df['valence_median_split'] = np.where(df['col2'] < valence_median, 'Low_Valence', 'High_Valence') # 抽取索引 low_indices = df[df['valence_median_split'] == 'Low_Valence'].index selected_low = np.random.choice(low_indices, size=2, replace=False) high_indices = df[df['valence_median_split'] == 'High_Valence'].index selected_high = np.random.choice(high_indices, size=2, replace=False) # 赋值 df['temp_selection'] = np.where(df['valence_median_split'] == 'Low_Valence', 'Low', 'High') df.loc[selected_low, 'temp_selection'] = 'Low_Valence' df.loc[selected_high, 'temp_selection'] = 'High_Valence' print(df)
执行后会得到符合预期的结果:Low_Valence组里有2行标记为'Low_Valence',其余为'Low';High_Valence组里有2行标记为'High_Valence',其余为'High',不会出现NaN或错误的标记。
补充说明
- 如果你的分组行数不足200(比如
Low_Valence只有150行),可以把replace=True打开(允许重复抽样),或者根据实际行数调整抽样数量。 - 用
np.random.choice比直接用sample更灵活,能直接拿到索引,方便后续的loc赋值操作。
内容的提问来源于stack exchange,提问作者arkadiy

