Как растопить `pandas.DataFrame` с часовыми колоннами и разделить их на 15-минутные интервалы - PullRequest
3 голосов
/ 12 октября 2019

У меня есть DataFrame что-то вроде этого:

data = [['2019-01-01', .1, .2],
        ['2019-01-02', .5, .3],
        ['2019-01-03', .2, .4]]
df = pd.DataFrame(data, columns=['date', 'hour01', 'hour02'])
         date  hour01  hour02
0  2019-01-01     0.1     0.2
1  2019-01-02     0.5     0.3
2  2019-01-03     0.2     0.4

Как расплавить его, чтобы получить правильные 15-минутные интервалы? Вот так:

    timestamp              value
0  2019-01-01 00:00:00     0.1
1  2019-01-01 00:15:00     0.1
2  2019-01-01 00:30:00     0.1
3  2019-01-01 00:45:00     0.1
4  2019-01-01 01:00:00     0.2
5  2019-01-01 01:15:00     0.2
6  2019-01-01 01:30:00     0.2
7  2019-01-01 01:45:00     0.2
...
16 2019-01-03 00:00:00     0.2
17 2019-01-03 00:15:00     0.2
18 2019-01-03 00:30:00     0.2
19 2019-01-03 00:45:00     0.2
20 2019-01-03 01:00:00     0.4
21 2019-01-03 01:15:00     0.4
22 2019-01-03 01:30:00     0.4
23 2019-01-03 01:45:00     0.4

Редактировать

df.melt(id_vars=['timestamp'], value_vars=['hour_{}'.format(str(x).zfill(2)) for x in range(1, 24)])

дает мне это:

27    2017-01-28  hour_01  34.90
28    2017-01-29  hour_01  36.04
29    2017-01-30  hour_01  36.51
          ...      ...    ...
16760 2018-12-02  hour_23  51.50
16761 2018-12-03  hour_23  54.00
16762 2018-12-04  hour_23  53.87

Куда идти отсюда?

Ответы [ 2 ]

3 голосов
/ 12 октября 2019

Возможно, вы также можете сделать это, начиная с melt, но если по какой-либо причине не требуется использовать melt, вы можете получить его следующим образом:

  1. Сделать 'date' adatetime столбец, если еще нет.
  2. Используя groupby и apply, вы можете сгенерировать временные метки для всех временных интервалов, используя pandas date_range и охватывая часовые значения, используя numpy repeat .
  3. Наконец, сбросьте индекс.

Переведено в код:

df['date'] = pd.to_datetime(df['date'])

ddf = df.groupby('date').apply(lambda row : pd.DataFrame(
      {'timestamp' : pd.date_range(row['date'].iloc[0], periods=4*len(df.columns[1:]), freq='15T'),
       'value' : np.repeat(np.array([row[col].iloc[0] for col in df.columns[1:]]), 4)}))
ddf.reset_index(inplace=True, drop=True)

Используя исходный фрейм данных, ddf равно:

             timestamp  value
0  2019-01-01 00:00:00    0.1
1  2019-01-01 00:15:00    0.1
2  2019-01-01 00:30:00    0.1
3  2019-01-01 00:45:00    0.1
4  2019-01-01 01:00:00    0.2
5  2019-01-01 01:15:00    0.2
6  2019-01-01 01:30:00    0.2
7  2019-01-01 01:45:00    0.2
8  2019-01-02 00:00:00    0.5
9  2019-01-02 00:15:00    0.5
10 2019-01-02 00:30:00    0.5
11 2019-01-02 00:45:00    0.5
12 2019-01-02 01:00:00    0.3
13 2019-01-02 01:15:00    0.3
14 2019-01-02 01:30:00    0.3
15 2019-01-02 01:45:00    0.3
16 2019-01-03 00:00:00    0.2
17 2019-01-03 00:15:00    0.2
18 2019-01-03 00:30:00    0.2
19 2019-01-03 00:45:00    0.2
20 2019-01-03 01:00:00    0.4
21 2019-01-03 01:15:00    0.4
22 2019-01-03 01:30:00    0.4
23 2019-01-03 01:45:00    0.4

Этот код автоматически выберет количество столбцов после 'date', при условии, что они все 'hour' столбцы. Если у вас есть другие столбцы, смешанные в кадре данных, они должны быть отфильтрованы из df.columns[1:].

2 голосов
/ 13 октября 2019

Решение на основе melt, set_index и ffill:

df = df.melt(id_vars=['date'], var_name='hour')
df['timestamp'] = pd.to_datetime(df['date']) + pd.to_timedelta(df['hour'].str[4:].astype(int) - 1, unit='h')
df = df.set_index(pd.DatetimeIndex(df['timestamp']))
df = df.drop(columns=['timestamp', 'date', 'hour'])
df = df.resample('15T').ffill()
df = df.reset_index()

Результаты:

              timestamp  value
0   2019-01-01 00:00:00    0.1
1   2019-01-01 00:15:00    0.1
2   2019-01-01 00:30:00    0.1
3   2019-01-01 00:45:00    0.1
4   2019-01-01 01:00:00    0.2
..                  ...    ...
192 2019-01-03 00:00:00    0.2
193 2019-01-03 00:15:00    0.2
194 2019-01-03 00:30:00    0.2
195 2019-01-03 00:45:00    0.2
196 2019-01-03 01:00:00    0.4
...