熊猫groupby:如何获得字符串的并集


122

我有一个这样的数据框:

   A         B       C
0  1  0.749065    This
1  2  0.301084      is
2  3  0.463468       a
3  4  0.643961  random
4  1  0.866521  string
5  2  0.120737       !

呼唤

In [10]: print df.groupby("A")["B"].sum()

将返回

A
1    1.615586
2    0.421821
3    0.463468
4    0.643961

现在,我想对列“ C”执行“相同”操作。因为该列包含字符串,所以sum()不起作用(尽管您可能认为它将字符串连接在一起)。我真正想看到的是每个组的字符串列表或一组字符串,即

A
1    {This, string}
2    {is, !}
3    {a}
4    {random}

我一直在尝试找到方法来做到这一点。

尽管Series.unique()(http://pandas.pydata.org/pandas-docs/stable/genic/pandas.Series.unique.html)无效,但是

df.groupby("A")["B"]

是一个

pandas.core.groupby.SeriesGroupBy object

所以我希望任何Series方法都可以。有任何想法吗?

Answers:


178
In [4]: df = read_csv(StringIO(data),sep='\s+')

In [5]: df
Out[5]: 
   A         B       C
0  1  0.749065    This
1  2  0.301084      is
2  3  0.463468       a
3  4  0.643961  random
4  1  0.866521  string
5  2  0.120737       !

In [6]: df.dtypes
Out[6]: 
A      int64
B    float64
C     object
dtype: object

当您应用自己的功能时,不会自动排除非数字列。这会慢一些,但比应用.sum()groupby

In [8]: df.groupby('A').apply(lambda x: x.sum())
Out[8]: 
   A         B           C
A                         
1  2  1.615586  Thisstring
2  4  0.421821         is!
3  3  0.463468           a
4  4  0.643961      random

sum 默认情况下串联

In [9]: df.groupby('A')['C'].apply(lambda x: x.sum())
Out[9]: 
A
1    Thisstring
2           is!
3             a
4        random
dtype: object

你几乎可以做你想做的

In [11]: df.groupby('A')['C'].apply(lambda x: "{%s}" % ', '.join(x))
Out[11]: 
A
1    {This, string}
2           {is, !}
3               {a}
4          {random}
dtype: object

在整个框架上进行一次,一次一组。关键是要返回一个Series

def f(x):
     return Series(dict(A = x['A'].sum(), 
                        B = x['B'].sum(), 
                        C = "{%s}" % ', '.join(x['C'])))

In [14]: df.groupby('A').apply(f)
Out[14]: 
   A         B               C
A                             
1  2  1.615586  {This, string}
2  4  0.421821         {is, !}
3  3  0.463468             {a}
4  4  0.643961        {random}

看来这些操作现在已向量化,消除了对applylambda的需要。我来到这里想知道为什么pandas实际上会合并而不在汇总字符串时返回错误。
NelsonGon

1
如果尝试连接字符串并在两者之间添加字符,则下面@voithos推荐的.agg解决方案比此处推荐的.apply快得多。在测试中,我的速度提高了5-10倍。
Doubledown

70

您可以使用该apply方法将任意函数应用于分组数据。因此,如果您想要一套,请套用set。如果需要列表,请应用list

>>> d
   A       B
0  1    This
1  2      is
2  3       a
3  4  random
4  1  string
5  2       !
>>> d.groupby('A')['B'].apply(list)
A
1    [This, string]
2           [is, !]
3               [a]
4          [random]
dtype: object

如果您还需要其他功能,只需编写一个函数即可执行所需的操作apply


工作正常,但缺少列A。
Vineesh TP

@VineeshTP:列A被用作分组列,因此它在索引中,如您在示例中所看到的。您可以使用来将其作为一列返回.reset_index()
布伦·巴恩(BrenBarn)

30

您可能可以使用aggregate(或agg)函数来连接值。(未经测试的代码)

df.groupby('A')['B'].agg(lambda col: ''.join(col))

真的行。惊人。正如@voithos提到的“未测试”一样,我并不十分乐观。我以agg字典中的条目测试了他的版本,它按预期工作:.agg({'tp':'sum','BaseWgt':'max','TP_short':lambda col:','.join (col)})
成就了

2
如果您尝试使用某种分隔符将字符串连接在一起,那么我发现此.agg建议比.apply快得多。对于包含600k +文本字符串的数据集,我得到的结果快5-10倍。
Doubledown

14

您可以尝试以下方法:

df.groupby('A').agg({'B':'sum','C':'-'.join})

2
点评来源:您能否在答案中添加更多解释?
toti08年

1
GROUPBY施加在列“A”和与AGG功能我可以使用在不同的列中不同的功能说总结在列“C”中的元素,并置的元素在列“C”而插入-单词之间“”
user3241146

8

一个简单的解决方案是:

>>> df.groupby(['A','B']).c.unique().reset_index()

这应该是正确的答案。让您清楚地回答。非常感谢!
imsrgadich

如果有人有兴趣将列表的内容添加到字符串中 df.groupby(['A','B']).c.unique().apply(lambda x: ';'.join(x)).reset_index()
Vivek-Ananth 18'Aug

8

以命名聚合 pandas >= 0.25.0

从pandas 0.25.0版开始,我们已命名聚合,可以在其中进行分组,聚合并同时为我们的列分配新名称。这样,我们就不会获得MultiIndex列,并且鉴于它们包含的数据,这些列的名称更有意义:


汇总并获取字符串列表

grp = df.groupby('A').agg(B_sum=('B','sum'),
                          C=('C', list)).reset_index()

print(grp)
   A     B_sum               C
0  1  1.615586  [This, string]
1  2  0.421821         [is, !]
2  3  0.463468             [a]
3  4  0.643961        [random]

汇总并加入字符串

grp = df.groupby('A').agg(B_sum=('B','sum'),
                          C=('C', ', '.join)).reset_index()

print(grp)
   A     B_sum             C
0  1  1.615586  This, string
1  2  0.421821         is, !
2  3  0.463468             a
3  4  0.643961        random

6

如果您想覆盖数据框中的B列,则应该可以使用:

    df = df.groupby('A',as_index=False).agg(lambda x:'\n'.join(x))

2

遵循@Erfan的好答案,大多数时候,在分析聚合值时,您希望这些现有字符值的唯一可能组合:

unique_chars = lambda x: ', '.join(x.unique())
(df
 .groupby(['A'])
 .agg({'C': unique_chars}))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.