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

Сделайте группу Pandas groupby, действуя аналогично группе itertools groupby

Предположим, что у меня есть список Python таких списков:

{'Grp': ['2'   , '6'   , '6'   , '5'   , '5'   , '6'   , '6'   , '7'   , '7'   , '6'], 
'Nums': ['6.20', '6.30', '6.80', '6.45', '6.55', '6.35', '6.37', '6.36', '6.78', '6.33']}

Я могу легко сгруппировать числа и групповой ключ, используя itertools.groupby:

from itertools import groupby
for k, l in groupby(zip(di['Grp'], di['Nums']), key=lambda t: t[0]):
    print k, [t[1] for t in l]

Печать

2 ['6.20']
6 ['6.30', '6.80']      # one field, key=6
5 ['6.45', '6.55']
6 ['6.35', '6.37']      # second
7 ['6.36', '6.78']
6 ['6.33']              # third

Обратите внимание, что ключ 6 разделен на три отдельные группы или поля.

Теперь предположим, что у меня есть эквивалент Pandas DataFrame для моего dict (те же данные, тот же порядок списка и те же клавиши):

  Grp  Nums
0   2  6.20
1   6  6.30
2   6  6.80
3   5  6.45
4   5  6.55
5   6  6.35
6   6  6.37
7   7  6.36
8   7  6.78
9   6  6.33

Если я использую Pandas 'groupby, я не вижу, как получить групповую итерацию. Вместо этого Pandas группируется по значению ключа:

for e in df.groupby('Grp'):
    print e

Печать

('2',   Grp  Nums
0   2  6.20)
('5',   Grp  Nums
3   5  6.45
4   5  6.55)
('6',   Grp  Nums
1   6  6.30            
2   6  6.80                # df['Grp'][1:2] first field
5   6  6.35                # df['Grp'][5:6] second field
6   6  6.37                 
9   6  6.33)               # df['Grp'][9] third field
('7',   Grp  Nums
7   7  6.36
8   7  6.78)

Примечание: групповые клавиши 6 сгруппированы вместе; а не отдельные группы.

Мой вопрос: существует ли эквивалентный способ использования группы Pandas ', так что 6, например, будет в трех группах таким же образом, как Python groupby?

Я пробовал это:

>>> df.reset_index().groupby('Grp')['index'].apply(lambda x: np.array(x))
Grp
2                [0]
5             [3, 4]
6    [1, 2, 5, 6, 9]         # I *could* do a second groupby on this...
7             [7, 8]
Name: index, dtype: object

Но он по-прежнему сгруппирован с помощью общего ключа Grp, и мне нужно будет сделать вторую группу на nd.array, чтобы разделить подгруппы каждого ключа.

4b9b3361

Ответ 1

Ну, чтобы не быть нахальным, но почему бы просто не использовать Python groupby в DataFrame, используя iterrows? Это то, для чего оно предназначено для:

>>> df
  Grp  Nums
0   2  6.20
1   6  6.30
2   6  6.80
3   5  6.45
4   5  6.55
5   6  6.35
6   6  6.37
7   7  6.36
8   7  6.78
9   6  6.33

>>> from itertools import groupby
>>> for k, l in groupby(df.iterrows(), key=lambda row: row[1]['Grp']):
        print k, [t[1]['Nums'] for t in l]

Печать

2 ['6.20']
6 ['6.30', '6.80']
5 ['6.45', '6.55']
6 ['6.35', '6.37']
7 ['6.36', '6.78']
6 ['6.33']

Чтобы попытаться сделать Panda groupby действовать так, как вы хотите, возможно, запрашивается так много многоуровневых методов, что вы не сможете следовать ему, когда перечитываете в будущем.

Ответ 2

Сначала вы можете определить, какие элементы в столбце Grp отличаются от предыдущего и получить совокупную сумму для формирования групп, которые вам нужны:

In [9]:
    diff_to_previous = df.Grp != df.Grp.shift(1)
    diff_to_previous.cumsum()
Out[9]:

0    1
1    2
2    2
3    3
4    3
5    4
6    4
7    5
8    5
9    6

Итак, вы можете сделать

df.groupby(diff_to_previous.cumsum()) 

чтобы получить желаемый объект группы

Ответ 3

В основном вы хотите создать новый столбец для индексации желаемого порядка группировки, а затем использовать его для группировки. Вы сохраняете номер индекса до тех пор, пока значение в Grp не изменится.

Для ваших данных вы хотели бы что-то вроде этого:

   Grp  Nums new_group
0    2  6.20         1
1    6  6.30         2
2    6  6.80         2
3    5  6.45         3
4    5  6.55         3
5    6  6.35         4
6    6  6.37         4
7    7  6.36         5
8    7  6.78         5
9    6  6.33         6

Теперь вы можете группировать как new group, так и Grp:

df.groupby(['new_group', 'Grp']).Nums.groups
{(1, 2): [0],
 (2, 6): [1, 2],
 (3, 5): [3, 4],
 (4, 6): [5, 6],
 (5, 7): [7, 8],
 (6, 6): [9]

Я использовал этот метод для создания нового столбца:

df['new_group'] = None
for n, grp in enumerate(df.Grp):
if n is 0:
    df.new_group.iat[0] = 1    
elif grp == df.Grp.iat[n - 1]:
    df.new_group.iat[n] = df.new_group.iat[n - 1]
else:
    df.new_group.iat[n] = df.new_group.iat[n - 1] + 1

Обратите внимание, что этот ответ здесь имеет ту же идею (спасибо @ajcr за ссылку), но в гораздо более сжатом представлении:

>>> df.groupby((df.Grp != df.Grp.shift()).cumsum()).Nums.groups
{1: [0], 2: [1, 2], 3: [3, 4], 4: [5, 6], 5: [7, 8], 6: [9]