139 votes

Le groupe des pandas : Comment obtenir une union de chaînes de caractères

J'ai un cadre de données comme ceci :

   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       !

Appel à

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

retournera

A
1    1.615586
2    0.421821
3    0.463468
4    0.643961

Maintenant, je voudrais faire "la même chose" pour la colonne "C". Comme cette colonne contient des chaînes de caractères, la fonction sum() ne fonctionne pas (bien que l'on puisse penser qu'elle concaténerait les chaînes de caractères). Ce que j'aimerais vraiment voir, c'est une liste ou un ensemble de chaînes de caractères pour chaque groupe, c.-à-d.

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

J'ai essayé de trouver des moyens de le faire.

Series.unique() ( http://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.unique.html ) ne fonctionne pas, bien que

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

est un

pandas.core.groupby.SeriesGroupBy object

donc j'espérais que n'importe quelle méthode des séries fonctionnerait. Des idées ?

199voto

Jeff Points 27612
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

Lorsque vous appliquez votre propre fonction, il n'y a pas d'exclusion automatique des colonnes non numériques. Cela est toutefois plus lent que l'application de la fonction .sum() au 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 par défaut, concatène

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

Vous pouvez faire à peu près ce que vous voulez

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

Je fais cela sur un cadre entier, un groupe à la fois. La clé est de retourner un 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}

83voto

BrenBarn Points 63718

Vous pouvez utiliser le apply pour appliquer une fonction arbitraire aux données groupées. Ainsi, si vous voulez un ensemble, appliquez set . Si vous voulez une liste, appliquez 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

Si vous voulez autre chose, écrivez simplement une fonction qui fait ce que vous voulez et ensuite apply que.

36voto

voithos Points 15066

Vous pouvez utiliser le aggregate (ou agg ) pour concaténer les valeurs. (Code non testé)

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

17voto

user3241146 Points 161

Vous pouvez essayer ceci :

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

15voto

Erfan Points 19682

Agrégations nommées avec pandas >= 0.25.0

Depuis la version 0.25.0 de pandas, nous disposons d'agrégations nommées qui nous permettent de regrouper, d'agréger et, en même temps, d'attribuer de nouveaux noms à nos colonnes. De cette façon, nous n'aurons pas les colonnes MultiIndex, et les noms des colonnes ont plus de sens compte tenu des données qu'elles contiennent :


agréger et obtenir une liste de chaînes de caractères

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]

agréger et joindre les chaînes de caractères

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X