Pandas 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/generated/pandas.Series.unique.html)は機能しませんが、

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

です

pandas.core.groupby.SeriesGroupBy object

だから私はどんなSeriesメソッドもうまくいくことを望んでいました。何か案は?

回答:


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

フレーム全体で、一度に1つのグループでこれを行います。キーを返すことです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}

これらの操作はベクトル化されapply、とlambdasの必要性がなくなったようです。なぜpandas実際に連結し、文字列の合計時にエラーを返さないのかと思ってここに来ました。
NelsonGon

1
文字列を連結してその間に文字を追加しようとしている場合、以下の@voithosで推奨されている.aggソリューションは、ここで推奨されている.applyよりもはるかに高速です。私のテストでは、5〜10倍速くなりました。
ダブルダウン

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倍速くなりました。
ダブルダウン

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

8

名前付き集計 pandas >= 0.25.0

パンダバージョン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}))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.