当一个是部分时,覆盖两个熊猫数据帧



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

下面是两个模拟数据帧,为简洁起见,它们具有简化的列名称。第一个是"背景"数据帧,我希望在其上叠加另一个内容,

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方法执行此操作,但这感觉很hack,我不想对我的单元测试进行单元测试。大流行的大脑让我思考得不那么好。

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'))

还有你不谈论的额外事情。您是否有关于 cols Attr1 和 Attr background_df 2 的信息,您希望保留这些信息,而不是data_df中可能的内容? 如果是这样,那么这需要进一步检查_x和_y属性列。

我喜欢使用迭代行,但你特别说不。

最新更新