Сгруппируйте в dataframe и передайте список полных строк в функцию сокращения - PullRequest
1 голос
/ 18 января 2020

Итак, у меня есть:

import pandas as pd

d = { id':  [0,    1,     2,   3,    4,    5,      6,   7,     8,      9],
d =  'date':[13,   7,     6,   12,   18,   11,     17,  5,     3,      17], 
     'foo': ['abc','def','def','abc','klm','abc', 'klm','xyz', 'pqr',  'klm'],
     'bar': ['123','456','333','123','111','123', '111', '331', '555', '111'],
     'cnt': [2,     0,    0,    1,    2,    0,     0,    0,      0,     0 ]
}
df = pd.DataFrame(d)
df

    id  date    foo bar cnt

0   0   13      abc 123 2
1   1   7       def 456 0
2   2   6       def 333 0
3   3   12      abc 123 1
4   4   18      klm 111 2
5   5   11      abc 123 0
6   6   17      klm 111 0
7   7   5       xyz 331 0
8   8   3       pqr 555 0
9   9   17      klm 111 0

Функция сокращения, которая на данный момент просто печатает свой аргумент, представляющий собой серию:

def fun(sr):
   print(sr.keys())
   for item in sr.iteritems(): 
       print(item)
   print('----')

Группировка по foo и bar :

df.groupby(['foo', 'bar']).date.agg([fun])

Мне нужно перейти к функции сокращения не только значений date, но и списка строк, соответствующих значениям foo и bar в groupby. Затем из этого списка мне нужно создать один словарь, ключи которого id -s от моего df, а значения dates. Эти словари следует добавить в виде отдельного столбца dicts к исходному фрейму данных df.

Обновление : полный пример того, что мне нужно получить:

    id  date    foo bar cnt dicts

0   0   13      abc 123 2   {('abc',123): [(0,13), (3,12), (5,11) }
1   1   7       def 456 0   {('def',456):[(1,7)]}
2   2   6       def 333 0   {('def',333):[(2,6)]}
3   3   12      abc 123 1   {('abc','123'): [(0,13), (3,12), (5,11) }
4   4   18      klm 111 2   {('klm',111):[(4,18),(6,17),(9,17)]}
5   5   11      abc 123 0   {('abc','123'): [(0,13), (3,12), (5,11) }
6   6   17      klm 111 0   {('klm',111):[(4,18),(6,17),(9,17)]}
7   7   5       xyz 331 0   {('xyz',331):[(7,5)]}
8   8   3       pqr 555 0   {('pqr',555):[(8,3)]}
9   9   17      klm 111 0   {('klm',111):[(4,18),(6,17),(9,17)]}

Любые идеи, как это сделать с groupby или, может быть, каким-то другим способом?

Ответы [ 2 ]

3 голосов
/ 19 января 2020

Самым простым является создание пользовательской функции с GroupBy.apply:

def fun(sr):
    vals = list(map(tuple, sr[['id','date']].to_numpy().tolist()))
    sr['dicts'] = [{sr.name:vals}] * len(sr)
    return sr

Решение для старых версий pandas:

def fun(sr):
    vals = list(map(tuple, sr[['id','date']].values.tolist()))
    sr['dicts'] = [{sr.name:vals}] * len(sr)
    return sr

df = df.groupby(['foo', 'bar']).apply(fun)
print (df)
  id  date  foo  bar  cnt                                          dicts
0   0    13  abc  123    2  {('abc', '123'): [(0, 13), (3, 12), (5, 11)]}
1   1     7  def  456    0                     {('def', '456'): [(1, 7)]}
2   2     6  def  333    0                     {('def', '333'): [(2, 6)]}
3   3    12  abc  123    1  {('abc', '123'): [(0, 13), (3, 12), (5, 11)]}
4   4    18  klm  111    2  {('klm', '111'): [(4, 18), (6, 17), (9, 17)]}
5   5    11  abc  123    0  {('abc', '123'): [(0, 13), (3, 12), (5, 11)]}
6   6    17  klm  111    0  {('klm', '111'): [(4, 18), (6, 17), (9, 17)]}
7   7     5  xyz  331    0                     {('xyz', '331'): [(7, 5)]}
8   8     3  pqr  555    0                     {('pqr', '555'): [(8, 3)]}
9   9    17  klm  111    0  {('klm', '111'): [(4, 18), (6, 17), (9, 17)]}
1 голос
/ 18 января 2020

Это должно сработать:

df["id_date"]=list(zip(df["id"], df["date"]))
gr=df.groupby(["foo", "bar"])

df=df.set_index(["foo", "bar"]).merge(gr["id_date"].agg(list).rename("dicts"), left_index=True, right_index=True).reset_index().drop("id_date", axis=1)
df["dicts"]=list(zip(list(zip(df["foo"], df["bar"])), df["dicts"]))

df["dicts"]=df["dicts"].map(lambda x: {x[0]: x[1]})

Вывод:

   foo  ...                                          dicts
0  abc  ...  {('abc', '123'): [(0, 13), (3, 12), (5, 11)]}
1  abc  ...  {('abc', '123'): [(0, 13), (3, 12), (5, 11)]}
2  abc  ...  {('abc', '123'): [(0, 13), (3, 12), (5, 11)]}
3  def  ...                     {('def', '333'): [(2, 6)]}
4  def  ...                     {('def', '456'): [(1, 7)]}
5  klm  ...  {('klm', '111'): [(4, 18), (6, 17), (9, 17)]}
6  klm  ...  {('klm', '111'): [(4, 18), (6, 17), (9, 17)]}
7  klm  ...  {('klm', '111'): [(4, 18), (6, 17), (9, 17)]}
8  pqr  ...                     {('pqr', '555'): [(8, 3)]}
9  xyz  ...                     {('xyz', '331'): [(7, 5)]}

[10 rows x 6 columns]
...