【问题标题】:Python: How to merge two dataframe using multiple columns as keysPython:如何使用多列作为键合并两个数据框
【发布时间】:2019-10-31 00:18:25
【问题描述】:

我正在使用 where "t1.A = t2.A OR t1.B = t2.A" OR t1.C = t2.A 搜索相当于 SQL 合并的内容。我有两个数据框说 D1,其中 A、B、C、D、E 作为列和 D2,其中 D2 的很少记录可以由 D1 的 A 列提取,很少来自其别名 B、C、D 和 E 列。

我尝试如下,但它给了我错误的输出。

sample = D1.merge(D2,left_on=[ 'A' or'B' or'C'or 'D' or E], 
right_on=['A'], how='left')

然后我尝试了

sample = pd.concat([D1.merge(D2,left_on='A', right_on= 'A', how='left'), 
D1.merge(D2,left_on='B', right_on='A', how='left'), D1.merge(D2, 
left_on='C',right_on='A', how='left'),D1.merge(D2,left_on='D', 
right_on='A', how='left'),D1.merge(D2,left_on='E', right_on='A', 
how='left')])

这给了我很多重复我试图删除重复但不幸的是,它没有成功。

dupes = (sample['A'] == sample['B']) == (sample['C'] == sample['D']) == 
sample['E']   
sample=sample.loc[~dupes]



ValueError: The truth value of a Series is ambiguous. Use a.empty, 
 a.bool(), a.item(), a.any() or a.all().

我需要输出或“样本”记录与数据框 D1 的记录相同。

【问题讨论】:

  • 在这种情况下,查看数据的外观至关重要。您能否添加示例数据,以便我们可以直观地看到您正在尝试做什么。欲了解更多信息,请查看here
  • 您可以将这些列设置为索引并进行常规合并吗?

标签: python-3.x pandas merge


【解决方案1】:

让我们从import itertools开始(我们将使用它)。

我按如下方式创建了测试数据帧:

D1 = pd.DataFrame(data=[
    [ 1, 0, 0, 0, 0, 91 ],
    [ 0, 2, 0, 0, 0, 92 ],
    [ 0, 0, 3, 0, 0, 93 ],
    [ 0, 0, 0, 4, 0, 94 ],
    [ 0, 0, 0, 0, 5, 95 ],
    [ 0, 6, 0, 0, 0, 96 ],
    [ 0, 0, 7, 0, 0, 97 ]], columns=list('ABCDEF'))

D2 = pd.DataFrame(data=[
    [ 1, 71, 89 ],
    [ 2, 72, 88 ],
    [ 3, 73, 87 ],
    [ 4, 74, 86 ],
    [ 5, 75, 85 ],
    [ 8, 76, 84 ]], columns=list('AXY'))

如你所见:

  • D1 包含“加入候选”列 AE 和一个额外的 列 (F),
  • D2 包含 一个 连接列 A 和另外两个 列(XY)。

然后我们来定义join函数:

def myJoin(df1, df2):
    rows = itertools.product(df1.iterrows(), df2.iterrows())
    df = pd.DataFrame(left.append(right.iloc[1:])
        for (_, left), (_, right) in rows
            if right.A in left.loc['A':'E'].tolist())
    return df.reset_index(drop=True)

而唯一要做的就是调用它:

myJoin(D1, D2)

结果是:

   A  B  C  D  E   F   X   Y
0  1  0  0  0  0  91  71  89
1  0  2  0  0  0  92  72  88
2  0  0  3  0  0  93  73  87
3  0  0  0  4  0  94  74  86
4  0  0  0  0  5  95  75  85

请注意,取自两个 DataFrame 的列名应该是 unique,所以我从 D2 (right.iloc[1:]) 中删除了 A 列。

编辑

上面介绍的函数实际上是inner join。 如果你想left加入,那么定义另一个加入函数为:

def myJoin2(df1, df2):
    res = []
    for (_, left) in df1.iterrows():
        found = False
        for (_, right) in df2.iterrows():
            if right.A in left.loc['A':'E'].tolist():
                res.append(left.append(right.iloc[1:]))
                found = True
        if not found:
            res.append(left)
    df = pd.DataFrame(res)
    return df.reset_index(drop=True)

然后调用它:

myJoin2(D1, D2)

得到结果:

     A    B    C    D    E     F     X     Y
0  1.0  0.0  0.0  0.0  0.0  91.0  71.0  89.0
1  0.0  2.0  0.0  0.0  0.0  92.0  72.0  88.0
2  0.0  0.0  3.0  0.0  0.0  93.0  73.0  87.0
3  0.0  0.0  0.0  4.0  0.0  94.0  74.0  86.0
4  0.0  0.0  0.0  0.0  5.0  95.0  75.0  85.0
5  0.0  0.0  0.0  0.0  5.0  95.0  76.0  84.0
6  0.0  6.0  0.0  0.0  0.0  96.0   NaN   NaN
7  0.0  0.0  7.0  0.0  0.0  97.0   NaN   NaN

缺点是int值被转换成float, 但由于 NaN 也是 float 的特例,它不能 避免。

【讨论】:

    猜你喜欢
    • 2015-05-26
    • 2021-05-27
    • 2021-09-10
    • 1970-01-01
    • 2019-05-04
    • 2020-09-19
    • 1970-01-01
    • 2021-05-17
    • 1970-01-01
    相关资源
    最近更新 更多