3. 时间特征工程
任务目标
本案例以某电商平台日度订单量数据为输入,完成两类时间特征工程:(1) 从时间戳中提取星期、月份、是否周末、是否节假日等日历特征;(2) 基于历史序列构造滞后特征与滚动统计特征(滚动均值、滚动标准差),最终输出可直接用于模型训练的增强特征表。
环境与依赖
Python 3.8+,仅需标准库 datetime、statistics 及 csv(若需读写文件)。无需第三方库,便于独立运行验证。
关键完整代码
import csv
from datetime import datetime, timedelta
from statistics import mean, stdev
# 节假日集合(示例:2023年部分中国法定节假日)
HOLIDAYS = {
datetime(2023, 1, 1), datetime(2023, 1, 2), datetime(2023, 1, 21),
datetime(2023, 1, 22), datetime(2023, 1, 23), datetime(2023, 1, 24),
datetime(2023, 1, 25), datetime(2023, 1, 26), datetime(2023, 1, 27),
datetime(2023, 4, 5), datetime(2023, 5, 1), datetime(2023, 5, 2),
datetime(2023, 5, 3), datetime(2023, 6, 22), datetime(2023, 6, 23),
datetime(2023, 6, 24), datetime(2023, 9, 29), datetime(2023, 10, 1),
datetime(2023, 10, 2), datetime(2023, 10, 3), datetime(2023, 10, 4),
datetime(2023, 10, 5), datetime(2023, 10, 6)
}
def extract_calendar_features(dt):
"""从单个时间戳提取日历特征"""
return {
'year': dt.year,
'month': dt.month,
'day': dt.day,
'day_of_week': dt.weekday(), # 0=周一, 6=周日
'is_weekend': 1 if dt.weekday() >= 5 else 0,
'is_holiday': 1 if dt.date() in {h.date() for h in HOLIDAYS} else 0
}
def build_features(dates, values, lag=3, window=7):
"""
为时间序列构造完整特征矩阵
dates: list[datetime], values: list[float], 按时间升序排列
lag: 滞后阶数, window: 滚动窗口大小
返回: (特征字典列表, 目标值列表)
"""
if len(dates) != len(values):
raise ValueError("dates 和 values 长度不一致")
if len(dates) < lag + window:
raise ValueError(f"数据量不足,至少需要 {lag + window} 条")
features_list = []
targets = []
# 从索引 lag+window-1 开始,保证每个样本都有完整的滞后与滚动窗口
for i in range(lag + window - 1, len(dates)):
feat = extract_calendar_features(dates[i])
# 滞后特征
for l in range(1, lag + 1):
feat[f'lag_{l}'] = values[i - l]
# 滚动统计特征(窗口内不含当前值)
window_vals = values[i - window:i]
feat['rolling_mean'] = round(mean(window_vals), 4)
feat['rolling_std'] = round(stdev(window_vals), 4) if len(window_vals) > 1 else 0.0
features_list.append(feat)
targets.append(values[i])
return features_list, targets
# ========== 最小可运行示例 ==========
if __name__ == '__main__':
# 构造2023年1月1日至1月31日的模拟订单数据(仅用于演示)
start = datetime(2023, 1, 1)
dates = [start + timedelta(days=i) for i in range(31)]
values = [100 + (i % 7) * 10 + (5 if dates[i].weekday() >= 5 else 0) for i in range(31)]
feats, targets = build_features(dates, values, lag=3, window=7)
print(f"共生成 {len(feats)} 个样本")
print("首个样本特征:", feats[0])
print("首个样本目标:", targets[0])
# 验证:检查特征完整性
required_keys = {'year', 'month', 'day', 'day_of_week', 'is_weekend',
'is_holiday', 'lag_1', 'lag_2', 'lag_3', 'rolling_mean', 'rolling_std'}
assert required_keys.issubset(feats[0].keys()), "特征缺失"
print("特征完整性验证通过")
运行与验证方式
- 将上述代码保存为
time_features.py,在命令行执行python time_features.py。 - 程序输出样本数量、首个样本的完整特征字典及目标值,并执行特征完整性断言。
- 通过条件:程序无异常退出,输出“特征完整性验证通过”,且首个样本特征中包含全部11个键(4个日期分量、2个布尔标志、3个滞后值、2个滚动统计量)。
关键说明
- 节假日集合仅包含2023年示例日期,实际使用时应替换为目标预测时段对应的节假日表(如使用
chinese_calendar库或自行维护)。 - 滚动统计使用不含当前值的前window个历史值计算,避免信息泄漏;滞后阶数
lag与窗口window可按需调整。 - 代码从索引
lag+window-1开始生成样本,确保每个样本都有完整的滞后窗口和滚动窗口,这是时序特征工程中防止未来信息泄漏的标准做法。