Поворот фрейма данных pandas по рангу по идентификатору

#python #python-3.x #pandas #pivot

#python #python-3.x #pandas #поворот

Вопрос:

В настоящее время я пытаюсь повернуть фрейм данных pandas по ‘id’ в ‘rank’

 print(df)

     id  rank  year  
0   key0  1    2011  
1   key0  2    2012  
2   key0  3    2013  
3   key1  1    2014  
4   key1  2    2015  
5   key1  3    2016  
6   key2  1    2017 
7   key2  2    2018 
8   key2  3    2019 
  

В зависимости от max (‘rank’) я хочу создать столько столбцов ‘years’ и присвоить им значения в соответствии с возрастающим рангом

 print(df)

     id  rank1  year1  rank2  year2  rank3   year3  
0   key0   1     2011    2     2012    3      2013
1   key1   1     2014    2     2015    3      2016  
2   key2   1     2017    2     2018    3      2019
  

Я попробовал свое собственное решение (в настоящее время работает, но у меня ~ 2 м строк и оно не очень эффективно)

 df2= df.melt(id_vars=["id", "rank"], value_vars=[elem for elem in df.columns if elem not ['id','rank']])
df2['col_name'] =df2['variable']  (df2['rang']-1).astype('str')
df2.value.fillna(0, inplace = True)
df2= pd.pivot_table(df2, index=["id"], columns=["col_name"], values="value", aggfunc=max)
  

Я знаю, что это не оптимальное решение и потребляет много памяти, вот почему я прошу лучшего решения

Заранее спасибо

Комментарии:

1. df.pivot(index="id",columns="rank", values=["year","rank"]) ?

Ответ №1:

Используйте DataFrame.sort_values с DataFrame.pivot , сортируя MultiIndex по DataFrame.sort_index , а затем сгладьте его по f-string s:

 df1 = (df.sort_values(['id','rank'])
         .pivot(index="id",columns="rank", values=["year","rank"])
         .sort_index(axis=1, level=1))
df1.columns = [f'{a}{b}' for a, b in df1.columns]
df1 = df1.reset_index()
print (df1)
     id  rank1  year1  rank2  year2  rank3  year3
0  key0      1   2011      2   2012      3   2013
1  key1      1   2014      2   2015      3   2016
2  key2      1   2017      2   2018      3   2019
  

Ответ №2:

Хотя это не имитирует точный результат, более простой подход предполагает выполнение поворота сразу.

 df.pivot(index="id", columns="rank", values="year")

rank     1     2     3
id                    
key0  2011  2012  2013
key1  2014  2015  2016
key2  2017  2018  2019
  

Лично мне не нравится иметь числа в качестве заголовков столбцов, поэтому я бы:

 df.pivot(index="id", columns="rank", values="year").rename(columns="rank_{}".format)

rank  rank_1  rank_2  rank_3
id                          
key0  2011    2012    2013  
key1  2014    2015    2016  
key2  2017    2018    2019 
  

Комментарии:

1. Все работает нормально, спасибо! Мне просто нужно выяснить, как изменить имя с несколькими индексами, если я добавлю несколько столбцов

2. Самый простой способ переименовать уровни мультииндексного с помощью метода Dataframe rename_axis

Ответ №3:

Вы можете сделать это:

 f=pd.DataFrame()
for name,group in df.groupby('rank'):
    group=group.rename(columns={'rank':'rank{}'.format(name),'year':'year{}'.format(name)})
    f=pd.concat([f.reset_index(drop=True),group.reset_index(drop=True)],axis=1)


#then, drop duplicate columns
f = f.loc[:,~f.columns.duplicated()]

f

     id  rank1  year1  rank2  year2  rank3  year3
0  key0      1   2011      2   2012      3   2013
1  key1      1   2014      2   2015      3   2016
2  key2      1   2017      2   2018      3   2019
  

Ответ №4:

Давайте используем .unstack with cumcount() для создания псевдоиндекса перед отключением и sort_index() .

Также предполагается, что ваш столбец ранга уже отсортирован.

 df1 = df.set_index(['id',df.groupby('id').cumcount()   1]).unstack(1).sort_index(1,1)

#flatten columns.
df1.columns = [f'{x}_{y}' for x,y in df1.columns]

print(df1)
      rank_1  year_1  rank_2  year_2  rank_3  year_3
id                                                  
key0       1    2011       2    2012       3    2013
key1       1    2014       2    2015       3    2016
key2       1    2017       2    2018       3    2019