将两个数据框与一些公共列合并,其中公共的组合需要是自定义函数

Posted

技术标签:

【中文标题】将两个数据框与一些公共列合并,其中公共的组合需要是自定义函数【英文标题】:merge two dataframes with some common columns where the combining of the common needs to be a custom function 【发布时间】:2019-03-13 06:38:12 【问题描述】:

我的问题与Merge pandas dataframe, with column operation 非常相似,但不能满足我的需求。

假设我有两个数据框,例如(请注意,数据框内容可以是浮点数而不是布尔值):

left = pd.DataFrame(0: [True, True, False], 0.5: [False, True, True], index=[12.5, 14, 15.5])
right = pd.DataFrame(0.7: [True, False, False], 0.5: [True, False, True], index=[12.5, 14, 15.5])

        0.5    0.7
12.5   True   True
14.0  False  False
15.5   True  False

        0.0    0.5
12.5   True  False
14.0   True   True
15.5  False   True

如您所见,它们具有相同的索引,并且其中一列是常见的。在现实生活中,可能会有更常见的列,例如 1.0 或其他尚未定义的数字,并且每一侧都有更多独特的列。 我需要组合两个数据框,以便保留所有唯一列,并使用特定函数组合公共列,例如此示例为布尔 OR,而两个数据帧的索引始终相同。

所以结果应该是:

结果

        0.0   0.5    0.7
12.5   True  True   True
14.0   True  True  False
15.5  False  True  False

在现实生活中需要合并的数据帧不止两个,但可以一个接一个地依次合并成一个空的第一个数据帧。

我觉得 pandas.combine 可以解决问题,但我无法从文档中弄清楚。任何人都会对如何通过一个或多个步骤进行操作提出建议。

【问题讨论】:

我会分几步来做:推导出公共列,将组合函数应用于两者,然后添加非公共列。如果有两个以上,您将在第一个数据帧中就地应用这些步骤,同时循环其他数据帧。这听起来合乎逻辑吗? 【参考方案1】:

您可以连接数据帧,然后按列名分组以对名称相似的列应用操作:在这种情况下,您可以不用求和,然后将类型转换回 bool 以获取 or 操作。

import pandas as pd

df = pd.concat([left, right], 1)
df.groupby(df.columns, 1).sum().astype(bool)

输出:

        0.0   0.5    0.7
12.5   True  True   True
14.0   True  True  False
15.5  False  True  False

如果您需要了解如何以较少特定于案例的方式执行此操作,那么只需按列分组并将某些内容应用于axis=1 上的分组对象

df = pd.concat([left, right], 1)
df.groupby(df.columns, 1).apply(lambda x: x.any(1))
#        0.0   0.5    0.7
#12.5   True  True   True
#14.0   True  True  False
#15.5  False  True  False

此外,您可以定义自定义组合函数。这是一个将左帧添加两倍到右帧的 4 倍。如果只有一列,则返回左帧的 2 倍。

样本数据

左:

      0.0  0.5
12.5    1   11
14.0    2   17
15.5    3   17

右:

      0.7  0.5
12.5    4    2
14.0    4   -1
15.5    5    5

代码

def my_func(x):
    try:
        res = x.iloc[:, 0]*2 + x.iloc[:, 1]*4
    except IndexError:
        res = x.iloc[:, 0]*2
    return res

df = pd.concat([left, right], 1)
df.groupby(df.columns, 1).apply(lambda x: my_func(x))

输出:

      0.0  0.5  0.7
12.5    2   30    8
14.0    4   30    8
15.5    6   54   10

最后,如果您想以连续方式执行此操作,那么您应该使用reduce。这里我将 5 DataFrames 与上述函数结合起来。 (我将在示例中重复正确的帧 4x)

from functools import reduce

def my_comb(df_l, df_r, func):
    """ Concatenate df_l and df_r along axis=1. Apply the
    specified function.
    """
    df = pd.concat([df_l, df_r], 1)
    return df.groupby(df.columns, 1).apply(lambda x: func(x))

reduce(lambda dfl, dfr: my_comb(dfl, dfr, func=my_func), [left, right, right, right, right])
#      0.0  0.5  0.7
#12.5   16  296  176
#14.0   32  212  176
#15.5   48  572  220

【讨论】:

不错....但是,如果组合函数不是简单的布尔 OR 并且数据帧包含数字而不是布尔值,该怎么办?该函数可以是通用的,但始终是对称的:f(right, left) @user10472446 查看更新。您可以定义自己的函数,然后与 reduce 结合使用,您可以通过提供要加入的 DataFrames 列表将该函数应用于每个连续的加入。 非常感谢,这正是我要找的!

以上是关于将两个数据框与一些公共列合并,其中公共的组合需要是自定义函数的主要内容,如果未能解决你的问题,请参考以下文章

将数据框与公共列连接起来[重复]

基于公共列将数据框与另一列中的列连接起来

将具有两个日期列的一个数据框与另一个具有两个日期列的数据框合并

合并两个没有公共字段的表

如何在 VBA 中使用 SQL 将两个工作簿与一个公共列合并

根据 Pandas 中的公共列值合并两个数据框