Может ли pandas группировать агрегат в список, а не суммировать, означать и т.д.?
У меня был успех с использованием функции groupby для суммирования или усреднения заданной переменной по группам, но есть ли способ агрегировать в список значений, а не для получения единственного результата? (И будет ли это еще называться агрегацией?)
Я не совсем уверен, что это подход, который я должен принимать, так что ниже приведен пример преобразования, которое я хотел бы сделать, с игрушечными данными.
То есть, если данные выглядят примерно так:
A B C
1 10 22
1 12 20
1 11 8
1 10 10
2 11 13
2 12 10
3 14 0
То, что я пытаюсь закончить, это что-то вроде следующего. Я не совсем уверен, что это можно сделать, объединив группы в списки, и я довольно потерял, куда идти отсюда.
Гипотетический вывод:
A B C New1 New2 New3 New4 New5 New6
1 10 22 12 20 11 8 10 10
2 11 13 12 10
3 14 0
Может быть, мне следовало бы сфокусироваться? Порядок, по которому данные помещаются в столбцы, не имеет значения - все столбцы B через New6 в этом примере эквивалентны. Все предложения/исправления очень ценятся.
Ответы
Ответ 1
мое решение немного дольше, чем вы можете ожидать, я уверен, что его можно сократить, но:
g = df.groupby("A").apply(lambda x: pd.concat((x["B"], x["C"])))
k = g.reset_index()
k["i"] = k1.index
k["rn"] = k1.groupby("A")["i"].rank()
k.pivot_table(rows="A", cols="rn", values=0)
# output
# rn 1 2 3 4 5 6
# A
# 1 10 12 11 22 20 8
# 2 10 11 10 13 NaN NaN
# 3 14 10 NaN NaN NaN NaN
Немного объяснения. Первая строка, g = df.groupby("A").apply(lambda x: pd.concat((x["B"], x["C"])))
. Эта одна группа df
на A
, а затем поместите столбцы B
и C
в один столбец:
A
1 0 10
1 12
2 11
0 22
1 20
2 8
2 3 10
4 11
3 10
4 13
3 5 14
5 10
Затем k = g.reset_index()
, создавая последовательный индекс, результат:
A level_1 0
0 1 0 10
1 1 1 12
2 1 2 11
3 1 0 22
4 1 1 20
5 1 2 8
6 2 3 10
7 2 4 11
8 2 3 10
9 2 4 13
10 3 5 14
11 3 5 10
Теперь я хочу переместить этот индекс в столбец (я хотел бы услышать, как я могу сделать последовательный столбец без сброса индекса), k["i"] = k1.index
:
A level_1 0 i
0 1 0 10 0
1 1 1 12 1
2 1 2 11 2
3 1 0 22 3
4 1 1 20 4
5 1 2 8 5
6 2 3 10 6
7 2 4 11 7
8 2 3 10 8
9 2 4 13 9
10 3 5 14 10
11 3 5 10 11
Теперь k["rn"] = k1.groupby("A")["i"].rank()
добавит row_number внутри каждого A
(например, row_number() over(partition by A order by i)
в SQL:
A level_1 0 i rn
0 1 0 10 0 1
1 1 1 12 1 2
2 1 2 11 2 3
3 1 0 22 3 4
4 1 1 20 4 5
5 1 2 8 5 6
6 2 3 10 6 1
7 2 4 11 7 2
8 2 3 10 8 3
9 2 4 13 9 4
10 3 5 14 10 1
11 3 5 10 11 2
И, наконец, только поворот с помощью k.pivot_table(rows="A", cols="rn", values=0)
:
rn 1 2 3 4 5 6
A
1 10 12 11 22 20 8
2 10 11 10 13 NaN NaN
3 14 10 NaN NaN NaN NaN
Ответ 2
Я использовал следующие
grouped = df.groupby('A')
df = grouped.aggregate(lambda x: tuple(x))
df['grouped'] = df['B'] + df['C']
Ответ 3
Я отвечаю на вопрос, как указано в его заголовке и первом предложении: следующие значения агрегируются в списки.
import pandas as pd
df = pd.DataFrame( {'A' : [1, 1, 1, 1, 2, 2, 3], 'B' : [10, 12, 11, 10, 11, 12, 14], 'C' : [22, 20, 8, 10, 13, 10, 0]})
print df
# Old version
# df2=df.groupby(['A']).apply(lambda tdf: pd.Series( dict([[vv,tdf[vv].unique().tolist()] for vv in tdf if vv not in ['A']]) ))
df2 = df.groupby('A').aggregate(lambda tdf: tdf.unique().tolist())
print df2
Вывод следующий:
In [3]: run tmp
A B C
0 1 10 22
1 1 12 20
2 1 11 8
3 1 10 10
4 2 11 13
5 2 12 10
6 3 14 0
[7 rows x 3 columns]
B C
A
1 [10, 12, 11] [22, 20, 8, 10]
2 [11, 12] [13, 10]
3 [14] [0]
[3 rows x 2 columns]
Ответ 4
Вот один лайнер
# if list of unique items is desired, use set
df.groupby('A',as_index=False)['B'].aggregate(lambda x: set(x))
# if duplicate items are okay, use list
df.groupby('A',as_index=False)['B'].aggregate(lambda x: list(x))
Ответ 5
Подобное решение, но довольно прозрачное (я думаю). Вы можете получить полный список или уникальные списки.
df = pd.DataFrame({'A':[1,1,2,2,2,3,3,3,4,5],
'B':[6,7, 8,8,9, 9,9,10,11,12],
'C':['foo']*10})
df
Out[24]:
A B C
0 1 6 foo
1 1 7 foo
2 2 8 foo
3 2 8 foo
4 2 9 foo
5 3 9 foo
6 3 9 foo
7 3 10 foo
8 4 11 foo
9 5 12 foo
list_agg = df.groupby(by='A').agg({'B':lambda x: list(x),
'C':lambda x: tuple(x)})
list_agg
Out[26]:
C B
A
1 (foo, foo) [6, 7]
2 (foo, foo, foo) [8, 8, 9]
3 (foo, foo, foo) [9, 9, 10]
4 (foo,) [11]
5 (foo,) [12]
unique_list_agg = df.groupby(by='A').agg({'B':lambda x: list(pd.unique(x)),
'C':lambda x: tuple(pd.unique(x))})
unique_list_agg
Out[28]:
C B
A
1 (foo,) [6, 7]
2 (foo,) [8, 9]
3 (foo,) [9, 10]
4 (foo,) [11]
5 (foo,) [12]
Ответ 6
Я боролся с одними и теми же проблемами, и ответ заключается в том, что да, вы можете использовать grouby для получения списков. Я не уверен на 100%, что я делаю это самым питоническим способом, но здесь для чего стоит моя попытка дойти до вашего вопроса. Вы можете создавать списки данных, содержащихся в таких группах:
import pandas as pd
import numpy as np
from itertools import chain
Data = {'A' : [1, 1, 1, 1, 2, 2, 3], 'B' : [10, 12, 11, 10, 11, 12, 14], 'C' : [22, 20, 8, 10, 13, 10, 0]}
DF = pd.DataFrame(Data)
DFGrouped = DF.groupby('A')
OutputLists = []
for group in DFGrouped:
AList = list(group[1].A)
BList = list(group[1].B)
CList = list(group[1].C)
print list(group[1].A)
print list(group[1].B)
print list(group[1].C)
ZIP = zip(BList, CList)
print ZIP
OutputLists.append(list(chain(*ZIP)))
OutputLists
Это выводит ваши данные в список списков, так, как мне кажется, вы этого хотите. Затем вы можете создать кадр данных. Вышеприведенные заявления для печати приведены только в иллюстративных целях. Наиболее эффективным (с точки зрения кода) способом сделать это с использованием моего метода является следующее:
import pandas as pd
import numpy as np
from itertools import chain
Data = {'A' : [1, 1, 1, 1, 2, 2, 3], 'B' : [10, 12, 11, 10, 11, 12, 14], 'C' : [22, 20, 8, 10, 13, 10, 0]}
DF = pd.DataFrame(Data)
DFGrouped = DF.groupby('A')
OutputLists = []
for group in DFGrouped:
ZIPPED = zip(group[1].B, group[1].C)
OutputLists.append(list(chain(*ZIPPED)))
OutputLists
Ключом к получению списков из сгруппированных данных, насколько я могу судить, является признание того, что сами данные хранятся в группе [1] для каждой группы в ваших сгруппированных данных.
надеюсь, что это поможет!
Ответ 7
df2 = df.groupby('A').aggregate(lambda tdf: tdf.unique().tolist())
Кажется, это работает идеально, но результирующий информационный кадр имеет два слоя столбцов, а df.columns показывает только один столбец в информационном кадре. Чтобы исправить это, используйте:
df2_copy=df2.copy()
df2_copy = df2_copy.reset_index(col_level=0)
Вы можете просмотреть уровни столбцов, используя: df2_copy.columns = df2_copy.columns.get_level_values (0)
df2_copy()
должен решить это.