Хороший способ выполнить следующее широкоформатное преобразование фрейма данных в длинный формат?

#python #python-3.x #pandas #dataframe

#python #python-3.x #pandas #фрейм данных

Вопрос:

Чего я пытаюсь достичь, так это преобразовать фрейм данных, аналогичный, но больше, чем здесь начинается, и в конечном итоге получить цель. Я полагаю, что следующие коды и выходные данные объясняют это лучше, чем я могу, но первые части имен столбцов (кроме даты) должны стать столбцами, а вторые части значениями нового столбца с именем source. У меня более двух типов и двух источников.

Фиктивные данные:

 import pandas as pd
import numpy as np
import datetime as dt

n = 10
date = [dt.datetime.strftime(dt.datetime.now()   dt.timedelta(days=x), '%Y-%m-%d') for x in range(n)]
rn1 = np.random.randint(0, 50, n)
rn2 = np.random.randint(-50, 1, n)
  

Начать:

 data = {'date': date, 'type1 source1': rn1, 'type2 source1': rn1*100, 'type1 source2': rn2, 'type2 source2': rn2*100}
df = pd.DataFrame(data)
  

Вывод:

     date      type1 source1 type2 source1   type1 source2   type2 source2
0   2019-03-31  43           4300            -37            -3700
1   2019-04-01  42           4200            -34            -3400
2   2019-04-02  11           1100            -29            -2900
3   2019-04-03  38           3800            -31            -3100
4   2019-04-04  42           4200            -28            -2800
5   2019-04-05  31           3100            -50            -5000
6   2019-04-06  30           3000            -17            -1700
7   2019-04-07  19           1900            -18            -1800
8   2019-04-08   2            200            -43            -4300
9   2019-04-09  26           2600            -39            -3900
  

Цель:

 data = {'date': date*2,'type1': np.concatenate([rn1, rn2]) , 'type2': np.concatenate([rn1*100, rn2*100]), 'source': np.concatenate([np.repeat('source1', n), np.repeat('source2', n)])}
df = pd.DataFrame(data)
  

Вывод:

     date    type1   type2   source
0   2019-03-31  43  4300    source1
1   2019-04-01  42  4200    source1
2   2019-04-02  11  1100    source1
3   2019-04-03  38  3800    source1
4   2019-04-04  42  4200    source1
5   2019-04-05  31  3100    source1
6   2019-04-06  30  3000    source1
7   2019-04-07  19  1900    source1
8   2019-04-08   2   200    source1
9   2019-04-09  26  2600    source1
10  2019-03-31  -37 -3700   source2
11  2019-04-01  -34 -3400   source2
12  2019-04-02  -29 -2900   source2
13  2019-04-03  -31 -3100   source2
14  2019-04-04  -28 -2800   source2
15  2019-04-05  -50 -5000   source2
16  2019-04-06  -17 -1700   source2
17  2019-04-07  -18 -1800   source2
18  2019-04-08  -43 -4300   source2
19  2019-04-09  -39 -3900   source2
  

Ответ №1:

Сначала создайте MultiIndex из всех столбцов без столбцов с разделителем пробелов по DataFrame.set_index , затем создайте MultiIndex в столбцах по Series.str.split (пробел — значение по умолчанию, поэтому разделитель указывать не обязательно), измените форму по DataFrame.stack , отсортировав по второму уровню MultiIndex по DataFrame.sort_index с DataFrame.reset_index и последнему rename столбцу:

 df = df.set_index('date')
df.columns = df.columns.str.split(expand=True)
df = (df.stack()
        .sort_index(level=1)
        .reset_index()
        .rename(columns={'level_1':'source'}))
print (df)
          date   source  type1  type2
0   2019-03-31  source1     43   4300
1   2019-04-01  source1     42   4200
2   2019-04-02  source1     11   1100
3   2019-04-03  source1     38   3800
4   2019-04-04  source1     42   4200
5   2019-04-05  source1     31   3100
6   2019-04-06  source1     30   3000
7   2019-04-07  source1     19   1900
8   2019-04-08  source1      2    200
9   2019-04-09  source1     26   2600
10  2019-03-31  source2    -37  -3700
11  2019-04-01  source2    -34  -3400
12  2019-04-02  source2    -29  -2900
13  2019-04-03  source2    -31  -3100
14  2019-04-04  source2    -28  -2800
15  2019-04-05  source2    -50  -5000
16  2019-04-06  source2    -17  -1700
17  2019-04-07  source2    -18  -1800
18  2019-04-08  source2    -43  -4300
19  2019-04-09  source2    -39  -3900
  

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

1. не могли бы вы, пожалуйста, объяснить, как sort_index(level=1) работает спасибо

2. @Akhilesh — Конечно, при сортировке MultiIndex — Индекс создается по 2 столбцам по второму «столбцу» — второму уровню мультииндекса.

Ответ №2:

Также другой возможной альтернативой является pd.wide_to_long():

 df1 = pd.wide_to_long(df, ['type1', 'type2'], i = 'date', j ='source', sep =' ', suffix = 'w ').reset_index()