【问题标题】:Merge DataFrames on two columns在两列上合并 DataFrame
【发布时间】:2016-07-23 19:12:29
【问题描述】:

这是this question的后续报道

我有两个pandas DataFrame,如下:

print( a )

    foo   bar   let letval
9  foo1  bar1  let1      a
8  foo2  bar2  let1      b
7  foo3  bar3  let1      c
6  foo1  bar1  let2      z
5  foo2  bar2  let2      y
4  foo3  bar3  let2      x

print( b )

    foo   bar   num  numval
0  foo1  bar1  num1       1
1  foo2  bar2  num1       2
2  foo3  bar3  num1       3
3  foo1  bar1  num2       4
4  foo2  bar2  num2       5
5  foo3  bar3  num2       6

我想merge 他们两个在[ 'foo', 'bar' ] 列上。

如果我只是做c = pd.merge( a, b, on=['foo', 'bar'] ),我会得到:

prnint( c )

     foo   bar   let letval   num  numval
0   foo1  bar1  let1      a  num1       1
1   foo1  bar1  let1      a  num2       4
2   foo1  bar1  let2      z  num1       1
3   foo1  bar1  let2      z  num2       4
4   foo2  bar2  let1      b  num1       2
5   foo2  bar2  let1      b  num2       5
6   foo2  bar2  let2      y  num1       2
7   foo2  bar2  let2      y  num2       5
8   foo3  bar3  let1      c  num1       3
9   foo3  bar3  let1      c  num2       6
10  foo3  bar3  let2      x  num1       3
11  foo3  bar3  let2      x  num2       6

我想要:

print( c )

    foo   bar   let letval   num   numval
0  foo1  bar1  let1      a   num1       1
1  foo2  bar2  let1      b   num1       2
2  foo3  bar3  let1      c   num1       3
3  foo1  bar1  let2      z   num2       4
4  foo2  bar2  let2      y   num2       5
5  foo3  bar3  let2      x   num2       6

我得到的最接近的是:

c = pd.merge( a, b, left_index=['foo', 'bar'], right_index=['foo', 'bar'] )

我错过了什么?

为什么我在第一个例子中得到c.shape = (12,6)


编辑

感谢@piRSquared's answer,我意识到根本问题是没有单一的列组合可以做到这一点。因此,如前所述的合并问题不能一概而论地解决。也就是说,这个问题被转换成一个更简单的问题:

如何在表之间建立明确的关系?

我使用映射需要对齐的所需输出的字典解决了这个问题:

map_ab = { 'num1':'let1', 'num2':'let2' }
b['let'] = b.apply( lambda x: map_ab[x['num']], axis=1 )
c = pd.merge( a, b, on=['foo', 'bar', 'let'] )
print( c )

【问题讨论】:

    标签: python pandas merge


    【解决方案1】:

    你得到这个的原因是因为你合并的列不构成唯一的组合。例如,a 的第一行(索引 0)有 foo1bar1,但第四行(索引 3)也是如此。好的,没关系,但b 有同样的问题。因此,当您将bfoo1bar10 索引的行匹配时,它匹配两次。当您在以3 索引的行中匹配foo1bar1 时也是如此,它匹配两次。所以你最终得到了这 2 行的四个匹配项。

    所以你得到了

    • a 第 0 行与 b 第 0 行匹配
    • a 第 0 行与 b 第 3 行匹配
    • a 第 3 行与 b 第 0 行匹配
    • a 第 3 行与 b 第 3 行匹配

    然后,您的示例又执行了 2 次。 3 * 4 == 12

    做到这一点并且明确的唯一方法是确定一个规则,如果有多个匹配项,则采用哪个匹配项。我决定按您的其他列之一分组,然后取第一个。它仍然不符合您的预期输出,但我建议您举了一个不好的例子。

    pd.merge( a, b, on=['foo', 'bar']).groupby(['foo', 'bar', 'let'], as_index=False).first()
    

    【讨论】:

    • 对正在发生的事情进行了很好的解释,特别是当您将 b 的 foo1 和 bar1 匹配为索引为 0 的行时,它匹配两次。
    • 这个例子和我手头的问题一样好/坏。诚然,我做了一些不同的事情(导入的 DataFrames 与文件不同),但这种情况时不时发生。
    • @Luis 同意了。但这就是问题所在。鉴于您提供的信息,没有明确的方法可以提供答案。我本可以删除重复项,但这不会给出您要求的答案。数据或请求有问题。你需要和解并再次询问。
    • 我明白你的观点,问题是模棱两可的,我被我知道let1 必须对应于值 num1 的事实所愚弄,毕竟两者都是 1 :P 我会尝试找到一个更好的例子或更改措辞以反映这一点。
    【解决方案2】:

    你可以使用combine_first:

    In[21]:a.combine_first(b)
    Out[21]: 
        bar   foo   let letval   num  numval
    0  bar1  foo1  let1      a  num1       1
    1  bar2  foo2  let1      b  num1       2
    2  bar3  foo3  let1      c  num1       3
    3  bar1  foo1  let2      z  num2       4
    4  bar2  foo2  let2      y  num2       5
    5  bar3  foo3  let2      x  num2       6
    

    在第一个示例中,您正在执行inner join,如果barfooa,b 中相等,则返回所有行。

    【讨论】:

    • combine_first 匹配 indexcolumns。它将生成一个索引为a.index.union(b.index) 的数据框,并且对于列也是如此。如果您有a = pd.DataFrame([], list('ab'), list('AB'))b = pd.DataFrame([], list('cd'), list('CD')),那么a.combine_first(b) 将是一个4x4 数据帧。关键是,您的答案是忽略了 OP 想要加入 ['bar', 'foo'] 并且实际上匹配给定整数索引的事实。
    • 是的,combine_first 仅因为索引匹配而起作用。如果您这样做a.index= [ 9,8,7,6,5,4 ] a.combine_first(b),它将不再起作用。此外,merge 上的行为发生在每个加入选项(innerouter 等)
    猜你喜欢
    • 2018-06-15
    • 2022-12-05
    • 1970-01-01
    • 2018-05-22
    • 2016-01-17
    • 2018-10-02
    • 2020-06-15
    • 2016-10-24
    • 2021-08-15
    相关资源
    最近更新 更多