Pandas一次性更新多列数据

33

我正在尝试同时更新两个字段 - 我有两个数据源,想要使它们相互协调。我知道我可以进行一些丑陋的合并,然后删除列,但是我希望以下代码能够奏效:

df = pd.DataFrame([['A','B','C',np.nan,np.nan,np.nan],
                  ['D','E','F',np.nan,np.nan,np.nan],[np.nan,np.nan,np.nan,'a','b','d'],
                  [np.nan,np.nan,np.nan,'d','e','f']], columns = ['Col1','Col2','Col3','col1_v2','col2_v2','col3_v2'])

print df

 Col1 Col2 Col3 col1_v2 col2_v2 col3_v2
0    A    B    C     NaN     NaN     NaN
1    D    E    F     NaN     NaN     NaN
2  NaN  NaN  NaN       a       b       d
3  NaN  NaN  NaN       d       e       f

#update 
df.loc[df['Col1'].isnull(),['Col1','Col2', 'Col3']] = df[['col1_v2','col2_v2','col3_v2']]

print df

 Col1 Col2 Col3 col1_v2 col2_v2 col3_v2
0    A    B    C     NaN     NaN     NaN
1    D    E    F     NaN     NaN     NaN
2  NaN  NaN  NaN       a       b       d
3  NaN  NaN  NaN       d       e       f

我的期望输出将是:

 Col1 Col2 Col3 col1_v2 col2_v2 col3_v2
0    A    B    C     NaN     NaN     NaN
1    D    E    F     NaN     NaN     NaN
2    a    b    c       a       b       d
3    d    e    f       d       e       f

我猜测这与更新/设置切片有关,但我通常使用.loc来更新值,只是不会在多个列上同时使用。

我感觉有一种简单的方法可以做到这一点,但我可能错过了什么,欢迎任何想法/建议!

编辑以反映以下解决方案感谢评论中的索引提示。 但是,就它与系列相关而言,我有一个问题。 如果我想以类似的方式更新单个系列,我可以像这样做:

df.loc[df['Col1'].isnull(),['Col1']] = df['col1_v2']

print df

  Col1 Col2 Col3 col1_v2 col2_v2 col3_v2
0    A    B    C     NaN     NaN     NaN
1    D    E    F     NaN     NaN     NaN
2    a  NaN  NaN       a       b       d
3    d  NaN  NaN       d       e       f

注意,我这里没有考虑索引,我筛选了一个2x1的系列并将其设置为一个4x1的系列,但它处理得很正确。有什么想法吗?我试图更好地理解我已经使用了一段时间的某些功能,但我想我对其基本机制/规则还没有完全掌握。


2
该赋值语句的右侧是一个不包含列信息的pd.Series。该列信息已经进入'pd.Series对象的'name'属性中。当进行赋值操作时,它会忽略列的对齐,并仅将您指定的系列放置在您指定的列中。尝试df.loc[df['Col1'].isnull(),['Col1', 'Col2']] = df['col1_v2']`,并查看它现在仅将该系列放入指定的两列中。为了从正确的列正确的列进行赋值,您需要正确调用这些列。否则,请使用循环方法。 - piRSquared
我还要补充一点,如果你使用df.loc[df['Col1'].isnull(),['Col1']] = df[['col1_v2']],在'col1_v2'周围加上双括号,这将尝试将一个数据框推入该列,这会使你陷入与之前相同的情况。这进一步说明了使用系列和数据框进行赋值之间的区别。 - piRSquared
2个回答

39

你想要替换

print df.loc[df['Col1'].isnull(),['Col1','Col2', 'Col3']]

  Col1 Col2 Col3
2  NaN  NaN  NaN
3  NaN  NaN  NaN

随着:

replace_with_this = df.loc[df['Col1'].isnull(),['col1_v2','col2_v2', 'col3_v2']]
print replace_with_this

  col1_v2 col2_v2 col3_v2
2       a       b       d
3       d       e       f

听起来很合理。不过,在进行分配时,您需要考虑索引对齐,包括列。

因此,以下应该有效:

df.loc[df['Col1'].isnull(),['Col1','Col2', 'Col3']] = replace_with_this.values

print df

  Col1 Col2 Col3 col1_v2 col2_v2 col3_v2
0    A    B    C     NaN     NaN     NaN
1    D    E    F     NaN     NaN     NaN
2    a    b    d       a       b       d
3    d    e    f       d       e       f

我通过在结尾使用.values来处理列信息。这将从replace_with_this数据框中剥离列信息,并仅使用适当位置的值。


谢谢 - 根据您的解决方案添加了编辑,对此有什么想法? - flyingmeatball

2
在“攻坚精神”的指引下,我提供以下解决方案,可产生所需的结果。
我意识到这并不完全符合您的要求,因为我没有按照您提出的合理但不可行的方式切分df。
#Does not work when indexing on np.nan, so I fill with some arbitrary value. 
df = df.fillna('AAA')

#mask to determine which rows to update
mask = df['Col1'] == 'AAA'

#dict with key value pairs for columns to be updated
mp = {'Col1':'col1_v2','Col2':'col2_v2','Col3':'col3_v2'}

#update
for k in mp: 
     df.loc[mask,k] = df[mp.get(k)]

#swap back np.nans for the arbitrary values
df = df.replace('AAA',np.nan)

输出:

Col1    Col2    Col3    col1_v2     col2_v2     col3_v2
A       B       C       NaN         NaN         NaN
D       E       F       NaN         NaN         NaN
a       b       d       a           b           d
d       e       f       d           e           f

如果我不替换NaN,我会得到下面的错误。我将研究这个错误的确切来源。

ValueError: array is not broadcastable to correct shape

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接