Jes*_*her 6 python merge multi-index pandas datetimeindex
我想合并两个由time和索引的数据集id.问题是,每个数据集的时间略有不同.在一个数据集中,时间(每月)是月中,因此是每个月的第15个月.在其他数据集中,这是最后一个工作日.这应该仍然是一对一的匹配,但日期并不完全相同.
我的方法是将月中日期转换为工作日的月末日期.
数据:
dt = pd.date_range('1/1/2011','12/31/2011', freq='D')
dt = dt[dt.day == 15]
lst = [1,2,3]
idx = pd.MultiIndex.from_product([dt,lst],names=['date','id'])
df = pd.DataFrame(np.random.randn(len(idx)), index=idx)
df.head()
Run Code Online (Sandbox Code Playgroud)
输出:
0
date id
2011-01-15 1 -0.598584
2 -0.484455
3 -2.044912
2011-02-15 1 -0.017512
2 0.852843
Run Code Online (Sandbox Code Playgroud)
这就是我想要的(我删除了性能警告):
In[83]:df.index.levels[0] + BMonthEnd()
Out[83]:
DatetimeIndex(['2011-01-31', '2011-02-28', '2011-03-31', '2011-04-29',
'2011-05-31', '2011-06-30', '2011-07-29', '2011-08-31',
'2011-09-30', '2011-10-31', '2011-11-30', '2011-12-30'],
dtype='datetime64[ns]', freq='BM')
Run Code Online (Sandbox Code Playgroud)
但是,索引是不可变的,因此这不起作用:
In: df.index.levels[0] = df.index.levels[0] + BMonthEnd()
TypeError: 'FrozenList' does not support mutable operations.
Run Code Online (Sandbox Code Playgroud)
我得到的唯一解决方案是reset_index(),更改日期,然后再次set_index():
df.reset_index(inplace=True)
df['date'] = df['date'] + BMonthEnd()
df.set_index(['date','id'], inplace=True)
Run Code Online (Sandbox Code Playgroud)
这给了我想要的东西,但这是最好的方法吗?是否有set_level_values()函数(我没有在API中看到它)?
或许我采取了错误的合并方法.我可以合并的带有按键的数据集df.index.get_level_values(0).year,df.index.get_level_values(0).month并id但这似乎并没有要好得多.
您可以使用set_levels以设置多索引级别:
df.index.set_levels(df.index.levels[0] + pd.tseries.offsets.BMonthEnd(),
level='date', inplace=True)
>>> df.head()
0
date id
2011-01-31 1 -1.410646
2 0.642618
3 -0.537930
2011-02-28 1 -0.418943
2 0.983186
Run Code Online (Sandbox Code Playgroud)
你可以再次构建它:
df.index = pd.MultiIndex.from_arrays(
[
df.index.get_level_values(0) + BMonthEnd(),
df.index.get_level_values(1)
])
Run Code Online (Sandbox Code Playgroud)
set_levels隐式重建封面下的索引.如果您有两个以上的级别,此解决方案将变得不合适,因此请考虑使用set_levels简化键入.
由于您无论如何都想合并,因此您可以忘记更改索引并使用 usepandas.merge_asof()
df1
0
date id
2011-01-15 1 -0.810581
2 1.177235
3 0.083883
2011-02-15 1 1.217419
2 -0.970804
3 1.262364
2011-03-15 1 -0.026136
2 -0.036250
3 -1.103929
2011-04-15 1 -1.303298
Run Code Online (Sandbox Code Playgroud)
这是本月最后一个工作日, df2
0
date id
2011-01-31 1 -0.277675
2 0.086539
3 1.441449
2011-02-28 1 1.330212
2 -0.028398
3 -0.114297
2011-03-31 1 -0.031264
2 -0.787093
3 -0.133088
2011-04-29 1 0.938732
Run Code Online (Sandbox Code Playgroud)
使用df1左侧DataFrame,然后选择合并方向为向前,因为最后一个工作日始终在 15 号之后。您可以选择设置容差。这在您缺少右侧月份的情况下非常有用,并且如果您缺少 2 月最后一个工作日的数据,这 DataFrame将阻止您合并03-31-2011。02-15-2011
import pandas as pd
pd.merge_asof(df1.reset_index(), df2.reset_index(), by='id', on='date',
direction='forward', tolerance=pd.Timedelta(days=20)).set_index(['date', 'id'])
Run Code Online (Sandbox Code Playgroud)
结果是
0_x 0_y
date id
2011-01-15 1 -0.810581 -0.277675
2 1.177235 0.086539
3 0.083883 1.441449
2011-02-15 1 1.217419 1.330212
2 -0.970804 -0.028398
3 1.262364 -0.114297
2011-03-15 1 -0.026136 -0.031264
2 -0.036250 -0.787093
3 -1.103929 -0.133088
2011-04-15 1 -1.303298 0.938732
Run Code Online (Sandbox Code Playgroud)