多列DataFrame中通过布尔索引为指定列赋值
问题
我有一个多级列DataFrame,索引为日期,第一级列是股票代码,第二级列是不同字段X1、X2、Y,数据结构如下:
df stock1 stock2 stock3 X1 X2 Y X1 X2 Y X1 X2 Y 0 True False NaN False False NaN True False NaN 1 False True NaN True False NaN True False NaN 3 False False NaN True False NaN False True NaN 4 True False NaN False True NaN True False NaN
需求:利用X1和X2的布尔数组为Y赋值,规则是:
- X1为True时,Y设为1
- X2为True时,Y设为-1
- 两者都为False时,保留Y的原有NaN值
我尝试用pd.IndexSlice获取X1和X2的视图,df.loc[:, idx[:, 'X1']]能返回正确的布尔数组,但赋值时遇到问题。比如用以下代码:
df.loc[:, idx[:, 'Y']] = (df.loc[:, idx[:, 'X1']] * 1).values
无法满足需求,因为False值会把Y设为0,而我需要保留NaN。
解决方案
方法1:嵌套np.where精准匹配条件
通过两层np.where依次判断X1、X2的布尔值,最后返回NaN满足“都为False时保留空值”的要求:
import numpy as np import pandas as pd idx = pd.IndexSlice # 提取X1和X2的布尔矩阵 x1_mask = df.loc[:, idx[:, 'X1']] x2_mask = df.loc[:, idx[:, 'X2']] # 为Y列赋值 df.loc[:, idx[:, 'Y']] = np.where(x1_mask, 1, np.where(x2_mask, -1, np.nan))
方法2:先计算基础值再替换0为NaN
利用布尔值转整数的特性,先算出1/-1/0的结果,再把0替换成NaN:
idx = pd.IndexSlice # X1转1/0,X2转1/0后取负,相加得到1/-1/0的矩阵 y_values = df.loc[:, idx[:, 'X1']].astype(int) - df.loc[:, idx[:, 'X2']].astype(int) # 将0替换为NaN,匹配需求 y_values = y_values.replace(0, np.nan) # 赋值给Y列 df.loc[:, idx[:, 'Y']] = y_values.values
方法3:拆解多级列简化操作
如果对多级列操作不熟悉,可以先将二级列转为行索引,处理后再恢复原结构:
# 把股票代码(第一级列)转成行索引 df_unstacked = df.unstack(level=0) # 直接对每行的X1/X2判断赋值Y df_unstacked['Y'] = np.where(df_unstacked['X1'], 1, np.where(df_unstacked['X2'], -1, np.nan)) # 恢复原多级列结构 df = df_unstacked.stack(level=0).swaplevel(0, 1, axis=1).sort_index(axis=1)
内容的提问来源于stack exchange,提问作者Vekkt
相关产品推荐
相关产品推荐

