Инициализация значений для первой и последней строки после операции передискретизации?

Учитывая, например, DataFrame с 1h Period, я хотел бы установить значения 0 и 1 в новом столбце всякий раз, когда новый 5h Period начинается и заканчивается соответственно.

Рассмотрим, например, эти входные данные:

import pandas as pd
from random import seed, randint
from collections import OrderedDict

p1h = pd.period_range(start='2020-02-01 00:00', end='2020-03-04 00:00', freq='1h', name='p1h')

seed(1)
values = [randint(0,10) for p in p1h]
df = pd.DataFrame({'Values' : values}, index=p1h)

Результат

df.head(10)

                  Values
p1h                     
2020-02-01 00:00       2
2020-02-01 01:00       9
2020-02-01 02:00       1
2020-02-01 03:00       4
2020-02-01 04:00       1
2020-02-01 05:00       7
2020-02-01 06:00       7
2020-02-01 07:00       7
2020-02-01 08:00      10
2020-02-01 09:00       6

Есть ли способ настроить новый столбец, чтобы получить следующий результат? (1-я и последняя строки для каждого периода инициализируются 0 и 1 соответственно)

df['period5h'] = df.resample('5h').???

df.head(10)

                  Values   period5h
p1h                     
2020-02-01 00:00       2          0   <- 1st row of 5h period
2020-02-01 01:00       9
2020-02-01 02:00       1
2020-02-01 03:00       4
2020-02-01 04:00       1          1   <- last row of 5h period
2020-02-01 05:00       7          0   <- 1st row of 5h period
2020-02-01 06:00       7
2020-02-01 07:00       7
2020-02-01 08:00      10
2020-02-01 09:00       6          1   <- last row of 5h period

Пожалуйста, можно ли это каким-то образом сделать с некоторыми функциями в пандах?

Конечная цель состоит в том, чтобы заполнить пустые значения линейной интерполяцией между 0 и 1, чтобы получить прогресс в% текущей строки по отношению к 5-часовому периоду.

Другой трек / вопрос

Другой подход может заключаться в инициализации 2-го DataFrame с 5h PeriodIndex, инициализации значений нового столбца до 1, а затем повышении дискретизации PeriodIndex до 1H для объединения обоих DataFrame.

Сдвиг (-1) инициализирует последнюю строку периода.

Я бы повторил процесс без сдвига для значения 0.

Тогда как я могу создать этот новый DataFrame, чтобы объединить его с первым? Я пробовал несколько команд слияния, но у меня есть ошибка, указывающая на то, что оба индекса имеют разную частоту.

Спасибо за вашу помощь! Лучшее


person pierre_j    schedule 03.04.2020    source источник
comment
если ваши данные действительно проиндексированы с периодом в 1 час, вы можете сделать df['period5h'] = np.arange(len(df))%5/4, что также создаст интерполяцию   -  person Ben.T    schedule 03.04.2020


Ответы (3)


Используйте атрибут indices объекта повторной выборки, чтобы найти первый и последний индексы групп. Это будет работать, даже если данные не имеют регулярной частоты или имеют частоту, которая не полностью разделяет частоту повторной дискретизации. В группах только одно измерение будет установлено на 1, а не на 0. Затем мы устанавливаем значения соответственно

i1 = [] # Last `.iloc` index labels
i0 = [] # First `.iloc` index labels
for k,v in df.resample('5H').indices.items():
    i0.append(v[0])
    i1.append(v[-1])

df.loc[df.index[i0], 'period_5H'] = 0
df.loc[df.index[i1], 'period_5H'] = 1

                  Values  period_5H
