Как получить данные о первых двух индексах для мультииндексного фрейма данных - PullRequest
0 голосов
/ 02 июля 2018

У меня есть фрейм данных, который выглядит следующим образом

enter image description here

Мне было интересно, существует ли самый быстрый способ создания диктата Python в пандах, который бы содержал данные, подобные следующим

table = {2: [4, 5, 6, 7, 8 ...], 4: [1, 2, 3, 4, ...]}

Здесь ключи - идентификаторы пользователей, а значения - уникальный список дат.

Это можно было сделать на ранних стадиях ядра Python, но мне было интересно, есть ли способ для быстрого вычисления, основанный на пандах или numpy. Мне нужно было быстрое решение, которое хорошо масштабируется, когда этот фрейм данных увеличивается.

Редактировать 1: Спектакли

Время: 14,3 мс ± 134 мкс на цикл (среднее ± стандартное отклонение из 7 циклов, 100 циклов в каждом)

levels = pd.DataFrame({k: df.index.get_level_values(k) for k in range(2)})

table = levels.drop_duplicates()\
              .groupby(0)[1].apply(list)\
              .to_dict()

print(table)

Время выполнения: 17,4 мс ± 105 мкс на цикл (среднее ± стандартное отклонение из 7 циклов, по 100 циклов в каждом)

res.reset_index().drop_duplicates(['user_id','date']).groupby('user_id')['date'].apply(list).to_dict()

принятое время: 294 мс ± 12,8 мс на цикл (среднее ± стандартное отклонение из 7 циклов, по 1 циклу каждый)

a = {k: list(pd.unique(list(zip(*g))[1])) 
     for k, g in groupby(df.index.values.tolist(), itemgetter(0))}
print (a)

Время съемки: 15 мс ± 187 мкс на цикл (среднее ± стандартное отклонение из 7 циклов, по 100 циклов в каждом)

pd.Series(res.index.get_level_values(1), index=res.index.get_level_values(0)).groupby(level=0).apply(set).to_dict()

Редактировать 2: Бенчмаркинг снова

Неверный результат

idx = df.index.droplevel(-1).drop_duplicates()
l1, l2 = idx.levels
mapping = defaultdict(list)
for i, j in zip(l1, l2):
    mapping[i].append(j)

Улучшенное время: 14,6 мс ± 58,8 мкс на цикл (среднее ± стандартное отклонение из 7 циклов, по 100 циклов каждый)

a = {k: list(set(list(zip(*g))[1])) 
     for k, g in groupby(res.index.values.tolist(), itemgetter(0))}

Ответы [ 3 ]

0 голосов
/ 02 июля 2018

Я думаю, что если требуется более высокая производительность, используйте itertools.groupby с unique для списков возврата в том же порядке, что и исходные данные. Если порядок не важен, используйте set:

df = pd.DataFrame({'A':list('abcdef'),
                   'B':[4,5,4,5,5,4],
                   'C':[7,8,9,4,2,3],
                   'D':[1,3,5,7,1,0],
                   'E':[5,3,6,9,2,4],
                   'F':list('aaabbb')}).set_index(['F','B', 'A'])

print (df)
       C  D  E
F B A         
a 4 a  7  1  5
  5 b  8  3  3
  4 c  9  5  6
b 5 d  4  7  9
    e  2  1  2
  4 f  3  0  4

from  itertools import groupby
from operator import itemgetter

a = {k: list(set(list(zip(*g))[1])) 
     for k, g in groupby(df.index.values.tolist(), itemgetter(0))}
print (a)
{'a': [4, 5], 'b': [5, 4]}

Другое решение для панд:

d = df.reset_index().drop_duplicates(['F','B']).groupby('F')['B'].apply(list).to_dict()
print (d)
{'a': [4, 5], 'b': [5, 4]}
0 голосов
/ 02 июля 2018

Данные из Jz

pd.Series(df.index.get_level_values(0),index=df.index.get_level_values(1)).groupby(level=0).apply(set).to_dict()
Out[92]: {4: {'a', 'b'}, 5: {'a', 'b'}}

Если вам нужен только список, вы можете добавить apply(list) PS: Лично не считаю, что этот шаг необходим

pd.Series(df.index.get_level_values(0),index=df.index.get_level_values(1)).groupby(level=0).apply(set).apply(list).to_dict()
Out[93]: {4: ['b', 'a'], 5: ['b', 'a']}
0 голосов
/ 02 июля 2018

Вот одно из решений, использующее drop_duplicates + groupby.

levels = pd.DataFrame({k: df.index.get_level_values(k) for k in range(2)})

table = levels.drop_duplicates()\
              .groupby(0)[1].apply(list)\
              .to_dict()

print(table)

{1: [2, 3], 2: [8, 9]}

Настройка

df = pd.DataFrame([[1, 2, 0, 3], [1, 2, 1, 4], [1, 3, 1, 5],
                   [2, 8, 1, 3], [2, 8, 1, 4], [2, 9, 2, 5]],
                  columns=['col1', 'col2', 'col3', 'col4'])

df = df.set_index(['col1', 'col2', 'col3'])

print(df)

                col4
col1 col2 col3      
1    2    0        3
          1        4
     3    1        5
2    8    1        3
          1        4
     9    2        5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...