在两列上合并DataFrame

时间:2016-07-23 19:12:30

标签: python pandas merge

这是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)

我错过了什么?

为什么我在第一个例子中得到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 )

修改

感谢@piRSquared's answer我意识到潜在的问题是没有一个列的组合来做到这一点。因此,之前提出的合并问题不能单一解决。也就是说,问题转化为更简单的问题:

如何在表格之间建立单一的关系?

我用一本字典来解决这个问题,该字典映射了需要对齐的所需输出:

class ExhibitionSurveyObject(models.Model):
    owner = models.ForeignKey(User, verbose_name="Owner of this Survey object", blank=False,)
    name = models.CharField(max_length=15, blank=False, verbose_name="Survey Object name", help_text="Please give a single word name for your farm",)
    farmer_email = models.EmailField(max_length=254, blank=False, verbose_name="Email of the farmer", )
    farmer_name = models.CharField(max_length=25, blank=False, verbose_name="Name of the farmer", )
    address = models.TextField(help_text="Please provide the address without the postal code", blank=True,)
    postal_code = models.CharField(max_length=5, blank=True, default='12043')
    size = models.DecimalField(max_digits=9, decimal_places=6, blank=False, )
    path = models.CharField(max_length=1000, blank=False)
    def setpath(self, x):
        self.path = json.dumps(x)

    def getpath(self, x):
        return json.loads(self.path)

    OBJECT_TYPES = (
        ('FARM', 'Farm'),
        ('SOLARPANEL', 'Solarpanel'),
        ('PLAIN', 'plain')
        )
    object_type = models.CharField(max_length=100, choices=OBJECT_TYPES)
    CYCLES = (
        ('ONCE', 'once'),
        ('WEEKLY', 'weekly'),
        ('MONTHLY', 'monthly')
        )
    cycle = models.CharField(max_length=100, choices=CYCLES)

    #To add user's full name in the admin interface for better readability
    def get_owner_full_name(self):
        return self.owner.get_full_name()

    #Works like a verbose_name but for a method
    get_owner_full_name.short_description = 'Owners full name'

2 个答案:

答案 0 :(得分:2)

您之所以这样做是因为您要合并的列不构成唯一组合。例如,a的第一行(索引0)行有foo1bar1,但第四行(索引3)也是如此。好的,没关系,但b有同样的问题。因此,当您匹配b' s foo1&对于使用bar1索引的行,0匹配两次。匹配foo1&在bar1索引的行中3,它匹配两次。所以你最终得到了这两行的四场比赛。

所以你得到了

  • 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()

enter image description here

答案 1 :(得分:1)

您可以使用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,如果bar& foo中的a,b相等。