在pandas DataFrame中修改行子集中的多个列

时间:2017-03-02 11:02:30

标签: python pandas dataframe

我有一个pandas DataFrame。在这个DataFrame中,我想修改一些行的几列。这些是我尝试过的方法。

df[['finalA', 'finalB']] = df[['A', 'B']]
exceptions = df.loc[df.normal == False]

哪个像魅力一样,但现在我想设置例外:

df.loc[exceptions.index, ['finalA', 'finalB']] = \
  df.loc[exceptions.index, ['A_except', 'B_except']]

哪个不起作用。所以我尝试使用this answer中的.ix

df.ix[exceptions.index, ['finalA', 'finalB']] = \
  df.ix[exceptions.index, ['A_except', 'B_except']]

哪个也不起作用。对于特殊行,这两种方法都会在NaNfinalA中为finalB提供{。}}。

似乎有效的唯一方法是一次只做一列:

df.ix[exceptions.index, 'finalA'] = \
  df.ix[exceptions.index, 'A_except']
df.ix[exceptions.index, 'finalB'] = \
  df.ix[exceptions.index, 'B_except']

熊猫在这里发生了什么?如何避免将值设置为通过选择多列显然进行的复制?有没有办法避免这种代码重复?

更多的思考:它实际上并没有将值设置为数据帧的副本,而是将值设置为NaN。它实际上会将它们覆盖为新值。

<小时/> 示例数据框:

import pandas as pd
df = pd.DataFrame({'A': [1,2,3,4],
                   'B': [5,6,7,8],
                   'normal': [True, True, False, False],
                   'A_except': [0,0,9,9],
                   'B_except': [0,0,10,10]})

结果:

    A   A_except    B   B_except    normal  finalA  finalB
0   1   0           5   0           True    1.0     5.0
1   2   0           6   0           True    2.0     6.0
2   3   9           7   10          False   NaN     NaN
3   4   9           8   10          False   NaN     NaN

预期结果:

    A   A_except    B   B_except    normal  finalA  finalB
0   1   0           5   0           True    1       5
1   2   0           6   0           True    2       6
2   3   9           7   10          False   9       10
3   4   9           8   10          False   9       10

2 个答案:

答案 0 :(得分:2)

您可以重命名对齐列名:

d = {'A_except':'finalA', 'B_except':'finalB'}
df.loc[exceptions.index, ['finalA', 'finalB']] = \
  df.loc[exceptions.index, ['A_except', 'B_except']].rename(columns=d)

print (df)
   A  A_except  B  B_except normal  finalA  finalB
0  1         0  5         0   True       1       5
1  2         0  6         0   True       2       6
2  3         9  7        10  False       9      10
3  4         9  8        10  False       9      10

另一个解决方案是将输出转换为numpy array,但列不对齐:

df.loc[exceptions.index, ['finalA', 'finalB']] = \
  df.loc[exceptions.index, ['A_except', 'B_except']].values

print (df)
   A  A_except  B  B_except normal  finalA  finalB
0  1         0  5         0   True       1       5
1  2         0  6         0   True       2       6
2  3         9  7        10  False       9      10
3  4         9  8        10  False       9      10

答案 1 :(得分:1)

如果查看方程的两边,您会注意到列的不同。 Pandas会考虑列的标签,因为它们不匹配,所以不会插入值。

它适用于单个列,因为您正在提取一个系列,然后列标签不再适用。

快速解决方案是将DataFrame简单地剥离到裸阵列,然后locix方法都可以工作:

df.loc[exceptions.index, ['finalA', 'finalB']] = 
  df.loc[exceptions.index, ['A_except', 'B_except']].values

但请记住,这样做会消除Pandas尝试匹配列标签和索引标签,它基本上是一个“硬”&#39;插入。因此,这使您成为负责正确对齐的用户。在这种情况下,这不是问题,而是一般要注意的事情。