Панды: от многострочных до однострочных наблюдений

1

Предположим, что у меня есть этот фреймворк:

df = pd.DataFrame({'index':['10a','10a','10a','20b','20b','20b','30c','30c','30c']
                   ,'var_vals': ['aaa','aaa','abb','bbb','bba','bbb','ccc','ccc','cab']
                   ,'var2_vals':['aga','aga','add','bgb','bbd','bgb','cdd','cdd','cda']})
display(df)

Выглядит так:

    index   var_vals    var2_vals
0   10a     aaa         aga
1   10a     aaa         aga
2   10a     abb         add
3   20b     bbb         bgb
4   20b     bba         bbd
5   20b     bbb         bgb
6   30c     ccc         cdd
7   30c     ccc         cdd
8   30c     cab         cda

Как превратить вывод в одну строку только с тем, что отличается в новом столбце как таковом:

    index   var_vals     var_vals_0     var2_vals    var2_vals_0
0   10a     aaa             abb          aga            add
1   20b     bbb             bba          bgb            bbd
2   30c     ccc             cab          cdd            cda

Я попробовал groupby, pivot/pivot_table, stack/unstack, и расплавился, но я либо закончил с огромной размерностью, либо потерял данные.

  • 0
    Хорошо, этот вопрос теперь полностью изменен. Я сделал быстрый рефакторинг своего кода с помощью pd.concat (). Может быть, есть более разумное решение.
Теги:
pandas

4 ответа

3
Лучший ответ

Вот еще один:

newdf = pd.DataFrame(df.groupby('index')['var_vals'].unique().tolist()).fillna('')
  1. tolist() передает данные обратно в формат списка, что дает нам возможность воссоздать dataframe, передав его еще раз в pd.DataFrame()
  2. fillna обрабатывает тот факт, что у вас может быть разное количество уникальных предметов.

Обновленный код:

dfs = (pd.DataFrame(df.groupby('index')[i].unique().tolist()).fillna('').add_prefix(i+'_')
        for i in df.drop('index', 1))
df = pd.concat(dfs, axis=1)

Полный пример

import pandas as pd

df = pd.DataFrame({'index':['10a','10a','10a','20b','20b','20b','30c','30c','30c']
                   ,'var_vals': ['aaa','aaa','abb','bbb','bba','bbb','ccc','ccc','cab']
                   ,'var2_vals':['aga','aga','add','bgb','bbd','bgb','cdd','cdd','cda']})

df = pd.concat(
    (pd.DataFrame(df.groupby('index')[i].unique().tolist()).fillna('').add_prefix(i+'_')
    for i in df.drop('index', 1)), axis=1)

print(df)

Возвращает:

  var2_vals_0 var2_vals_1 var_vals_0 var_vals_1
0         aga         add        aaa        abb
1         bgb         bbd        bbb        bba
2         cdd         cda        ccc        cab
  • 0
    Фантастика, это делает трюк!
3

Использование drop_duplicates с drop_duplicates pivot

df.drop_duplicates().assign(key=lambda x : x.groupby('index').cumcount()).pivot('index','key','var_vals')
Out[910]: 
key      0    1
index          
10a    aaa  abb
20b    bbb  bba
30c    ccc  cab
  • 0
    Спасибо за быстрый ответ @Wen!
3

Еще один способ использования конструктора по умолчанию

x = df.drop_duplicates().groupby('index').var_vals.agg(list).to_dict()
pd.DataFrame(x).T

    0   1
10a aaa abb
20b bbb bba
30c ccc cab

Сроки (незначительно очень похоже, я думаю):

df = pd.concat([df]*10000).reset_index(drop=True)

%%timeit
x = df.drop_duplicates().groupby('index').var_vals.agg(list).to_dict()
pd.DataFrame(x).T
7.92 ms ± 224 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%%timeit 
df.drop_duplicates().assign(key=lambda x : x.groupby('index').cumcount()).pivot('index','key','var_vals')
8.81 ms ± 74.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%%timeit
df.groupby('index')['var_vals'].apply(lambda x: pd.Series(x.unique())).unstack()
8.83 ms ± 187 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%%timeit
pd.DataFrame(df.groupby('index')['var_vals'].unique().tolist())
13.3 ms ± 705 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
  • 1
    Благодарю за ваш ответ. Ваше решение эффективно даже при больших объемах данных. Фактически, когда я изолирую каждую интересующую переменную и запускаю ваш код, чтобы дать новый фрейм данных, я могу добавить имя переменной в качестве префикса, а затем объединить все вместе в конце.
  • 0
    @Cibic Рад, что я мог помочь человеку;)
3

Один метод через groupby.apply:

df.groupby('index')['var_vals'].apply(lambda x: pd.Series(x.unique())).unstack()

         0    1
index          
10a    aaa  abb
20b    bbb  bba
30c    ccc  cab
  • 1
    Может быть, не использовать apply :-)
  • 0
    Да, в этом смысле метод @ AntonvBR лучше!
Показать ещё 7 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню