当索引不匹配时更新pandas数据框的最有效方法

3
我有两个pandas数据帧,我想用其中一个更新另一个...但我不能确定索引是否匹配。(所以使用DataFrame.update会出问题!)
示例:
import pandas as pd
df1 = pd.DataFrame([('path1', 0, 0, 0),
                    ('path2', 0, 0, 0),
                    ('path3', 0, 0, 0),
                    ('path4', 0, 0, 0),],
                  columns=['path', 'class', 'manual', 'conf'],
                  index = [1,2,3,4])

df2 = pd.DataFrame([('path1', 1, 0, 0),
                    ('path2', 0, 1, 0),
                    ('path3', 0, 0, 1),
                    ('path5', 1, 1, 0),
                    ('path6', 1, 1, 0),],
                  columns=['path', 'class', 'manual', 'conf'],
                  index = [10,11,12,13,14])

期望的结果:

update_annotations(df1, df2)

    path  class  manual  conf
1  path1      1       0     0
2  path2      0       1     0
3  path3      0       0     1
4  path4      0       0     0

df1.update(df2) 可能存在风险,因为这些数据框的索引可能不匹配。那么最安全和最有效的方法是什么呢?


2
将路径列设置为索引,然后更新。 - Chris
2个回答

4

快速而不精确的

df1[['path']].merge(df2, 'left')

    path  class  manual  conf
0  path1    1.0     0.0   0.0
1  path2    0.0     1.0   0.0
2  path3    0.0     0.0   1.0
3  path4    NaN     NaN   NaN

更优雅、更简洁的编码方式

df1[['path']].merge(df2, 'left').fillna(0).astype(df1.dtypes)

    path  class  manual  conf
0  path1      1       0     0
1  path2      0       1     0
2  path3      0       0     1
3  path4      0       0     0

过于严谨

使用 df1 填充 NaN

df1[['path']].merge(df2, 'left').fillna({**df1}).astype(df1.dtypes)

    path  class  manual  conf
0  path1      1       0     0
1  path2      0       1     0
2  path3      0       0     1
3  path4      0       0     0

根据Chris所说:

df1.set_index('path').assign(**df2.set_index('path')).reset_index()

    path  class  manual  conf
0  path1    1.0     0.0   0.0
1  path2    0.0     1.0   0.0
2  path3    0.0     0.0   1.0
3  path4    NaN     NaN   NaN

保留索引

由于顺序保证相同,我们可以使用set_index来实现。

df1[['path']].merge(df2, 'left').fillna({**df1}).astype(df1.dtypes).set_index(df1.index)

    path  class  manual  conf
1  path1      1       0     0
2  path2      0       1     0
3  path3      0       0     1
4  path4      0       0     0

谢谢!嗯,我需要保证顺序和原始索引,所以我想第四个解决方案是最好的。我不知道你可以做.fillna({**df1}) - 这真的很酷。我之前尝试了前两个,但它们没有通过我的一些测试(我不想用0来填充)。 - Dror Hilman
对我而言实际起作用的是:在fillna之前放置set_index!... " df1[['path']].merge(df2, 'left').set_index(df1.index).fillna({**df1}) " - Dror Hilman

1

根据piRSquared的精彩回答,我找到了我需要的答案:

df1 = (df1[['path']]
       .merge(df2, 'left')
       .set_index(df1.index)
       .fillna(df1))

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