Как суммировать столбец, сгруппированный другими столбцами в списке?
У меня есть список следующим образом.
[['Andrew', '1', '9'], ['Peter', '1', '10'], ['Andrew', '1', '8'], ['Peter', '1', '11'], ['Sam', '4', '9'], ['Andrew', '2', '2']]
Я хотел бы подвести итог последнему столбцу, сгруппированному по другим столбцам. Результат такой вот
[['Andrew', '1', '17'], ['Peter', '1', '21'], ['Sam', '4', '9'], ['Andrew', '2', '2']]
который по-прежнему является списком.
В реальной практике я всегда хотел бы подытожить последний столбец, сгруппированный по многим другим столбцам. Есть ли способ сделать это на Python? Очень признателен.
Ответы
Ответ 1
динамическая группировка по всем столбцам, кроме последней:
In [24]: df = pd.DataFrame(data)
In [25]: df.groupby(df.columns[:-1].tolist(), as_index=False).agg(lambda x: x.astype(int).sum()).values.tolist()
Out[25]: [['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]
Ответ 2
Это решение O (n) через collections.defaultdict
, адаптируемое к любому количеству ключей.
Если ваш желаемый результат является списком, то это может быть предпочтительнее для решения через Pandas, что требует преобразования в нестандартный тип и из него.
from collections import defaultdict
lst = [['Andrew', '1', '9'], ['Peter', '1', '10'], ['Andrew', '1', '8'],
['Peter', '1', '11'], ['Sam', '4', '9'], ['Andrew', '2', '2']]
d = defaultdict(int)
for *keys, val in lst:
d[tuple(keys)] += int(val)
res = [[*k, v] for k, v in sorted(d.items())]
Результат
[['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]
объяснение
- Пролистайте список списков, определите ключи/значение и добавьте в свой
defaultdict
по defaultdict
списки. - Используйте список, чтобы преобразовать словарь в желаемый результат.
Ответ 3
Op1
Вы можете передать индексную sum
и добавить tolist convert back to list
pd.DataFrame(L).\
set_index([0,1])[2].astype(int).sum(level=[0,1]).\
reset_index().values.tolist()
Out[78]: [['Andrew', '1', 17], ['Peter', '1', 21], ['Sam', '4', 9], ['Andrew', '2', 2]]
Op2
Для списка списка вы можете использовать groupby
из itertools
from itertools import groupby
[k+[sum(int(v) for _,_, v in g)] for k, g in groupby(sorted(l), key = lambda x: [x[0],x[1]])]
Out[98]: [['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]
Ответ 4
Создайте в DataFrame
и DataFrame
третий столбец, преобразованный в целые числа первым и вторым столбцами, последний конвертируйте обратно в list
s:
df = pd.DataFrame(L)
L = df[2].astype(int).groupby([df[0], df[1]]).sum().reset_index().values.tolist()
print (L)
[['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]
И решение с defaultdict, только python 3.x:
from collections import defaultdict
d = defaultdict(int)
#https://stackoverflow.com/a/10532492
for *head, tail in L:
d[tuple(head)] += int(tail)
d = [[*i, j] for i, j in sorted(d.items())]
print (d)
[['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]
Ответ 5
pd.factorize
и np.bincount
f, u = pd.factorize([tuple(x[:-1]) for x in data])
v = np.array([x[-1] for x in data], int)
[list(k) + [int(v)] for k, v in zip(u, np.bincount(f, v))]
[['Andrew', '1', 17], ['Peter', '1', 21], ['Sam', '4', 9], ['Andrew', '2', 2]]
Ответ 6
Добавил мои 2 цента. Оба из них используют groupby
, agg
V1: вводит новую функцию суммы.
sum=lambda x: x.astype(int).sum()
print(df.groupby([0,1], as_index=False).agg({2: sum}).values.tolist())
V2: преобразовывает столбец в числовой
df[2] = pd.to_numeric(df[2])
print(df.groupby([0,1], as_index=False).agg({2: sum}).values.tolist())
И вернется:
[['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]