电力负荷案例之结果展示
1 课程概览
本课讲解电力负荷案例的结果展示。包括保存预测结果、计算评估指标、绘制折线图等。这是整个案例的最后一步。
2 核心概念与定义
- evaluate_list:保存预测结果的列表。
- evaluate_df:结果转成DataFrame。
- 真实负荷:从
time_load_dict获取。 - 预测负荷:模型预测结果。
- 折线图:可视化预测结果。
3 算法与模型详解
3.1 结果展示步骤
步骤:
- 定义
evaluate_list保存预测结果 - 获取真实负荷
- 获取预测负荷
- 保存到
evaluate_list - 转成DataFrame
- 计算评估指标
- 绘制折线图
3.2 定义evaluate_list
作用:保存预测结果,方便后续评价
代码:
evaluate_list = []
3.3 获取真实负荷
方法:从time_load_dict获取
代码:
true_value = pp.time_load_dict.get(pre_time, 500)
说明:
pp.time_load_dict:时间-负荷字典pre_time:预测时间500:默认值
3.4 获取预测负荷
方法:模型预测
代码:
predicted_value = model.predict(X)[0]
说明:
model.predict(X):返回长度为1的列表[0]:获取第一个元素
3.5 保存到evaluate_list
代码:
evaluate_list.append({
'预测时间': pre_time,
'真实负荷': true_value,
'预测负荷': predicted_value
})
3.6 转成DataFrame
代码:
evaluate_df = pd.DataFrame(
evaluate_list,
columns=['预测时间', '真实负荷', '预测负荷']
)
3.7 绘制折线图
代码:
plt.figure(figsize=(14, 6))
plt.plot(evaluate_df['预测时间'], evaluate_df['真实负荷'], label='真实负荷')
plt.plot(evaluate_df['预测时间'], evaluate_df['预测负荷'], label='预测负荷')
plt.legend()
plt.show()
4 代码示例
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import logging
import joblib
import datetime
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, mean_squared_error
# 解决中文乱码
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 1. 日志工具类
print("=== 1. 日志工具类 ===")
class LogUtils:
"""日志工具类"""
def __init__(self, root_path='./', log_name='project', level=logging.INFO):
self.logger = logging.getLogger(log_name)
self.logger.setLevel(level)
if not self.logger.handlers:
log_dir = os.path.join(root_path, 'log')
os.makedirs(log_dir, exist_ok=True)
log_file = os.path.join(log_dir, f'{log_name}.log')
file_handler = logging.FileHandler(log_file, encoding='utf-8')
file_handler.setLevel(level)
console_handler = logging.StreamHandler()
console_handler.setLevel(level)
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)
self.logger.addHandler(file_handler)
self.logger.addHandler(console_handler)
def get_log(self):
return self.logger
# 2. 生成模拟数据
print("\n=== 2. 生成模拟数据 ===")
def generate_power_load_data(n_days=30):
"""生成电力负荷数据"""
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=n_days*24, freq='h')
power_load = []
for date in dates:
hour = date.hour
dayofweek = date.dayofweek
month = date.month
if 0 <= hour < 6:
base_load = 500
elif 6 <= hour < 9:
base_load = 800
elif 9 <= hour < 17:
base_load = 1000
elif 17 <= hour < 21:
base_load = 1200
else:
base_load = 700
if dayofweek >= 5:
base_load *= 0.8
if month in [12, 1, 2]:
base_load *= 1.2
elif month in [6, 7, 8]:
base_load *= 1.1
load = base_load + np.random.normal(0, 50)
power_load.append(max(100, load))
data = pd.DataFrame({
'time': dates,
'power_load': power_load
})
return data
# 3. 特征工程
print("\n=== 3. 特征工程 ===")
def feature_engineering(data, logger=None):
"""特征工程"""
feature_data = data.copy()
# 1. 提取hour和month
feature_data['hour'] = feature_data['time'].dt.hour
feature_data['month'] = feature_data['time'].dt.month
# 2. One-Hot编码
feature_data = pd.get_dummies(feature_data, columns=['hour', 'month'])
# 3. 添加窗口字段
feature_data['prev_1'] = feature_data['power_load'].shift(1)
feature_data['prev_2'] = feature_data['power_load'].shift(2)
feature_data['prev_3'] = feature_data['power_load'].shift(3)
# 4. 获取昨日同时刻负荷
feature_data['yesterday_time'] = feature_data['time'].apply(
lambda x: (pd.to_datetime(x) - pd.Timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')
)
time_load_map = dict(zip(
feature_data['time'].dt.strftime('%Y-%m-%d %H:%M:%S'),
feature_data['power_load']
))
feature_data['yesterday_load'] = feature_data['yesterday_time'].map(time_load_map)
# 5. 删除NaN
feature_data = feature_data.dropna().reset_index(drop=True)
return feature_data
# 4. 训练模型
print("\n=== 4. 训练模型 ===")
def train_model(data, logger=None):
"""训练模型"""
# 特征工程
feature_data = feature_engineering(data, logger)
# 获取特征列名
exclude_columns = ['time', 'power_load', 'yesterday_time']
features = [col for col in feature_data.columns if col not in exclude_columns]
# 数据集切分
X = feature_data[features]
y = feature_data['power_load']
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, shuffle=False
)
# 训练模型
model = GradientBoostingRegressor(
n_estimators=100,
max_depth=6,
learning_rate=0.1,
random_state=42
)
model.fit(X_train, y_train)
return model, features
# 5. 结果展示类
print("\n=== 5. 结果展示类 ===")
class ResultDisplay:
"""结果展示类"""
def __init__(self, log_file=None):
if log_file:
log_name = os.path.splitext(os.path.basename(log_file))[0]
log_dir = os.path.dirname(log_file)
self.log_utils = LogUtils(
root_path=log_dir if log_dir else './',
log_name=log_name
)
self.logger = self.log_utils.get_log()
else:
self.logger = logging.getLogger('result_display')
def predict_and_evaluate(self, data, model, features, predict_start_time):
"""
预测并评估
Args:
data: 完整数据
model: 训练好的模型
features: 特征列名
predict_start_time: 预测开始时间
Returns:
evaluate_df: 评估结果DataFrame
"""
self.logger.info(f"开始预测: {predict_start_time}以后")
# 1. 定义evaluate_list保存预测结果
evaluate_list = []
# 2. 建立时间-负荷字典
time_load_dict = dict(zip(
data['time'].dt.strftime('%Y-%m-%d %H:%M:%S'),
data['power_load']
))
# 3. 筛选预测时间
predict_times = data[data['time'] >= predict_start_time]['time'].values
self.logger.info(f"预测时间数量: {len(predict_times)}")
# 4. 循环预测
for pre_time in predict_times:
# 4.1 获取真实负荷
pre_time_str = pd.Timestamp(pre_time).strftime('%Y-%m-%d %H:%M:%S')
true_value = time_load_dict.get(pre_time_str, 500)
# 4.2 掩盖数据
masked_data = data[data['time'] < pre_time].copy()
# 4.3 特征工程
feature_data = feature_engineering(masked_data)
# 4.4 获取最后一行数据
if len(feature_data) == 0:
continue
last_data = feature_data.iloc[-1:]
X = last_data[features]
# 4.5 预测
predicted_value = model.predict(X)[0]
# 4.6 保存到evaluate_list
evaluate_list.append({
'预测时间': pre_time_str,
'真实负荷': true_value,
'预测负荷': predicted_value
})
# 5. 转成DataFrame
evaluate_df = pd.DataFrame(
evaluate_list,
columns=['预测时间', '真实负荷', '预测负荷']
)
self.logger.info(f"预测完成,结果数量: {len(evaluate_df)}")
return evaluate_df
def calculate_metrics(self, evaluate_df):
"""计算评估指标"""
mae = mean_absolute_error(evaluate_df['真实负荷'], evaluate_df['预测负荷'])
mse = mean_squared_error(evaluate_df['真实负荷'], evaluate_df['预测负荷'])
rmse = np.sqrt(mse)
self.logger.info(f"MAE: {mae:.4f}")
self.logger.info(f"MSE: {mse:.4f}")
self.logger.info(f"RMSE: {rmse:.4f}")
print(f"\n评估指标:")
print(f" MAE: {mae:.4f}")
print(f" MSE: {mse:.4f}")
print(f" RMSE: {rmse:.4f}")
return mae, mse, rmse
def plot_results(self, evaluate_df, save_path='prediction_result.png'):
"""绘制折线图"""
self.logger.info("绘制折线图")
plt.figure(figsize=(14, 6))
plt.plot(range(len(evaluate_df)), evaluate_df['真实负荷'],
label='真实负荷', marker='o', alpha=0.7)
plt.plot(range(len(evaluate_df)), evaluate_df['预测负荷'],
label='预测负荷', marker='x', alpha=0.7)
plt.xlabel('时间步')
plt.ylabel('电力负荷')
plt.title('电力负荷预测结果')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig(save_path, dpi=100)
plt.show()
self.logger.info(f"折线图已保存: {save_path}")
def save_results(self, evaluate_df, save_path='prediction_results.csv'):
"""保存结果到CSV"""
evaluate_df.to_csv(save_path, index=False, encoding='utf-8-sig')
self.logger.info(f"结果已保存: {save_path}")
print(f"结果已保存: {save_path}")
# 6. 运行结果展示
print("\n=== 6. 运行结果展示 ===")
def run_result_display():
"""运行结果展示"""
# 创建日志对象
log_time = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
log_file = f'log/predict_{log_time}.log'
# 生成数据
data = generate_power_load_data(n_days=30)
# 训练模型
model, features = train_model(data)
# 创建结果展示对象
display = ResultDisplay(log_file=log_file)
# 预测并评估
predict_start_time = pd.Timestamp('2024-01-29')
evaluate_df = display.predict_and_evaluate(
data, model, features, predict_start_time
)
# 计算评估指标
mae, mse, rmse = display.calculate_metrics(evaluate_df)
# 绘制折线图
display.plot_results(evaluate_df)
# 保存结果
display.save_results(evaluate_df)
# 显示前10条结果
print("\n前10条预测结果:")
print(evaluate_df.head(10))
return evaluate_df
evaluate_df = run_result_display()
# 7. evaluate_list详解
print("\n=== 7. evaluate_list详解 ===")
def evaluate_list_explanation():
"""evaluate_list详解"""
print("""
evaluate_list详解:
1. 作用
- 保存预测结果
- 方便后续评价
2. 结构
evaluate_list = [
{'预测时间': '2024-01-29 00:00:00', '真实负荷': 524.56, '预测负荷': 530.12},
{'预测时间': '2024-01-29 01:00:00', '真实负荷': 489.12, '预测负荷': 495.34},
...
]
3. 添加结果
evaluate_list.append({
'预测时间': pre_time,
'真实负荷': true_value,
'预测负荷': predicted_value
})
4. 转成DataFrame
evaluate_df = pd.DataFrame(
evaluate_list,
columns=['预测时间', '真实负荷', '预测负荷']
)
""")
evaluate_list_explanation()
# 8. 预测负荷获取
print("\n=== 8. 预测负荷获取 ===")
def predicted_value_explanation():
"""预测负荷获取详解"""
print("""
预测负荷获取详解:
1. 模型预测
predicted_value = model.predict(X)[0]
2. 说明
- model.predict(X) 返回长度为1的列表
- [0] 获取第一个元素
- 不加[0]就是列表,不是数值
3. 代码
# 错误(返回列表)
predicted_value = model.predict(X)
# 正确(返回数值)
predicted_value = model.predict(X)[0]
""")
predicted_value_explanation()
# 9. 完整代码
print("\n=== 9. 完整代码 ===")
def complete_code():
"""完整代码"""
print("""
# 1. 定义evaluate_list
evaluate_list = []
# 2. 循环预测
for pre_time in pre_times:
# 获取真实负荷
true_value = pp.time_load_dict.get(pre_time, 500)
# 掩盖数据
masked_data = data[data['time'] < pre_time]
# 特征工程
feature_data = feature_engineering(masked_data)
# 预测
X = feature_data.iloc[-1:][features]
predicted_value = model.predict(X)[0]
# 保存到evaluate_list
evaluate_list.append({
'预测时间': pre_time,
'真实负荷': true_value,
'预测负荷': predicted_value
})
# 3. 转成DataFrame
evaluate_df = pd.DataFrame(
evaluate_list,
columns=['预测时间', '真实负荷', '预测负荷']
)
# 4. 计算评估指标
mae = mean_absolute_error(evaluate_df['真实负荷'], evaluate_df['预测负荷'])
mse = mean_squared_error(evaluate_df['真实负荷'], evaluate_df['预测负荷'])
rmse = np.sqrt(mse)
# 5. 绘制折线图
plt.figure(figsize=(14, 6))
plt.plot(evaluate_df['预测时间'], evaluate_df['真实负荷'], label='真实负荷')
plt.plot(evaluate_df['预测时间'], evaluate_df['预测负荷'], label='预测负荷')
plt.legend()
plt.show()
""")
complete_code()
# 10. 总结
def result_summary():
"""结果展示总结"""
print("=" * 50)
print("结果展示总结")
print("=" * 50)
print("\n1. evaluate_list")
print(" 保存预测结果")
print("\n2. 真实负荷")
print(" 从time_load_dict获取")
print("\n3. 预测负荷")
print(" model.predict(X)[0]")
print("\n4. DataFrame")
print(" 转成DataFrame方便分析")
print("\n5. 评估指标")
print(" MAE、MSE、RMSE")
print("\n6. 折线图")
print(" 可视化预测结果")
print("\n" + "=" * 50)
print("结果展示完成!")
print("=" * 50)
result_summary()
输出示例:
=== 6. 运行结果展示 ===
评估指标:
MAE: 52.3456
MSE: 4567.8901
RMSE: 67.5678
结果已保存: prediction_results.csv
前10条预测结果:
预测时间 真实负荷 预测负荷
0 2024-01-29 00:00:00 524.56 530.12
1 2024-01-29 01:00:00 489.12 495.34
...
5 重难点与易错提醒
- ❗重点:
evaluate_list保存预测结果。 - ❗重点:真实负荷从
time_load_dict获取。 - ❗重点:预测负荷用
model.predict(X)[0]。 - ❗重点:转成DataFrame方便分析。
- ⚠️易错:
model.predict(X)返回列表,要加[0]。 - ⚠️易错:忘记保存结果到CSV。
- 💡深入理解:结果展示是案例的最后一步。
6 课堂问答精选
Q: 为什么model.predict(X)要加[0]?
A: 原因:
model.predict(X)返回长度为1的列表- 不加
[0]就是列表,不是数值 - 加
[0]获取第一个元素(数值)
Q: 如何获取真实负荷?
A: 方法:从time_load_dict获取
true_value = pp.time_load_dict.get(pre_time, 500)
pp.time_load_dict:时间-负荷字典pre_time:预测时间500:默认值
7 本课小结
- 列表:
evaluate_list保存结果。 - 真实:从
time_load_dict获取。 - 预测:
model.predict(X)[0]。 - DataFrame:转成DataFrame分析。
- 指标:MAE、MSE、RMSE。
- 折线图:可视化结果。
8 延伸思考与实践
- 实践:运行结果展示代码。
- 预习:扩展思路。
- 思考:如何提高预测精度?