电力负荷预测案例:XGBOOST——模型训练
本章会介绍如何使用xgboost模型对每个时间段的电力负荷进行预测,本章是模型训练部分。
该案例重点在与特征工程,即如何根据原来的数据去创造不同的特征,根据这些特征进行预测
加载相关的库
import os
import pandas as pd
import matplotlib.pyplot as plt
import datetime
from matplotlib import rcParams
from utils.log import Logger
from utils.common import data_preprocessing, mean_absolute_percentage_error
from xgboost import XGBRegressor
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import mean_squared_error, mean_absolute_error, root_mean_squared_error
import joblib
rcParams['font.sans-serif'] = ['Microsoft YaHei']
一、定义电力负荷模型类,配置日志,获取数据源
在这里,data_preprocessing是自己写的一个脚本,对数据进行获取,排序与去重。
class PowerLoadModel:
#1. 初始化数字信息
def __init__(self):
# 1.2 拼接日志文件名
logfile_name = 'train' + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
# 1.3 创建日志对象
self.logfile = Logger('../', logfile_name).get_logger()
# 测试写一条日志
self.logfile.info('开始创建 电力负荷模型类的对象了')
# 1.4 获取数据源
self.data_source = data_preprocessing('../data/train.csv')
二、查看数据的整体分布情况
def ana_data(data): #analysis 分析
# 0 为了防止会修改原数据,我们做一次拷贝
ana_data = data.copy()
# 1.查看数据的整体情况
ana_data.info()
# 2.负荷整体的分布情况,直方图
# 2.1 创建画布
fig = plt.figure(figsize=(20,40))
# 2.2 添加子图,画出每个小时对应的平均负荷
ax1 = fig.add_subplot(411)
ax1.hist(ana_data['power_load'],bins=100) # 负荷,直方图,100个区间
ax1.set_title('负荷整体分布情况')
ax1.set_xlabel('负荷')
# 3.各个小时的平均负荷趋势,看一下负荷再一天中的变化情况
# 3.1 新增一列,充当小时
ana_data['hour'] = ana_data['time'].str[11:13]
# print(ana_data['hour'])
# 3.2 根据小时分组,计算平均值
hour_load_mean = ana_data.groupby('hour',as_index = False)['power_load'].mean()
# 3.3 画出折线图
ax2 = fig.add_subplot(412)
ax2.plot(hour_load_mean['hour'],hour_load_mean['power_load'])
ax2.set_title('各个小时的平均负荷趋势')
ax2.set_xlabel('小时')
# 4. 各个月份的平均负荷趋势,看一下负荷在一年中的变化情况
# 4.1 新增一列,充当月份
ana_data['month'] = ana_data['time'].str[5:7]
print(ana_data['month'])
# 4.2 根据月份分组,计算平均值
month_load_mean = ana_data.groupby('month',as_index = False)['power_load'].mean()
print(month_load_mean)
# 4.3 画出折线图
ax3 = fig.add_subplot(413)
ax3.plot(month_load_mean['month'],month_load_mean['power_load']) # X轴:月份,Y轴:平均负荷
ax3.set_title('各个月份的平均负荷趋势')
ax3.set_xlabel('月份')
plt.savefig('../data/fig/负荷整体分布情况.png')
# 5. 工作日与周末的平均负荷情况,看一下工作日负荷与周末的负荷是否有区别
ana_data['weekday'] = ana_data['time'].apply(lambda x: pd.to_datetime(x).weekday())
# .apply(函数):遍历该列里每一个元素,把每个元素依次传给 lambda x 里的 x,执行函数后,把所有返回值拼成一个新 Series,赋值给新列weekday
ana_data['is_holiday'] = ana_data['weekday'].apply(lambda x: 1 if x in [5,6] else 0)
work_load_mean = ana_data[ana_data['is_holiday'] == 0].power_load.mean()
holiday_load_mean = ana_data[ana_data['is_holiday'] == 1].power_load.mean()
ax4 = fig.add_subplot(414)
ax4.bar(x=['工作日','周末'],height=[work_load_mean,holiday_load_mean])
ax4.set_title('工作日与周末平均负荷情况')
ax4.set_xlabel('类别')
plt.show()
三、特征工程(重点)
def feature_engineering(data,logger):
# 先拷贝数据
feature_data = data.copy()
# 1.提取出时间特征:小时、月份
feature_data['hour'] = feature_data['time'].str[11:13]
feature_data['month'] = feature_data['time'].str[5:7]
# 热编码
hour_month_data = pd.get_dummies(feature_data[['hour','month']])
feature_data = pd.concat([feature_data,hour_month_data],axis=1)
# print(feature_data.head(10))
# print(feature_data.info())
# 2. 提取出相近时间窗口中的负荷特征,step大小窗口的负荷
# 2.1 获取上1个小时的负荷
load_1h_data = feature_data['power_load'].shift(1) #shift(1):整体向下偏移 1 行,第一行变为NA
# 2.2 获取上2、3个小时的负荷
load_2h_data = feature_data['power_load'].shift(2)
load_3h_data = feature_data['power_load'].shift(3)
# 2.3 把前3个小时的负荷拼接在一起
load_shift_df = pd.concat([load_1h_data,load_2h_data,load_3h_data],axis=1)
# 2.4 修改列名
load_shift_df.columns = ['前1小时','前2小时','前3小时']
# 2.5 把列名拼接在一起
feature_data = pd.concat([feature_data,load_shift_df],axis=1)
# print(feature_data.info())
# 3.提取出昨日同时刻负荷特征
# 3.1 给特征新增一列列名,yesterday_time
feature_data['yesterday_time'] = feature_data['time'].apply(lambda x:(pd.to_datetime(x) - datetime.timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S'))
# print(feature_data.head(30))
# 3.2 我们把所有的日期和负荷拼接成字典,方便查找;key:时间。value:负荷
# 格式:{'2013-09-02 00:00:00':750.75,'2013-09-02 01:00:00'}
# 将时间列设为行索引后提取负荷列生成 Series,再以时间为键、负荷值为值转换成字典。
time_load_dict = feature_data.set_index('time')['power_load'].to_dict()
# print(time_load_dict)
# 3.3 新增一列 yesterday_load,表示:昨天相同时刻的负荷
# time_load_dict.get(x):去提前建好的时间 - 负荷字典里,用x作为键,查找昨天这个时间对应的用电负荷值;
feature_data['yesterday_load'] = feature_data['yesterday_time'].apply(lambda x: time_load_dict.get(x))
# print(feature_data.head(30))
# feature_data.info()
# 4.剔除出现空值的样本
fearture_data = feature_data.dropna()
# 5.整理时间特征,并返回
feature_columns = list(hour_month_data.columns) + list(load_shift_df.columns) + ['yesterday_load']
# print(feature_columns):['hour_00', 'hour_01', 'hour_02', 'hour_03', 'hour_04', 'hour_05', 'hour_06', 'hour_07', 'hour_08', 'hour_09', 'hour_10', 'hour_11', 'hour_12', 'hour_13', 'hour_14', 'hour_15', 'hour_16', 'hour_17', 'hour_18', 'hour_19', 'hour_20', 'hour_21', 'hour_22', 'hour_23', 'month_01', 'month_02', 'month_03', 'month_04', 'month_05', 'month_06', 'month_07', 'month_08', 'month_09', 'month_10', 'month_11', 'month_12', '前1小时', '前2小时', '前3小时', 'yesterday_load']
# 6. 返回结果
return fearture_data, feature_columns
四、模型训练,评估,保存
def model_train(data,features,logger):
# 1.数据集切分
x = data[features]
y = data['power_load']
# print(x.shape,y.shape)
# print(x.head())
# print(y.head())
x_train, x_test, y_train, y_test = train_test_split(x,y,test_size=0.2,random_state=23)
# 2.网格搜索与交叉验证
logger.info('----------网格搜索与交叉验证 寻找最优超参数--------------')
logger.info(f'开始时间:{datetime.datetime.now()}')
# 2.1 定义参数字典
param_dict = {
'n_estimators': [50,100,150,200],
'max_depth': [3,5,6,7],
'learning_rate': [0.01,0.1],
}
# 2.2 创建XGboost 模型的对象
xgb_model = XGBRegressor()
# 2.3 创造网格搜索对象
gs = GridSearchCV(xgb_model,param_grid=param_dict,cv=5)
# 2.4 模型训练
gs.fit(x_train,y_train)
# 2.5 打印最优参数组合
logger.info(f'最优参数组合:{gs.best_params_}')
logger.info(f'结束时间:{datetime.datetime.now()}')
# 3. 模型实例化
estimator = XGBRegressor(n_estimators=gs.best_params_['n_estimators'],max_depth=gs.best_params_['max_depth'],learning_rate=gs.best_params_['learning_rate'])
# 4. 模型训练
estimator.fit(x_train,y_train)
y_pred = estimator.predict(x_test)
# 5. 模型评价
print(f'均方误差:{mean_squared_error(y_test,y_pred)}')
print(f'均方根误差:{root_mean_squared_error(y_test,y_pred)}')
print(f'平均绝对误差:{mean_absolute_error(y_test,y_pred)}')
print(f'平均绝对百分比误差:{mean_absolute_percentage_error(y_test,y_pred)}')
# 6. 模型保存
joblib.dump(estimator,'../model/xgb_260630.pkl')
logger.info(f'模型保存成功,保存路径为:{os.path.abspath("../model/xgb_260630.pkl")}')
五、测试
if __name__ == '__main__':
# 5.1 创建电力负荷模型类的对象
pm = PowerLoadModel()
# 5.2 打印数据源
# print(pm.data_source)
# # 5.3 查看数据分布
# ana_data(pm.data_source)
# 4.4 特征工程
feature_data,feature_columns = feature_engineering(pm.data_source,pm.logfile)
# 5.5 模型训练
# 参1:处理后的全部数据集;参2:特征名称列表;参3:日志对象
model_train(feature_data,feature_columns,pm.logfile)

浙公网安备 33010602011771号