Создание столбцов для фрейма данных Pandas в соответствии со значением другого столбца

#python #pandas

#python #pandas

Вопрос:

Я использую Python3.7 и Pandas v0.25.3. У меня есть такой фрейм данных,

 pri_col col1 col2        Date
     r1    3    4  2020-09-10
     r2    4    1  2020-09-10
     r1    2    7  2020-09-11
     r3    6    4  2020-09-11
  

Я хочу что-то вроде,

 pri_col col1_2020-09-10 col2_2020-09-10 col1_2020-09-11 col2_2020-09-11
   r1               3               4             NaN             NaN
   r2               4               1             NaN             NaN
   r1             NaN             NaN               2               7
   r3             NaN             NaN               6               4
  

Я попробовал следующий код:

 import pandas as pd
df = pd.DataFrame([['r1', '3', '4', '2020-09-10'], ['r2', '4', '1', '2020-09-10'], ['r1', '2', '7', '2020-09-11'], ['r3', '6', '4', '2020-09-11']], columns=['pri_col', 'col1', 'col2', 'Date'])
print(df)
df_list = list()
for key, item in df.groupby('Date'):
    item = item.drop('Date', axis=1)
    item.columns = ['pri_col'] [str(x) '_' str(key) for x in item.columns if x != 'pri_col']
    df_list.append(item)
finDf = pd.concat(df_list, sort=False)
print(finDf)
  

Но этот код не оптимизирован для больших фреймов данных. Возможно ли иметь векторизованную реализацию для этого приложения в Pandas?
Многоуровневый фрейм данных также подходит для меня, если код векторизован. На верхнем уровне у меня может быть значение столбца «Дата», а на следующем уровне у меня могут быть столбцы.

Ответ №1:

Изменить форму с DataFrame.set_index помощью , DataFrame.stack и DataFrame.unstack это первая идея, которую необходимо сгладить MultiIndex :

 df = (df.set_index(['pri_col','Date'], append=True)
        .stack()
        .unstack([3,2])
        )
df.columns = [f'{a}-{b}' for a, b in df.columns]
df = df.reset_index(level=1).
print (df)
  pri_col  col1-2020-09-10  col2-2020-09-10  col1-2020-09-11  col2-2020-09-11
0      r1              3.0              4.0              NaN              NaN
1      r2              4.0              1.0              NaN              NaN
2      r1              NaN              NaN              2.0              7.0
3      r3              NaN              NaN              6.0              4.0
  

Или изменить форму с помощью DataFrame.melt и DataFrame.pivot :

 df = (df.reset_index()
        .melt(id_vars=['index','pri_col','Date'], 
              var_name='cols',
              value_name='val')
        .pivot(index=['index','pri_col'],
               columns=['cols','Date'],
               values='val'))
df.columns = [f'{a}-{b}' for a, b in df.columns]
df = df.reset_index(level=1).rename_axis(None)
print (df)
  pri_col  col1-2020-09-10  col1-2020-09-11  col2-2020-09-10  col2-2020-09-11
0      r1              3.0              NaN              4.0              NaN
1      r2              4.0              NaN              1.0              NaN
2      r1              NaN              2.0              NaN              7.0
3      r3              NaN              6.0              NaN              4.0
  

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

1. Привет. Я получаю сообщение об ошибке в сводной части. raise DataError("No numeric types to aggregate") pandas.core.base.DataError: No numeric types to aggregate

2. @AsifIqbal — это означает, что столбцы col1 col2 не заполняются числом, как работает первое решение?

3. Первое решение работает хорошо. Но не могли бы вы уточнить длинные цепочки в обоих ответах, чтобы я мог адаптировать их к своему приложению? На самом деле я новичок в Pandas. Так что извините, если мне нужно какое-то ненужное объяснение.

4. @AsifIqbal — Конечно, дайте мне знать, если что-то непонятно. For second используется pivot_table с агрегацией по умолчанию mean , поэтому он терпит неудачу, если не числовые столбцы. Возможное решение здесь — изменить его с aggfunc='mean' на aggfunc='first'

5. если ваша версия pandas> 1.1, pivot поддерживает создание мультииндексов, поэтому вам не нужно полагаться на pivot_table фиктивную функцию агрегирования