Предположим, что у меня есть этот фреймворк:
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, и расплавился, но я либо закончил с огромной размерностью, либо потерял данные.
Вот еще один:
newdf = pd.DataFrame(df.groupby('index')['var_vals'].unique().tolist()).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
Использование 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
Еще один способ использования конструктора по умолчанию
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)
Один метод через 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
apply
:-)