Pandas使用逻辑列或公共列合并两个数据帧

时间:2018-05-22 23:58:13

标签: python pandas

我有两个pandas数据框AB,用日期编制索引:

>>> A
                a      b      c
Timestamp
2018-02-19   True  False  False
2018-02-20  False   True  False
2018-02-21  False  False   True

>>> B
                a      b      d
Timestamp
2018-02-19  False   True   True
2018-02-20  False  False  False
2018-02-21   True   True   True

我想合并这两个数据帧,使得合并的数据帧在每个公共条目(索引,列)之间是逻辑or,并且还包括每个数据帧唯一的列。在这种情况下,输出将是:

>>> C
                a      b      c      d
Timestamp
2018-02-19   True   True  False   True
2018-02-20  False   True  False  False
2018-02-21   True   True   True   True

有没有办法在熊猫中做到这一点?

1 个答案:

答案 0 :(得分:2)

这可能是一个更优雅和更通用的解决方案,但这适用于您已经给出的简单示例。

A = pd.DataFrame({"a":[True, False, False],
                  'b':[False, True, False],
                  'c': [False, False, True]},
                  index=['a','b','c'])

B = pd.DataFrame({"a":[False, False, True],
                  'b':[True, False, True], 
                  'd': [True, False, True]}, 
                  index=['a','b','c'])

C = pd.concat([(A | B)[['a', 'b']], A['c'], B['d']], axis=1)

print C

       a     b      c      d
a   True  True  False   True
b  False  True  False  False
c   True  True   True   True

这对两个帧进行OR运算,这将为共同的列(a,b)生成正确的结果,但是对于列c,d,则为Nan。因此,我们只是将a和b列切掉,然后用c和d连接,因为它们通过OR运算保持不变。

编辑:根据您的评论,这里是更通用的解决方案,这将使您不必知道和/或硬编码特定的列名称。

# Get all column names
all_columns = A.columns | B.columns

# Get column names in common
union = A.columns & B.columns

# Get disjoint column names
not_B = list(set(all_columns) - set(B.columns))
not_A = list(set(all_columns) - set(A.columns))

# Logical-or common columns, and concatenate disjoint columns
C = pd.concat([A[union] | B[union], A[not_B], B[not_A]], axis=1)

# If columns names get disordered because of set operations, use
# `all_columns` to reorder

print(C[all_columns])

       a     b      c      d
a   True  True  False   True
b  False  True  False  False
c   True  True   True   True

编辑2 :根据kmundnic的最终解决方案,这是一个更新的版本,适用于更多的两个数据框。

# For Python 3
from functools import reduce

# A third data frame
C = pd.DataFrame({'a':[False, False, False],
                  'b':[True, True, False], 
                  'e': [True, True, True]}, 
                  index=['a','b','c'])

def logical_merge(A, B):

    # Get all column names
    all_columns = A.columns | B.columns

    # Get column names in common
    common = A.columns & B.columns

    # Get disjoint column names
    _A = [x for x in B.columns if not x in common]
    _B = [x for x in A.columns if not x in common]

    # Logical-or common columns, and concatenate disjoint columns
    return pd.concat([(A | B)[common], A[_B], B[_A]], axis=1)[all_columns]

frames = [A, B, C]

print(reduce(logical_merge, frames))

       a     b      c      d     e
a   True  True  False   True  True
b  False  True  False  False  True
c   True  True   True   True  True