如果一列的条目包含在另一列中,则 Pandas 会合并嵌套列

问题描述 投票:0回答:1

我想创建一个函数

new_merge
,它是一个 pandas 合并了
left_on
right_on
列的所有常用规则,但有一些额外的逻辑。为此,将有 2 个额外的列表参数(都指定一些列) - 让我们称它们为
left_partial_on
right_partial_on
。仅当
left_partial_on[i][j]
的每个元素都包含在
right_partial_on[i][k]
中时,2 个单独列
left_partial_on[i][j]
right_partial_on[i][k]
的 2 个条目才被视为“匹配”,反之亦然(即
right_partial_on[i][j]
的每个元素都包含在
left_partial_on[i][k] 中) 
)。

例如,假设我有这些数据框

df1 = pd.DataFrame({'Writer': [['John', 'Adam'], ['Gary', 'Peter'], ['Frida', 'Kate']], 'Cast': [['Carrie', 'Ryan'], ['Jamie'], ['Maggie', 'Shaun']], 'Title': ['The Boring Film', 'The Great Film', 'The Awesome Film']})
df2 = pd.DataFrame({'Writer': [['Adam', 'John'], ['Betty', 'Bob'], ['Frida']], 'Cast': [['Carrie', 'Rita'], ['Paula', 'Beatrice'], ['Maggie']], 'Title': ['The Boring Film', 'The Great Film', 'The Awesome Film']})

然后当我打电话时

new_merge(df1, df2, left_on = ['Title'], right_on = ['Title'], left_partial_on = ['Writer', 'Cast'], right_partial_on = ['Writer', 'Cast'])
我最终只得到最后一行:


Writer  Cast        Title
[Frida] [Maggie]    The Awesome Film

解释:数据帧之间唯一可能的匹配是第一、第二和第三行,否则

Title
之间不相等。对于第一行,每个
[Adam, John]
都包含在
[John, Adam]
所以
Writer
是一个匹配项,但是
Ryan
不包含在
[Carrie, Rita]
中,所以
Cast
不是一个匹配项。同样,在第二行中,
Jamie
不包含在
[Paula, Beatrice]
中,因此
Cast
也不是第二行中的匹配项。但是第三个
[Frida, Kate]
包含
[Frida]
中的每个元素,
[Maggie, Shaun]
包含
[Maggie]
中的每个元素,并且正如我们已经确定的
Title
是相等的,因此我们有一个匹配。

当谈到将其打包为一个函数时,我所能想到的就是尝试基于 for 循环的东西,因此非常慢,因为我正在处理非常大的数据帧(不仅仅是这个例子)。我有点困惑什么是更/最有效的方法来做到这一点。我在这里寻找实现以及 pandas 中是否存在执行此操作的现有函数,但我没有找到任何内容。

pandas join merge
1个回答
0
投票

这是一种可能的解决方案。首先,分解

left_partial_on
right_partial_on
中的所有列。然后计算每部电影的行数。现在将两个数据帧在“所有”列上合并在一起,并计算结果中每部电影的行数。如果该计数与任一数据帧中的计数匹配,则将胶片保留在结果中。最后,将“部分”字段重新聚合回列表中。 def new_merge(df1, df2, left_on, right_on, left_partial_on, right_partial_on): def explode_partials(df, cols): dfe = df.explode(cols[0]) for col in cols[1:]: dfe = dfe.explode(col) return dfe df1e = explode_partials(df1, left_partial_on) df2e = explode_partials(df2, left_partial_on) df1e['rows'] = df1e.groupby(left_on).transform('size') df2e['rows'] = df2e.groupby(right_on).transform('size') merged = df1e.merge(df2e, left_on=left_on + left_partial_on, right_on=right_on + right_partial_on, how='inner') group_cols = list(set(left_on + right_on)) mergedsizes = merged.groupby(group_cols).transform('size') merged = merged[(merged['rows_x'] == mergedsizes) | (merged['rows_y'] == mergedsizes)] merged = merged.drop(columns=['rows_x', 'rows_y']) return merged.groupby(group_cols, sort=False).agg(lambda g:g.unique()).reset_index() new_merge(df1, df2, ['Title'], ['Title'], ['Writer', 'Cast'], ['Writer', 'Cast'])

输出:

Title Writer Cast 0 The Awesome Film [Frida] [Maggie]

另一个例子:

df3 = df2.copy() df3.loc[0, 'Cast'] = df1.loc[0, 'Cast'] new_merge(df3, df1, ['Title'], ['Title'], ['Writer', 'Cast'], ['Writer', 'Cast'])

输出:

Title Writer Cast 0 The Boring Film [Adam, John] [Carrie, Ryan] 1 The Awesome Film [Frida] [Maggie]

© www.soinside.com 2019 - 2024. All rights reserved.