Python 熊猫群比:如何获得字符串的并集

Python 熊猫群比:如何获得字符串的并集,python,pandas,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 ! 召唤 In [10]: print df.groupby("A")["B"].sum() 会回来的 A 1 1.615586 2 0.421

我有这样一个数据帧:

   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()不起作用

df.groupby("A")["B"]
是一个

所以我希望任何级数方法都能奏效。有什么想法吗

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()
应用于
分组比

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
一次一组,在整个框架上进行此操作。关键是返回一个
系列

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}

您可以使用
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

如果您还需要其他功能,只需编写一个函数来实现您想要的功能,然后应用该功能。

您可以使用
聚合
(或
agg
)函数来连接这些值。(未测试代码)


一个简单的解决办法是:

>>> df.groupby(['A','B']).c.unique().reset_index()
你可以试试这个:

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

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

    df = df.groupby('A',as_index=False).agg(lambda x:'\n'.join(x))
pandas>=0.25.0的命名聚合
自从pandas版本0.25.0以来,我们已经命名了聚合,我们可以在其中进行分组、聚合,同时为列指定新名称。这样,我们就不会得到多索引列,而且考虑到它们包含的数据,列名更有意义:


聚合并获取字符串列表

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

聚合并连接字符串

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

按照@Erfan的正确答案,在分析聚合值时,大多数情况下,您希望这些现有字符值的唯一可能组合:

unique_chars = lambda x: ', '.join(x.unique())
(df
 .groupby(['A'])
 .agg({'C': unique_chars}))

它确实有效。太神了正如@voithos提到的“未经测试”,我并不十分乐观。我把他的版本作为agg字典中的一个条目进行了测试,它按预期工作:.agg({'tp':'sum','BaseWgt':'max','tp_short':lambda col:','.join(col)})是我的一天。如果您试图用某种类型的分隔符将字符串合并在一起,我发现这个.agg建议比.apply快得多。对于一个600k+文本字符串的数据集,我得到的相同结果快了5-10倍。这应该是正确的答案。让你清楚地回答。谢谢!如果某人有兴趣将列表内容加入字符串
df.groupby(['a','B']).c.unique().apply(lambda x:';').join(x)).reset_index()
From review:您能为您的答案添加更多解释吗?Groupby应用于“A”列,使用agg函数,我可以在不同的列上使用不同的函数,比如对“C”列中的元素求和,将列“C”中的元素串联起来,同时在字之间插入“-”,这些操作现在似乎已矢量化,不再需要
apply
lambda
s。我来这里想知道为什么
pandas
实际上是concats而不是返回一个求和字符串的错误。如果您试图在字符串之间加上一个字符,下面@voithos推荐的.agg解决方案要比这里推荐的.apply快得多。在我的测试中,我的速度提高了5-10倍。工作正常,但缺少列A。@VineeshTP:列A被用作分组列,因此它在索引中,如示例中所示。您可以使用
.reset\u index()
将其作为列返回。为了确认我的理解,lambda中使用的
.unique()
正在确定包含所有唯一值的序列是否在指定的group by values中?如果是,pandas是否将每个唯一值(按值分组)临时存储在
unique\u chars
变量之外的某个位置,以确定在最终将值分配给变量之前哪些值实际上是唯一的?也许值得一个新的SO问题。@deesolie
unique_chars
是向量x的函数。Lambda是在python中创建单行函数的简称。然后将该函数与每个列向量一起用作输入。我理解lambda函数。假设我们有
df.groupby(['A'])['B'].transform(lambda x:','.join(x.unique())
,我很好奇pandas是如何临时存储group by序列中的每个值,以检查正在进行的值是否已经在连接的字符串中。同样,这可能是一个更大的问题,因此应作为一个新的SO问题进行提问。@deesolie No pandas不检查该值是否已在连接的字符串中。你点错菜了。这是一个矢量化操作。首先,unique返回唯一字符的向量。其次,
.join
将向量的所有元素连接在一起。谢谢Paul,用这种方式查看操作顺序更容易理解这一行是如何工作的。