熊猫-如果特定列的值为1,则将行中的其他列替换为0

时间:2018-11-04 16:02:43

标签: python pandas

这是一个示例数据框:

X Y Z 
1 0 1
0 1 0
1 1 1

现在,这是我想出的规则:

  • X保持不变
  • 如果Y等于1,则将X中的相应值设置为0
  • 如果Z等于1,则将X和Y中的对应值设置为0

最终数据框应如下所示:

X Y Z 
0 0 1
0 1 0
0 0 1

我对解决方案的第一个想法是:

df_null_list = ['X']

for i in ['Y', 'Z']:

    df[df[i] == 1][df_null_list] = 0

    df_null_list.append(i)

当我这样做并在y轴上求和时,我开始获得2和4的值,这是没有意义的。注意,我指的是我在实际数据集上运行的时间。

您对改进或替代解决方案有什么建议吗?

3 个答案:

答案 0 :(得分:4)

使用mask

df['X'] = df['X'].mask(df.Y == 1, 0)
df[['X', 'Y']] = df[['X', 'Y']].mask(df.Z == 1, 0)

使用DataFrame.loc的另一种解决方案:

df.loc[df.Y == 1, 'X'] = 0
df.loc[df.Z == 1, ['X', 'Y']] = 0

print (df)
   X  Y  Z
0  0  0  1
1  0  1  0
2  0  0  1

答案 1 :(得分:1)

您可以将其概括为希望每行的最后一个索引1保持1,并将其他所有内容保留为0。为了提高性能,请对基础numpy数组进行操作:

a = df.values
idx = (a.shape[1] - a[:, ::-1].argmax(1)) - 1
t = np.zeros(a.shape)
t[np.arange(a.shape[0]), idx] = 1

array([[0., 0., 1.],
       [0., 1., 0.],
       [0., 0., 1.]])

如果您需要将结果作为DataFrame退回:

pd.DataFrame(t, columns=df.columns, index=df.index).astype(int)

   X  Y  Z
0  0  0  1
1  0  1  0
2  0  0  1

答案 2 :(得分:0)

另一种解决方案是使用numpy在行轴上执行扩展操作:

df1 = df.copy() == 1
df1.iloc[:,::-1].expanding(axis=1).apply(
                 lambda x: x[-1] * np.prod(np.logical_not(x[:-1]))
                 ).iloc[:,::-1]

     X    Y    Z
0  0.0  0.0  1.0
1  0.0  1.0  0.0
2  0.0  0.0  1.0