p1h                                
2020-02-01 00:00       2        0.0
2020-02-01 01:00       9        NaN
2020-02-01 02:00       1        NaN
2020-02-01 03:00       4        NaN
2020-02-01 04:00       1        1.0
2020-02-01 05:00       7        0.0
2020-02-01 06:00       7        NaN
2020-02-01 07:00       7        NaN
2020-02-01 08:00      10        NaN
2020-02-01 09:00       6        1.0
2020-02-01 10:00       3        0.0
...
person ALollz    schedule 03.04.2020
comment
Привет, aLollz, я ищу решение без петель. На самом деле я чувствую, что могу инициализировать новый DataFrame с помощью PeriodIndex «5H», полученного из моего начального кадра данных, я инициализирую новый столбец значением 1, затем я выполняю слияние между двумя DataFrame. Затем я могу выполнить сдвиг-1 нового столбца. Затем повторите для значения 0 без сдвига. Но я не знаю, как сохранить этот второй DataFrame, который я могу объединить. Есть ли у вас какие-либо идеи? - person pierre_j; 03.04.2020
comment
@pierre_j это действительно зависит от того, есть ли у вас регулярные частоты, которые равномерно делят вашу передискретизацию. Если вы этого не сделаете, тогда нет простого способа, потому что resample будет выводить регулярно отобранный DataFrame, а затем вы застряли, пытаясь угадать, какие строки слились с ними. Я предполагаю, что вы можете использовать слияние asof, но это становится чрезвычайно сложным по сравнению с буквальным выбором первого и последнего индексов в каждой группе. - person ALollz; 03.04.2020
comment
@ ALollz. да, PeriodIndex получается с помощью функции period_range (), поэтому он равномерно распределен. - person pierre_j; 03.04.2020

Не самый питонический подход, но он работает.

import pandas as pd
from random import seed, randint
from collections import OrderedDict
import time
p1h = pd.period_range(start='2020-02-01 00:00', end='2040-03-04 00:00', freq='1h', name='p1h')

seed(1)
values = [randint(0,10) for p in p1h]
df = pd.DataFrame({'Values' : values}, index=p1h)

t1 = time.time()
for i in range(len(df['Values'])):
  if (i+1)% 5 == 1:
    df['Values'].iloc[i] = 0
  elif (i+1) % 5 == 0:
    df['Values'].iloc[i] = 1
t2 = time.time()
df.head(20)

print(t2-t1)


время: 8.770591259002686

Подход 2:

import pandas as pd
from random import seed, randint
from collections import OrderedDict
import time
p1h = pd.period_range(start='2020-02-01 00:00', end='2040-03-04 00:00', freq='1h', name='p1h')

seed(1)
values = [randint(0,10) for p in p1h]
df = pd.DataFrame({'Values' : values}, index=p1h)

t1 = time.time()

df['Values'].iloc[range(0,len(df['Values']),5)] = 0
df['Values'].iloc[range(4,len(df['Values']),5)] = 1
t2 = time.time()
df.head(20)

print(t2-t1)

время: 0.009400367736816406

person Zabir Al Nazi    schedule 03.04.2020
comment
Привет, фурцифер. Спасибо за ваше предложение, но я ищу решение без петель. Время исполнения критично. - person pierre_j; 03.04.2020
comment
@furcufer, большое спасибо за ваш вклад. Извините, я действительно хочу работать с периодом. они могут быть практически любыми: 5 часов, 1 день, 1 неделя, 1 месяц ... Тем не менее, спасибо, я ценю вашу помощь! - person pierre_j; 03.04.2020
comment
это именно то, что он делает !!! Вы можете просто рассчитать длину кадра данных из периода и использовать диапазон. Если период важен, то он определенно делает то, о чем говорит, за очень короткое время. - person Zabir Al Nazi; 04.04.2020

Хорошо, я наконец настроил использовать следующий подход, который довольно быстр (без цикла)

 super_pi = pd.period_range(start='2020-01-01 00:00', end='2020-06-01 00:00', freq='5h', name='p5h')
 super_df = pd.DataFrame({'End' : 1, 'Start' : 0}, index=super_pi).resample('1h').first()
 # We know last row is a 1 (end of period)
 super_df['End'] = super_df['End'].shift(-1, fill_value=1)
 super_df['Period'] = super_df[['End','Start']].sum(axis=1, min_count=1)

Результат

 supder_df.head(10)

                   End  Start  Period
 p5h                                 
 2020-01-01 00:00  NaN    0.0     0.0
 2020-01-01 01:00  NaN    NaN     NaN
 2020-01-01 02:00  NaN    NaN     NaN
 2020-01-01 03:00  NaN    NaN     NaN
 2020-01-01 04:00  1.0    NaN     1.0
 2020-01-01 05:00  NaN    0.0     0.0
 2020-01-01 06:00  NaN    NaN     NaN
 2020-01-01 07:00  NaN    NaN     NaN
 2020-01-01 08:00  NaN    NaN     NaN

Лучшие,

person pierre_j    schedule 03.04.2020