Сдвиг индекса DateTime в пределах Pandas MultiIndex - PullRequest
2 голосов
/ 19 апреля 2020

У меня есть CSV-файл, который выглядит следующим образом, когда я загружаю его:

# generate example data
users = ['A', 'B', 'C', 'D']
#dates = pd.date_range("2020-02-01 00:00:00", "2020-04-04 20:00:00", freq="H")
dates = pd.date_range("2020-02-01 00:00:00", "2020-02-04 20:00:00", freq="H")
idx = pd.MultiIndex.from_product([users, dates])
idx.names = ["user", "datehour"]
y = pd.Series(np.random.choice(a=[0, 1], size=len(idx)), index=idx).rename('y')

# write to csv and reload (turns out this matters)
y.to_csv('reprod_example.csv')
y = pd.read_csv('reprod_example.csv', parse_dates=['datehour'])
y = y.set_index(['user', 'datehour']).y

>>> y.head()
user  datehour           
A     2020-02-01 00:00:00    0
      2020-02-01 01:00:00    0
      2020-02-01 02:00:00    1
      2020-02-01 03:00:00    0
      2020-02-01 04:00:00    0
Name: y, dtype: int64

У меня есть следующая функция для создания отстающих функций индекса уровня:

def shift_index(a, dt_idx_name, lag_freq, lag):

    # get datetime index of relevant level
    ac = a.copy()
    dti = ac.index.get_level_values(dt_idx_name)

    # shift it
    dti_shifted = dti.shift(lag, freq=lag_freq)

    # put it back where you found it
    ac.index.set_levels(dti_shifted, level=dt_idx_name, inplace=True)

    return a

Но когда я запускаю: y_lag = shift_index(y, 'datehour', 'H', 1), я получаю следующую ошибку:

ValueError: Level values must be unique...

(я могу на самом деле устранить эту ошибку, добавив verify_integrity=False в .index.set_levels... в функции, но это (как и ожидалось) вызывает проблемы в будущем)

Вот странная часть. Если вы запустили приведенный выше пример, но без сохранения / перезагрузки из CSV, это работает. Кажется, причина в том, что y.index.get_level_value('datehour') показывает атрибут freq='H' сразу после его создания, но freq=None после его перезагрузки из CSV.

Это имеет смысл, очевидно, CSV не сохраняет эти метаданные. Но я обнаружил, что на удивление сложно установить атрибут freq для серии MultiIndexed. Например, это ничего не сделало. df.index.freq = pd.tseries.frequencies.to_offset("H"). И этот ответ также не работал для моего MultiIndex.

Так что я думаю, что мог бы решить эту проблему, если бы мне удалось установить атрибут freq компонента DateTime моего MultiIndex. Но моей конечной целью является создание версии моих y данных со смещенным компонентом DateTime MultiIndex, как, например, с моей функцией shift_index выше. Поскольку я получаю свои данные через CSV, «просто не сохранять в CSV и перезагрузить» не вариант.

1 Ответ

2 голосов
/ 19 апреля 2020

После долгих волнений я смог установить часовую частоту, используя asfreq('H') для сгруппированных данных, так что каждая группа имеет уникальные значения для индекса datehour.

y = pd.read_csv('reprod_example.csv', parse_dates=['datehour'])
y = y.groupby('user').apply(lambda df: df.set_index('datehour').asfreq('H')).y

Просмотр индекса значение показывает правильную частоту.

y.index[0]                                                                                                                                                                                                                          
# ('A', Timestamp('2020-02-01 00:00:00', freq='H'))

Все, что мы делаем, это устанавливаем индекс из двух частей. user идет первым, так что вложенный индекс datehour может быть уникальным в нем. Если индекс datehour уникален, можно без труда использовать asfreq.

Если вы попробуете asfreq для неуникального индекса, он не будет работать.

y_load.set_index('datehour').asfreq('H')
# ---------------------------------------------------------------------------
# ValueError                                Traceback (most recent call last)
# <ipython-input-433-3ba51b619417> in <module>
# ----> 1 y_load.set_index('datehour').asfreq('H')
# ...
# ValueError: cannot reindex from a duplicate axis
...