如何用函数解决Pandas数据框合并冲突?

7 投票
3 回答
3307 浏览
提问于 2025-04-18 15:34

假设我有两个数据框(dataframe),我想把它们合并在一起,但因为行和列有重叠,所以出现了冲突。为了避免重复行,我想用一个函数来解决这个冲突。这能做到吗?

import numpy as np
import pandas as pd
dates1 = pd.date_range("2014-01-01", periods = 4)
dates2 = pd.date_range("2014-01-03", periods = 4)
cols1 = list("ABCD")
cols2 = list("CDEF")
df1 = pd.DataFrame(np.ones([4, 4], dtype = "bool"), index = dates1, columns = cols1)
df2 = pd.DataFrame(np.zeros([4, 4], dtype = "bool"), index = dates2, columns = cols2)

In [317]: df1
Out[317]: 
               A     B     C     D
2014-01-01  True  True  True  True
2014-01-02  True  True  True  True
2014-01-03  True  True  True  True
2014-01-04  True  True  True  True

In [318]: df2
Out[318]: 
                C      D      E      F
2014-01-03  False  False  False  False
2014-01-04  False  False  False  False
2014-01-05  False  False  False  False
2014-01-06  False  False  False  False

如你所见,这两个数据框在C列和D列上有重叠,并且在2014-01-03和2014-01-04这两行上也有重叠。所以当我合并它们时,就会因为这个冲突而出现重复的行:

In [321]: pd.concat([df1, df2])
Out[321]: 
               A     B      C      D      E      F
2014-01-01  True  True   True   True    NaN    NaN
2014-01-02  True  True   True   True    NaN    NaN
2014-01-03  True  True   True   True    NaN    NaN
2014-01-04  True  True   True   True    NaN    NaN
2014-01-03   NaN   NaN  False  False  False  False
2014-01-04   NaN   NaN  False  False  False  False
2014-01-05   NaN   NaN  False  False  False  False
2014-01-06   NaN   NaN  False  False  False  False

其实我想要的是,让True的值覆盖False(或者NaN),比如我可以用一个“或”函数来解决这种重复冲突。这在Pandas中能实现吗?

最终的结果应该是这样的:

               A     B      C      D      E      F
2014-01-01  True  True   True   True    NaN    NaN
2014-01-02  True  True   True   True    NaN    NaN
2014-01-03  True  True   True   True  False  False
2014-01-04  True  True   True   True  False  False
2014-01-05   NaN   NaN  False  False  False  False
2014-01-06   NaN   NaN  False  False  False  False

也就是说,在没有重复的地方,两个数据框的值都能显示出来;如果两个框都没有数据,就返回NaN;但如果两个框都有数据,True会覆盖False(也就是“或”的效果)。

我在寻找一个通用的解决方案,用于在合并Pandas数据框时处理冲突,最好是通过传递函数来实现。

3 个回答

1

这个问题是在遇到类似需求时发现的,主要是想把两列数据合并,并且有一个简单的冲突解决方法:一列的值会覆盖另一列的值。相比于创建一个解决冲突的函数,pandas 提供了一个方便的工具 Series.combine_first(other),它会优先选择调用者的值,而不是其他列的值。

3

这段代码应该能满足你的需求:

def conflict_resolver(x):

    # If there is only one row, just return it as is
    if x.shape[0] == 1:
        return x
    # If all values are nan, just return the first row
    elif x.isna().all():
        return x[:1]
    else:
        # Remove na values and drop duplicates
        x = x.dropna().drop_duplicates()

        # If only 1 row of non-na data exists, just return it
        if x.shape[0] == 1:
            return x
        else:

            # Handle conflicts here:
            
            if isinstance(x, bool):
                x.iloc[0] = x.any()
                return x[:1]

concat_df = pd.concat([df1, df2]).reset_index(drop=False).groupby(by='index').agg(conflict_resolver)
3

与其使用concat,不如用merge:

>> pd.merge(df1, df2, on=(df1.columns & df2.columns).tolist(), how='outer', left_index=True, right_index=True)
               A     B      C      D      E      F
2014-01-01  True  True   True   True    NaN    NaN
2014-01-02  True  True   True   True    NaN    NaN
2014-01-03  True  True   True   True  False  False
2014-01-04  True  True   True   True  False  False
2014-01-05   NaN   NaN  False  False  False  False
2014-01-06   NaN   NaN  False  False  False  False

这里的 on=(df1.columns & df2.columns).tolist() 参数会给你一个重叠列的列表(在这个例子中是 ['C','D']

how='outer' 则是把两个数据框的键合并在一起(就像SQL中的全外连接)

使用 left_index=Trueright_index=True 可以保持行索引不变

撰写回答