Python 在多索引中移动日期时间索引

Python 在多索引中移动日期时间索引,python,pandas,indexing,multi-index,Python,Pandas,Indexing,Multi Index,我有一个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", "2

我有一个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 ac
但当我跑步时:
y\u lag=shift\u索引(y,'datehour','H',1)
,我得到以下错误:

ValueError:级别值必须是唯一的…

(我实际上可以通过添加
verify\u integrity=False
在函数中的
.index.set_levels…
,但这(可以预见)会导致后续问题)

这是奇怪的部分。如果您运行上面的示例,但没有从csv保存/重新加载,则它可以工作。原因似乎是,我认为,
y.index.get_level_value('datehour')
在创建后立即显示
freq='H'
属性,但从csv重新加载后,
freq=None

这是有道理的,csv显然不会保存元数据。但是我发现为多索引序列设置freq属性非常困难。例如,这没有任何作用。
df.index.freq=pd.tseries.frequencies.to_offset(“H”)
。而且对我的多重索引也不起作用


因此,如果我能够设置多重索引的DateTime组件的
freq
属性,我想我可以解决这个问题。但我的最终目标是创建一个带有移位日期时间多索引组件的my
y
数据版本,比如上面的my
shift\u index
函数。由于我通过csv接收数据,“只是不保存到csv并重新加载”不是一个选项。

经过多次烦躁之后,我能够在分组数据上使用
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'))
所有这些工作都是分两部分设置索引。
用户
首先进入,以便嵌套的
日期小时
索引在其中是唯一的。一旦
datehour
索引是唯一的,就可以毫不费力地使用
asfreq

如果在非唯一索引上尝试
asfreq
,它将不起作用

y\u load.set\u index('datehour').asfreq('H'))
# ---------------------------------------------------------------------------
#ValueError回溯(最近一次调用上次)
#在
#--->1 y\U加载。设置索引('datehour')。asfreq('H'))
# ...
#ValueError:无法从重复轴重新编制索引

Wow,在groupby/apply/lambda中设置一个索引以设置频率,wild。我敢肯定,经过多次摆弄之后。我对你的发现印象深刻,我可以证实它绝对有效(+1)。希望你不介意我等一两天,看看有没有人想出一个更简单/更惯用的方法,我想这一定存在?很好。很高兴这有帮助!是的,很疯狂。熊猫是伟大的,当它做你想要的东西的时候,它从盒子里出来,但是如果它不做,它可能会变得非常尴尬。在这里为熊猫开发者发布了一个问题,我们将看看他们是否有一个更简单的方法。好问题。我有一个类似的问题,
freq
在操作后被设置为
None
——在我的例子中,当我使用
df.index=pd.MultiIndex.from_数组([qhour.index,qhour.index.year])重新编制索引时,
。我很想知道是否有更多。。。直截了当的做事方式(无意冒犯@mcskinner;)