如何在Pandas中按日期列连接同/不同频率的DataFrame?
嘿,我来帮你解决Pandas里按日期连接不同DataFrame的问题,咱们针对你给出的三个场景逐一拆解,每个场景都附上可直接运行的代码和思路说明:
场景1:同频率(月度)但日期不全匹配的左连接
这个场景里两个DataFrame都是月度日期,只是slow的日期更少,咱们直接用pd.merge按date列做左连接就行,分别以fast和slow为基准:
import pandas as pd # 初始化数据 fast = pd.DataFrame({ 'date': pd.to_datetime(['2018-01', '2018-02', '2018-03', '2018-04', '2018-05', '2018-06']), 'store': ['A'] * 3 + ['B'] * 3, 'sales': [3000, 2000, 1800, 1700, 1500, 1600] }) slow = pd.DataFrame({ 'date': pd.to_datetime(['2018-01', '2018-03', '2018-06']), 'temp': [45, 55, 70] }) # 以fast为基准的左连接 alligned_left_fast = pd.merge(fast, slow, on='date', how='left') # 以slow为基准的左连接 alligned_left_slow = pd.merge(slow, fast, on='date', how='left')
思路说明:因为两个DataFrame的日期频率完全一致(都是月度),直接通过on='date'指定连接键,how='left'保留基准DataFrame的所有行,匹配不到的列会填充NaN。
场景2:同频率但日期点不对齐的左连接
这里注意你给出的unaligned_df2代码有小问题,我先修正了(pd.to_datetime不能直接传periods参数,改用pd.date_range)。这个场景是同频率但日期不是完全重合的点,咱们用pd.merge_asof做近似日期匹配:
import pandas as pd # 初始化数据 unaligned_df1 = pd.DataFrame({ 'date': pd.to_datetime(['2018-01', '2018-02', '2018-03', '2018-04', '2018-05', '2018-06']), 'store': ['A'] * 3 + ['B'] * 3, 'sales': [3000, 2000, 1800, 1700, 1500, 1600] }) # 修正后的unaligned_df2创建代码 unaligned_df2 = pd.DataFrame({ 'date': pd.date_range('2018-02-11', periods=6, freq='30D'), 'temp': [105, 95, 87, 78, 66, 55] # 补全对应6个日期的temp值 }) # merge_asof要求两个DataFrame按连接键排序 df1_sorted = unaligned_df1.sort_values('date') df2_sorted = unaligned_df2.sort_values('date') # 左连接,以df1的日期为基准,匹配最近的不大于当前日期的df2日期 Unaligned_merged_left_date_index = pd.merge_asof(df1_sorted, df2_sorted, on='date', direction='backward')
思路说明:merge_asof专门用于时间序列的近似匹配,适合同频率但日期点不对齐的场景。direction='backward'表示为每个df1的日期找最近的、不晚于它的df2日期,你也可以根据需求换成forward(找不早于的)或nearest(找最近的)。
场景3:不同频率(日度vs月度)的连接
这个场景里一个是日度数据,一个是月度数据,咱们需要先把高频的日度日期对齐到月度频率,再做连接:
import pandas as pd # 初始化数据 unaligned_fast_diff_freq = pd.DataFrame({ 'date': pd.to_datetime(['2018-01-12', '2018-02-10', '2018-02-16', '2018-04-28', '2018-04-29', '2018-06-11']), 'store': ['A'] * 3 + ['B'] * 3, 'sales': [3000, 2000, 1800, 1700, 1500, 1600] }) unaligned_slow_diff_freq = pd.DataFrame({ 'date': pd.to_datetime(['2018-04', '2018-05', '2018-01', '2018-06']), 'sales_monthly': [2700, 2500, 2600, 3300] # 重命名列避免冲突 }) # 把日度日期转成月度周期,月度日期也统一转成相同格式 unaligned_fast_diff_freq['month'] = unaligned_fast_diff_freq['date'].dt.to_period('M') unaligned_slow_diff_freq['month'] = unaligned_slow_diff_freq['date'].dt.to_period('M') # 按月度周期连接,之后删除临时列 unaligned_fast_slow = pd.merge(unaligned_fast_diff_freq, unaligned_slow_diff_freq, on='month', how='left').drop('month', axis=1)
思路说明:不同频率的日期无法直接匹配,所以我们把日度数据向下采样到月度(用dt.to_period('M')生成月度周期对象),和月度数据的日期统一格式后,再用常规的merge连接。如果不想新增临时列,也可以用dt.floor('M')把日期对齐到当月第一天,直接作为连接键。
内容的提问来源于stack exchange,提问作者coder

