Pandas groupby:如何获得字符串联合

Ann*_*nne 111 python pandas

我有这样的数据帧:

   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       !
Run Code Online (Sandbox Code Playgroud)

调用

In [10]: print df.groupby("A")["B"].sum()
Run Code Online (Sandbox Code Playgroud)

将返回

A
1    1.615586
2    0.421821
3    0.463468
4    0.643961
Run Code Online (Sandbox Code Playgroud)

现在我想为"C"列做"相同".因为该列包含字符串,sum()不起作用(尽管您可能认为它会连接字符串).我真正想看到的是每个组的一个列表或一组字符串,即

A
1    {This, string}
2    {is, !}
3    {a}
4    {random}
Run Code Online (Sandbox Code Playgroud)

我一直在努力想办法做到这一点.

Series.unique()(http://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.unique.html)不起作用,尽管

df.groupby("A")["B"]
Run Code Online (Sandbox Code Playgroud)

是一个

pandas.core.groupby.SeriesGroupBy object
Run Code Online (Sandbox Code Playgroud)

所以我希望任何系列方法都能奏效.有任何想法吗?

Jef*_*eff 166

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
Run Code Online (Sandbox Code Playgroud)

应用自己的函数时,不会自动排除非数字列.然而,这比应用程序.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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

你几乎可以做你想做的事

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
Run Code Online (Sandbox Code Playgroud)

一次完成一个整个框架组.关键是返回一个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}
Run Code Online (Sandbox Code Playgroud)

  • 看来这些操作现在已经矢量化,不再需要“apply”和“lambda”。我来到这里想知道为什么“pandas”实际上连接并且在求和字符串时不返回错误。 (2认同)

Bre*_*arn 62

您可以使用该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
Run Code Online (Sandbox Code Playgroud)

如果你想要别的东西,只需编写一个能够做你想要的功能然后apply再做.

  • @VineeshTP:A 列用作分组列,因此它位于索引中,如示例中所示。您可以使用“.reset_index()”将其作为列返回。 (2认同)

voi*_*hos 23

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

df.groupby('A')['B'].agg(lambda col: ''.join(col))
Run Code Online (Sandbox Code Playgroud)

  • 如果您尝试将字符串与某种类型的分隔符连接在一起,我发现这个 .agg 建议比 .apply 快得多。对于 600k+ 文本字符串的数据集,我获得相同结果的速度提高了 5-10 倍。 (4认同)

use*_*146 8

您可以尝试以下方法:

df.groupby('A').agg({'B':'sum','C':'-'.join})
Run Code Online (Sandbox Code Playgroud)

  • 点评来源:您能否在答案中添加更多解释? (2认同)
  • Groupby 应用于列“A”,并且使用 agg 函数,我可以在不同列上使用不同的函数,例如对“C”列中的元素求和,连接“C”列中的元素,同时在单词之间插入“-” (2认同)

Use*_*YmY 7

一个简单的解决方案是:

>>> df.groupby(['A','B']).c.unique().reset_index()
Run Code Online (Sandbox Code Playgroud)


Ami*_*mit 6

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

    df = df.groupby('A',as_index=False).agg(lambda x:'\n'.join(x))
Run Code Online (Sandbox Code Playgroud)


Erf*_*fan 5

用命名聚合 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]
Run Code Online (Sandbox Code Playgroud)

聚集并加入字符串

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
Run Code Online (Sandbox Code Playgroud)