首页 > 解决方案 > 当一个是部分的时覆盖两个 Pandas DataFrame

问题描述

我正在尝试覆盖两个数据帧,如果中的值匹配,则用另一个数据帧覆盖一个。我不关心数据帧的索引,相关的是列中的内容匹配发生覆盖。当发生这种匹配时,从一个数据帧中删除行并连接剩余的行也是可以接受的。

为了简洁起见,下面是两个带有简化列名的模拟数据框。第一个是“背景”数据框,我希望在其上覆盖另一个内容,

   Name1 Name2  Id1  Id2 Attr1 Attr2
3      A     B    0    0  None  None
1      A     B    0    1  None  None
7      A     B    0    2  None  None
15     A     B    0    3  None  None
13     A     B    1    0  None  None
14     A     B    1    1  None  None
0      A     B    1    2  None  None
4      A     B    1    3  None  None
10     A     B    2    0  None  None
9      A     B    2    1  None  None
12     A     B    2    2  None  None
11     A     B    2    3  None  None
6      A     B    3    0  None  None
8      A     B    3    1  None  None
2      A     B    3    2  None  None
5      A     B    3    3  None  None

第二个包含一些数据

  Name1 Name2  Id1  Id2     Attr1  Attr2
0     A     B    0    0   LEVEL_A   1.00
1     A     B    0    1   LEVEL_A   0.97
2     A     B    1    1   LEVEL_A   1.00
3     A     B    2    2   LEVEL_A   1.00
4     A     B    3    3   LEVEL_A   1.00

我包括索引以表明它们不匹配。预期结果将包含以下数据:

   Name1 Name2  Id1  Id2 Attr1 Attr2
3      A     B    0    0  Level_A  1.00 # Name1,Name2,Id1,Id2 matches
1      A     B    0    1  Level_A  0.97
7      A     B    0    2  None  None
15     A     B    0    3  None  None
13     A     B    1    0  None  None
14     A     B    1    1  Level_A  1.00
0      A     B    1    2  None  None
4      A     B    1    3  None  None
10     A     B    2    0  None  None
9      A     B    2    1  None  None
12     A     B    2    2  Level_A  1.00
11     A     B    2    3  None  None
6      A     B    3    0  None  None
8      A     B    3    1  None  None
2      A     B    3    2  None  None
5      A     B    3    3  Level_A  1.00

注意:如果最终结果中的行顺序不同,那也没关系。如果在第一个数据帧中找到所有行,那么对于任何给定的行,其列的值Name1,Name2,Id1,Id2也存在于第二个数据帧中,这是可以预期的。

奖励:我很想知道如果一个人不使用哨兵值是否可以这样做None,如果可能的话,怎么做?

我一直弄错了,因为combine_firstisin等。都看指数。我很危险地接近使用一些 - 方法来做到这iterrow一点,但这感觉很hacky,我不想对我的单元测试进行单元测试。流行病的大脑让我觉得不太好。

标签: pythonpandasdataframe

解决方案


check_cols = 'Name1 Name2 Id1 Id2'.split()
val_cols = 'Attr1 Attr2'.split()

创建唯一 ID

background_df['full_id'] = background_df[check_cols].apply(lambda row: '_'.join([str(_).strip() for _ in row]), axis=1)
data_df['full_id'] = data_df[check_cols].apply(lambda row: '_'.join([str(_).strip() for _ in row]), axis=1)

合并唯一的 id。您可以更改后缀以帮助您稍后删除额外的列

background_df.merge(data_df, how='left', on='full_id', suffixes=('_x', '_y'))

然后你会删除你不想要的任何列,或者只用更少的列开始合并。

background_df[check_cols+['full_id',]].merge(data_df[val_cols+['full_id',]], how='left', on='full_id', suffixes=('_x', '_y'))

还有一些你不谈论的额外事情。您是否有关于 background_df 上的 cols Attr1 和 Attr2 的信息,您希望保留这些信息而不是 data_df 中的信息?如果是这样,那么这将需要进一步检查 _x 和 _y attr cols。

我喜欢使用 iterrows,但你明确拒绝了。


推荐阅读