基于Date和Hour列在Pandas中实现数据列小时偏移
解决方案:手动实现小时偏移列生成
针对你的需求,我们可以通过计算偏移后的具体日期+小时,再用字典映射匹配值的方式实现,完全不用依赖时间序列的shift方法,代码简单易懂,适合新手:
步骤1:构造示例数据(如果已有数据可跳过)
先把你提供的示例DataFrame用代码还原出来:
import pandas as pd # 构造目标格式的示例DataFrame df = pd.DataFrame({ 'ID': [2]*6, 'Date': pd.to_datetime(['2022-01-01']*6), # 确保是datetime64格式 'Hour': [1,2,3,4,5,6], 'A': [100,200,300,400,500,600] })
步骤2:计算偏移后的日期和小时
我们先算出每一行对应的t+1(向前1小时)和t-1(向后1小时)的具体日期和小时,跨天的情况会自动处理(比如1月1日23点的t+1就是1月2日1点):
n = 1 # 要偏移的小时数,可根据需求修改 # 计算t+1的完整时间,再拆分出日期和小时 df['t_plus_1_datetime'] = df['Date'] + pd.Timedelta(hours=n) df['t_plus_1_Date'] = df['t_plus_1_datetime'].dt.date df['t_plus_1_Hour'] = df['t_plus_1_datetime'].dt.hour # 计算t-1的完整时间,再拆分出日期和小时 df['t_minus_1_datetime'] = df['Date'] - pd.Timedelta(hours=n) df['t_minus_1_Date'] = df['t_minus_1_datetime'].dt.date df['t_minus_1_Hour'] = df['t_minus_1_datetime'].dt.hour
步骤3:创建值映射字典
把原数据的(Date, Hour)作为键,A的值作为值,做成一个字典,方便快速查找偏移后对应的值:
a_map = df.set_index(['Date', 'Hour'])['A'].to_dict()
步骤4:生成偏移列并填充缺失值
通过apply遍历每一行,用字典的get方法取值——如果偏移后的(Date, Hour)在原数据中不存在,就返回0填充:
# 生成"A t+1"列 df['A t+1'] = df.apply( lambda row: a_map.get((pd.to_datetime(row['t_plus_1_Date']), row['t_plus_1_Hour']), 0), axis=1 ) # 生成"A t-1"列 df['A t-1'] = df.apply( lambda row: a_map.get((pd.to_datetime(row['t_minus_1_Date']), row['t_minus_1_Hour']), 0), axis=1 )
步骤5:清理结果
删掉中间生成的辅助列,得到最终的目标DataFrame:
# 保留需要的列 result_df = df[['ID', 'Date', 'Hour', 'A', 'A t+1', 'A t-1']] print(result_df)
运行后输出的结果如下:
| ID | Date | Hour | A | A t+1 | A t-1 |
|---|---|---|---|---|---|
| 2 | 2022-01-01 | 1 | 100 | 200 | 0 |
| 2 | 2022-01-01 | 2 | 200 | 300 | 100 |
| 2 | 2022-01-01 | 3 | 300 | 400 | 200 |
| 2 | 2022-01-01 | 4 | 400 | 500 | 300 |
| 2 | 2022-01-01 | 5 | 500 | 600 | 400 |
| 2 | 2022-01-01 | 6 | 600 | 0 | 500 |
扩展:多列偏移处理
如果你的DataFrame还有其他需要偏移的列(比如B、C),可以用循环批量处理:
# 假设要偏移的列是A、B、C cols_to_shift = ['A', 'B', 'C'] # 为每个列创建映射字典 col_maps = {col: df.set_index(['Date', 'Hour'])[col].to_dict() for col in cols_to_shift} # 循环生成每个列的偏移列 for col in cols_to_shift: df[f'{col} t+1'] = df.apply( lambda row: col_maps[col].get((pd.to_datetime(row['t_plus_1_Date']), row['t_plus_1_Hour']), 0), axis=1 ) df[f'{col} t-1'] = df.apply( lambda row: col_maps[col].get((pd.to_datetime(row['t_minus_1_Date']), row['t_minus_1_Hour']), 0), axis=1 )
内容的提问来源于stack exchange,提问作者Shivam Bindal
相关产品推荐
相关产品推荐

