Pandalar groupby: Bir dizi birliği nasıl elde edilir


122

Bunun gibi bir veri çerçevem ​​var:

   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       !

çağrı

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

dönecek

A
1    1.615586
2    0.421821
3    0.463468
4    0.643961

Şimdi "C" sütunu için "aynısını" yapmak istiyorum. Bu sütun dizeler içerdiğinden, sum () çalışmaz (dizeleri birleştireceğini düşünseniz bile). Gerçekten görmek istediğim şey, her grup için bir dizi veya dizi dizisidir.

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

Bunu yapmanın yollarını bulmaya çalışıyorum.

Series.unique () ( http://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.unique.html ) çalışmıyor, ancak

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

bir

pandas.core.groupby.SeriesGroupBy object

bu yüzden herhangi bir Seri yönteminin işe yarayacağını umuyordum. Herhangi bir fikir?

Yanıtlar:


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

Kendi işlevinizi uyguladığınızda, sayısal olmayan sütunların otomatik olarak hariç tutulması söz konusu değildir. Yine de .sum()bu,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 varsayılan olarak birleştirir

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

İstediğini hemen hemen yapabilirsin

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

Bunu tüm çerçeve üzerinde, her seferinde bir grup yapmak. Anahtar, birSeries

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}

Görünüşe göre bu işlemler artık applyve lambdas'ye olan ihtiyacı ortadan kaldırarak vektörleştirilmiştir . Buraya neden pandasaslında concats'i ve dizeleri toplamada bir hata döndürmediğini merak ederek geldim .
NelsonGon

1
Dizeleri birleştirmeye ve aralarına bir karakter eklemeye çalışıyorsanız, aşağıdaki @voithos tarafından önerilen .agg çözümü burada .apply'den çok daha hızlıdır. Testlerimde 5-10 kat daha hızlı oluyordum.
Doubledown

70

applyGruplanmış verilere rastgele bir işlev uygulamak için yöntemi kullanabilirsiniz . Yani bir set istiyorsanız, uygulayın set. Liste istiyorsanız başvurunuz 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

Başka bir şey istiyorsanız, istediğinizi yapan ve sonra applybunu yapan bir işlev yazın .


İyi çalışıyor, ancak Sütun A eksik.
Vineesh TP

@VineeshTP: A Sütunu, gruplandırma sütunu olarak kullanıldı, bu nedenle, örnekte görebileceğiniz gibi dizinde yer alıyor. Kullanarak bir sütun olarak geri alabilirsiniz .reset_index().
BrenBarn

30

Kullanılacak mümkün olabilir aggregate(ya da aggdeğerlerini birleştirmek için) işlevini. (Test edilmemiş kod)

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

Gerçekten çalışıyor. İnanılmaz. @Voithos'un "denenmemiş" dediği gibi, pek iyimser değildim. Bit versiyonunu bir agg sözlüğünde bir girdi olarak test ettim ve amaçlandığı gibi çalıştı: .agg ({'tp': 'sum', 'BaseWgt': 'max', 'TP_short': lambda col: ',' .join (col)})
Günümü Kurdu

2
Dizeleri bir tür ayırıcıyla birleştirmeye çalışıyorsanız, bu .agg önerisinin .apply'den çok daha hızlı olduğunu buldum. 600k + metin dizelerinden oluşan bir veri kümesi için, aynı sonuçları 5-10 kat daha hızlı aldım.
2019

14

Bunu deneyebilirsin:

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

2
İncelemeden: Lütfen cevabınıza daha fazla açıklama ekleyebilir misiniz?
toti08

1
Groupby, 'A' sütununa uygulanır ve agg işlevi ile farklı sütunlarda farklı işlevler kullanabilirim, örneğin 'C' sütunundaki öğeleri
toplayabilir

8

basit bir çözüm şöyle olacaktır:

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

bu doğru cevap olmalı. temiz cevap vermenizi sağlar. çok teşekkürler!
imsrgadich

Birinin listenin içeriğini bir dizeye dahil etmekle ilgilenmesi durumunda df.groupby(['A','B']).c.unique().apply(lambda x: ';'.join(x)).reset_index()
Vivek-Ananth

8

İle adlandırılmış toplamalar pandas >= 0.25.0

Pandalar 0.25.0 sürümünden beri gruplandırabileceğimiz, toplayabileceğimiz ve aynı zamanda sütunlarımıza yeni isimler atayabileceğimiz toplamaları adlandırdık. Bu şekilde MultiIndex sütunlarını alamayız ve sütun adları, içerdikleri veriler göz önüne alındığında daha anlamlı olur:


toplayın ve dizelerin bir listesini alın

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]

toplayın ve dizeleri birleştirin

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

Veri çerçevesinde B sütununun üzerine yazmak isterseniz, bu işe yaramalıdır:

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

2

@ Erfan'ın iyi cevabının ardından, çoğu zaman toplam değerlerin analizinde bu mevcut karakter değerlerinin benzersiz olası kombinasyonlarını istersiniz:

unique_chars = lambda x: ', '.join(x.unique())
(df
 .groupby(['A'])
 .agg({'C': unique_chars}))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.