Скользящее временное окно на кадре данных панд по группам - PullRequest
1 голос
/ 01 ноября 2019

Рассмотрим пример этого кадра данных (код для построения ниже):

             t    p
o                   
2007-01-01  0.0  1.0
2007-01-02  0.0  1.0
2007-01-03  0.0  1.0
2007-01-10  0.0  1.0
2007-01-11  0.0  1.0
2007-01-20  1.0  0.0
2007-01-21  1.0  0.0
2007-01-22  1.0  0.0
2007-01-23  1.0  0.0
2007-01-27  1.0  0.0

Я хотел бы получить скользящую сумму за 2 дня прогнозного окна, для каждой «группы» вt. Для этого я реализовал:

df.iloc[::-1].groupby('t').rolling(window='2D').sum()

Однако это возвращает:

                 t    p
 t      o                   
0.0 2007-01-11  0.0  1.0
    2007-01-10  0.0  2.0
    2007-01-03  0.0  3.0
    2007-01-02  0.0  4.0
    2007-01-01  0.0  5.0
1.0 2007-01-27  1.0  0.0
    2007-01-23  2.0  0.0
    2007-01-22  3.0  0.0
    2007-01-21  4.0  0.0
    2007-01-20  5.0  0.0

, что не является двухдневной скользящей суммой окна. Я считаю, что проблема заключается в том, что когда я группирую t, я теряю временную информацию ('o'), так как она устанавливается в качестве индекса данных.

Повторная выборка строк с постоянными интервалами в 1 день для группы не будет работать из-за размера моего информационного кадра. Я попытался сгруппировать по 't', затем 'o', но это не работает.

Решение, которое я хотел бы получить:

             t    p
    o                   
2007-01-01  0.0  2.0
2007-01-02  0.0  1.0
2007-01-03  0.0  0.0
2007-01-10  0.0  1.0
2007-01-11  0.0  0.0
2007-01-20  2.0  0.0
2007-01-21  2.0  0.0
2007-01-22  1.0  0.0
2007-01-23  0.0  0.0
2007-01-27  0.0  0.0

Дополнительный код:

# code to construct df used in this example
o = ['2007-01-01','2007-01-02','2007-01-03','2007-01-10','2007-01-11',
     '2007-01-20','2007-01-21','2007-01-22','2007-01-23','2007-01-27']
t = np.zeros(10)
p = np.ones(10)
p[5:] = 0
t[5:] = 1
df = pd.DataFrame({'o':o, 't':t, 'p':p})
df['o'] = pd.to_datetime(df['o'], format='%Y-%m-%d')
df = df.set_index('o')

1 Ответ

1 голос
/ 01 ноября 2019

Как обойти (в течение двух дней):

def day_shift(x, days=2):
    ret = pd.DataFrame(0, index=x.index, columns=x.columns)
    for day in range(-days, 0):
        ret = ret.add(x.shift(day, freq='D'), fill_value=0)

    return ret.reindex(x.index)

df.groupby('t', as_index=False).apply(day_shift, days=2)

Вывод:

              t    p
o                   
2007-01-01  0.0  2.0
2007-01-02  0.0  1.0
2007-01-03  0.0  0.0
2007-01-10  0.0  1.0
2007-01-11  0.0  0.0
2007-01-20  2.0  0.0
2007-01-21  2.0  0.0
2007-01-22  1.0  0.0
2007-01-23  0.0  0.0
2007-01-27  0.0  0.0

Редактировать : еще один способ использовать прокаткудата должна перевернуть индекс даты, тогда мы можем использовать обратную прокрутку, которая фактически переходит вперед с точки зрения исходных дат:

future_date = pd.to_datetime('2100-01-01')
ancient_date = pd.to_datetime('2000-01-01')

# instead of setting `'o'` as index, let set ['o','t'] as index
df = df.set_index(['o','t'])

# here comes the crazy code
(df
    .assign(r_dates = (future_date - df.index.get_level_values('o')) + ancient_date)  # reverse date
    .sort_values('r_dates')
    .groupby('t')
    .rolling('2D', on='r_dates').sum()    # change 2 to the actual number of days
    .reset_index(level=0, drop=True)      # remove the index caused by groupby
    .assign(r_dates = lambda x: (x.index.get_level_values('o') - pd.to_timedelta('1D')), # shifted the date by one, since rolling includes the current date
           )
    .reset_index()
    .drop('o', axis=1)
    .set_index(['r_dates','t'])
    .reindex(df.index, fill_value=0)
)

Вывод:

                  p
o          t       
2007-01-01 0.0  2.0
2007-01-02 0.0  1.0
2007-01-03 0.0  0.0
2007-01-10 0.0  1.0
2007-01-11 0.0  0.0
2007-01-01 1.0  0.0
2007-01-02 1.0  0.0
2007-01-03 1.0  0.0
2007-01-10 1.0  0.0
2007-01-11 1.0  0.0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...