【DataWhale 夏令营】AI+经济--Task3

一、时间序列挖掘任务

特征工程

特征工程是数据预处理过程的一部分,涉及从原始数据中提取和创建新特征,以提高机器学习模型的性能。特征工程的目标是通过选择和构建合适的特征,使模型能够更好地理解数据和预测目标变量。

一般而言,我们可以构造如下时间序列特征:

  • 时间戳特征:年、月、日……

  • 历史信息特征:过去n期同日期的均值、标准差……

  • 滞后特征:将数据平移n期,例如平移7期就是用上周同时间的出清价作为参考(但本案例中预测区间过长,无法用到该特征,除非使用迭代预测)

  • 滑窗特征:历史7天、14天……均值、标准差、最大值、最小值、变异系数、峰度、偏度……

  • 周期特征:将年月日等时间特征转为正余弦函数

  • 异常值特征:例如在一定滑窗下用3标准差原则发现总负荷的异常值作为特征

  • 节假日特征与外部数据:节假日与天气数据在本案例中有很大的影响

train_data["hour"] = electricity_price.index.hour
train_data["day"] = electricity_price.index.day
train_data["month"] = electricity_price.index.month
train_data["year"] = electricity_price.index.year
train_data["weekday"] = electricity_price.index.weekday
# 根据月份信息,判断是否为风季(1-5月和9-12月),创建布尔型 "is_windy_season" 列
train_data["is_windy_season"] = electricity_price.index.month.isin([1, 2, 3, 4, 5, 9, 10, 11, 12])
# 根据小时信息,判断是否为低谷时段(10-15点),创建布尔型 "is_valley" 列
train_data["is_valley"] = electricity_price.index.hour.isin([10, 11, 12, 13, 14, 15])
train_data["quarter"] = electricity_price.index.quarter
# 对时间特征进行独热编码(One-Hot Encoding),删除第一列以避免多重共线性
train_data = pd.get_dummies(
    data=train_data,        # 需要进行独热编码的 DataFrame
    columns=["hour", "day", "month", "year", "weekday"],  # 需要独热编码的列
    drop_first=True         # 删除第一列以避免多重共线性
)

基于Task2中的EDA,我们发现节假日中电力价格更容易为负值,因此我们构造典型的春节和劳动节的节假日特征。当然你也可以尝试构造其他的节假日特征(端午节、清明节、国庆节……)

def generate_holiday_dates(start_dates, duration):
    holidays = []  # 初始化一个空列表,用于存储节假日日期
    for start_date in start_dates:  # 遍历每个节假日的开始日期
        # 生成从 start_date 开始的日期范围,持续时间为 duration 天
        holidays.extend(pd.date_range(start=start_date, periods=duration).tolist())
    return holidays  # 返回所有节假日日期的列表

spring_festival_start_dates = ["2022-01-31", "2023-01-21", "2024-02-10"]
labor_start_dates = ["2022-04-30", "2023-04-29"]
spring_festivals = generate_holiday_dates(spring_festival_start_dates, 7)
labor = generate_holiday_dates(labor_start_dates, 5)

# 判断训练数据的索引是否在春节日期列表中,生成布尔型列 "is_spring_festival"
train_data["is_spring_festival"] = train_data.index.isin(spring_festivals)

# 判断训练数据的索引是否在劳动节日期列表中,生成布尔型列 "is_labor"
train_data["is_labor"] = train_data.index.isin(labor)

可以发现一段时间内,总负荷如果有下降趋势,则下一个出清价格也可能下降。因此联想到构造基于总需求的窗口特征。

在这里我们利用到了pandas非常好用的agg聚合函数,其可以将一列根据选择的函数转换为统计值(例如取一列标准差、均值),这里由于是对每个窗口agg,相当于取每个窗口的特定统计值。

在agg函数定义中,参数接受一列值(为pandas的Series),做某种计算后返回单个值。

from tqdm import tqdm  # 导入 tqdm 库用于显示进度条

# 定义滚动窗口大小的列表
window_sizes = [4, 12, 24]

# 遍历每个窗口大小
with tqdm(window_sizes) as pbar:
    for window_size in pbar:
        # 定义要应用的聚合函数列表
        functions = ["mean", "std", "min", "max", cal_range, increase_num,
                     decrease_num, increase_mean, decrease_mean, increase_std, decrease_std]

        # 遍历每个聚合函数
        for func in functions:
            # 获取函数名称,如果是字符串则直接使用,否则使用函数的 __name__ 属性
            func_name = func if type(func) == str else func.__name__

            # 生成新列名,格式为 demand_rolling_{window_size}_{func_name}
            column_name = f"demand_rolling_{window_size}_{func_name}"

            # 计算滚动窗口的聚合值,并将结果添加到 train_data 中
            train_data[column_name] = train_data["demand"].rolling(
                window=window_size,        # 滚动窗口大小
                min_periods=window_size//2,  # 最小观测值数
                closed="left"         # 滚动窗口在左侧闭合
            ).agg(func)              # 应用聚合函数

            pbar.set_postfix({"window_size": window_size, "func": func_name})

我们还可以加入一些其他的时序特征,例如demand的滞后特征,差分特征,百分比特征等。通常我们会尝试构造尽可能多的特征,随后在特征筛选中留下对结果有显著影响的特征。

# 添加新的特征列:demand_shift_1,表示将 demand 列中的值向后移动一位
train_data["demand_shift_1"] = train_data["demand"].shift(1)
# 添加新的特征列:demand_diff_1,表示 demand 列中相邻值的差
train_data["demand_diff_1"] = train_data["demand"].diff(1)
# 添加新的特征列:demand_pct_1,表示 demand 列中相邻值的百分比变化
train_data["demand_pct_1"] = train_data["demand"].pct_change(1)

二、代码运行及结果 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值