Подтвердить что ты не робот

Pandas groupby: Как получить объединение строк

У меня есть dataframe, как это:

   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

поэтому я надеялся, что любой метод серии будет работать. Любые идеи?

4b9b3361

Ответ 1

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

Делать это на весь кадр, по одной группе за раз. Ключ должен вернуть 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}

Ответ 2

Вы можете использовать метод 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.

Ответ 3

Вы можете использовать функцию aggregate (или agg), чтобы объединить значения. (Непроверенный код)

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

Ответ 4

Вы можете попробовать это:

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

Ответ 5

простое решение:

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

Ответ 6

Если вы хотите перезаписать столбец B в кадре данных, это должно работать:

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

Ответ 7

Именованные агрегаты с 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

Ответ 8

После хорошего ответа @Erfan в большинстве случаев при анализе агрегированных значений вам нужны уникальные возможные комбинации этих существующих значений символов:

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