电力负荷案例之解析预测特征(下)
1 课程概览
本课讲解电力负荷案例的预测特征解析(下)。包括解析时间特征、提取hour和month、添加窗口字段、获取昨日同时刻负荷等。这是特征工程在预测阶段的应用。
2 核心概念与定义
- 预测时间:
time字段,字符串格式。 - 截取hour:
time.str[11:13]。 - 截取month:
time.str[5:7]。 - 特征工程:与训练阶段一致。
- 样本数据:预测时间对应的那一行数据。
3 算法与模型详解
3.1 解析特征步骤
步骤:
- 截取预测时间的hour信息
- 截取预测时间的month信息
- 添加窗口字段(prev_1、prev_2、prev_3)
- 获取昨日同时刻负荷
- 组装特征数据
- 模型预测
3.2 截取hour信息
方法:字符串切片
代码:
pre_hour = time.str[11:13]
说明:
time:预测时间字符串[11:13]:截取第11到13位(包左不包右)- 得到hour信息
示例:
- 时间:
'2015-08-01 04:00:00' - 截取:
'04'
3.3 截取month信息
方法:字符串切片
代码:
pre_month = time.str[5:7]
说明:
time:预测时间字符串[5:7]:截取第5到7位(包左不包右)- 得到month信息
示例:
- 时间:
'2015-08-01 04:00:00' - 截取:
'08'
3.4 添加窗口字段
字段:
- prev_1:前1小时负荷
- prev_2:前2小时负荷
- prev_3:前3小时负荷
方法:从数据字典中获取
代码:
prev_1 = time_load_dict[time - 1hour]
prev_2 = time_load_dict[time - 2hour]
prev_3 = time_load_dict[time - 3hour]
3.5 获取昨日同时刻负荷
方法:从数据字典中获取
代码:
yesterday_time = time - 1day
yesterday_load = time_load_dict[yesterday_time]
3.6 特征工程一致性
重点:预测阶段的特征工程与训练阶段一致
说明:
- 顺序一致
- 方法一致
- 字段一致
4 代码示例
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import logging
import joblib
import datetime
# 解决中文乱码
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. 电力负荷预测类 ===")
class PowerLoadPredict:
"""电力负荷预测类"""
def __init__(self, log_file=None, data_source=None):
self.log_file = log_file
self.data_source = data_source
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('power_load_predict')
def build_time_load_dict(self, data):
"""建立时间-负荷字典"""
time_load_dict = dict(zip(
data['time'].dt.strftime('%Y-%m-%d %H:%M:%S'),
data['power_load']
))
return time_load_dict
def parse_time_features(self, time_str):
"""
解析时间特征
Args:
time_str: 时间字符串,如 '2024-01-15 04:00:00'
Returns:
hour: 小时
month: 月份
"""
self.logger.info(f"解析时间特征: {time_str}")
# 1. 截取hour信息
# 字符串切片 [11:13]:包左不包右
hour = time_str[11:13]
# 2. 截取month信息
# 字符串切片 [5:7]:包左不包右
month = time_str[5:7]
self.logger.info(f"hour: {hour}, month: {month}")
return hour, month
def get_window_features(self, time_str, time_load_dict):
"""
获取窗口字段
Args:
time_str: 预测时间字符串
time_load_dict: 时间-负荷字典
Returns:
prev_1: 前1小时负荷
prev_2: 前2小时负荷
prev_3: 前3小时负荷
"""
self.logger.info(f"获取窗口字段: {time_str}")
# 将字符串转为datetime
time_dt = pd.to_datetime(time_str)
# 获取前1、2、3小时的负荷
prev_1_time = (time_dt - pd.Timedelta(hours=1)).strftime('%Y-%m-%d %H:%M:%S')
prev_2_time = (time_dt - pd.Timedelta(hours=2)).strftime('%Y-%m-%d %H:%M:%S')
prev_3_time = (time_dt - pd.Timedelta(hours=3)).strftime('%Y-%m-%d %H:%M:%S')
prev_1 = time_load_dict.get(prev_1_time, 0)
prev_2 = time_load_dict.get(prev_2_time, 0)
prev_3 = time_load_dict.get(prev_3_time, 0)
self.logger.info(f"prev_1: {prev_1}, prev_2: {prev_2}, prev_3: {prev_3}")
return prev_1, prev_2, prev_3
def get_yesterday_load(self, time_str, time_load_dict):
"""
获取昨日同时刻负荷
Args:
time_str: 预测时间字符串
time_load_dict: 时间-负荷字典
Returns:
yesterday_load: 昨日同时刻负荷
"""
self.logger.info(f"获取昨日同时刻负荷: {time_str}")
# 计算昨日时间
time_dt = pd.to_datetime(time_str)
yesterday_time = (time_dt - pd.Timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')
# 从字典获取昨日负荷
yesterday_load = time_load_dict.get(yesterday_time, 0)
self.logger.info(f"yesterday_load: {yesterday_load}")
return yesterday_load
def build_feature_dict(self, time_str, time_load_dict, all_features):
"""
组装特征字典
Args:
time_str: 预测时间字符串
time_load_dict: 时间-负荷字典
all_features: 所有特征列名
Returns:
feature_dict: 特征字典
"""
self.logger.info(f"组装特征字典: {time_str}")
# 1. 解析时间特征
hour, month = self.parse_time_features(time_str)
# 2. 获取窗口字段
prev_1, prev_2, prev_3 = self.get_window_features(time_str, time_load_dict)
# 3. 获取昨日同时刻负荷
yesterday_load = self.get_yesterday_load(time_str, time_load_dict)
# 4. 组装特征字典
feature_dict = {}
# hour的One-Hot编码
for h in range(24):
col_name = f'hour_{h}'
if col_name in all_features:
feature_dict[col_name] = 1 if f'{h:02d}' == hour else 0
# month的One-Hot编码
for m in range(1, 13):
col_name = f'month_{m}'
if col_name in all_features:
feature_dict[col_name] = 1 if f'{m:02d}' == month else 0
# 窗口字段
feature_dict['prev_1'] = prev_1
feature_dict['prev_2'] = prev_2
feature_dict['prev_3'] = prev_3
# 昨日负荷
feature_dict['yesterday_load'] = yesterday_load
self.logger.info(f"特征字典大小: {len(feature_dict)}")
return feature_dict
# 4. 运行特征解析
print("\n=== 4. 运行特征解析 ===")
def run_feature_parsing():
"""运行特征解析"""
# 创建日志对象
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)
# 创建预测类
predictor = PowerLoadPredict(log_file=log_file, data_source=data)
# 1. 建立时间-负荷字典
print("--- 1. 建立时间-负荷字典 ---")
time_load_dict = predictor.build_time_load_dict(data)
print(f"字典大小: {len(time_load_dict)}")
# 2. 解析时间特征
print("\n--- 2. 解析时间特征 ---")
time_str = '2024-01-15 04:00:00'
hour, month = predictor.parse_time_features(time_str)
print(f"时间: {time_str}")
print(f"hour: {hour}")
print(f"month: {month}")
# 3. 获取窗口字段
print("\n--- 3. 获取窗口字段 ---")
prev_1, prev_2, prev_3 = predictor.get_window_features(time_str, time_load_dict)
print(f"prev_1: {prev_1:.2f}")
print(f"prev_2: {prev_2:.2f}")
print(f"prev_3: {prev_3:.2f}")
# 4. 获取昨日同时刻负荷
print("\n--- 4. 获取昨日同时刻负荷 ---")
yesterday_load = predictor.get_yesterday_load(time_str, time_load_dict)
print(f"yesterday_load: {yesterday_load:.2f}")
# 5. 组装特征字典
print("\n--- 5. 组装特征字典 ---")
# 模拟所有特征列名
all_features = []
for h in range(24):
all_features.append(f'hour_{h}')
for m in range(1, 13):
all_features.append(f'month_{m}')
all_features.extend(['prev_1', 'prev_2', 'prev_3', 'yesterday_load'])
feature_dict = predictor.build_feature_dict(time_str, time_load_dict, all_features)
print(f"特征字典大小: {len(feature_dict)}")
print(f"非零特征:")
for k, v in feature_dict.items():
if v != 0:
print(f" {k}: {v}")
run_feature_parsing()
# 5. 字符串切片详解
print("\n=== 5. 字符串切片详解 ===")
def string_slicing_explanation():
"""字符串切片详解"""
print("""
字符串切片详解:
1. 时间格式
'2024-01-15 04:00:00'
0123456789...
2. hour切片 [11:13]
位置: 11 12
内容: 0 4
结果: '04'
3. month切片 [5:7]
位置: 5 6
内容: 0 1
结果: '01'
4. 切片规则
[start:end] 包左不包右
[11:13] 取第11、12位
[5:7] 取第5、6位
5. 代码
hour = time_str[11:13]
month = time_str[5:7]
""")
string_slicing_explanation()
# 6. 特征工程一致性
print("\n=== 6. 特征工程一致性 ===")
def feature_engineering_consistency():
"""特征工程一致性"""
print("""
特征工程一致性:
1. 训练阶段特征工程
- 提取hour和month
- One-Hot编码
- 添加窗口字段
- 获取昨日负荷
2. 预测阶段特征工程
- 截取hour和month
- One-Hot编码
- 获取窗口字段
- 获取昨日负荷
3. 一致性要求
- 顺序一致
- 方法一致
- 字段一致
4. 重点
预测阶段的特征工程与训练阶段一致
""")
feature_engineering_consistency()
# 7. 完整代码
print("\n=== 7. 完整代码 ===")
def complete_code():
"""完整代码"""
print("""
def parse_time_features(self, time_str):
\"\"\"解析时间特征\"\"\"
# 截取hour
hour = time_str[11:13]
# 截取month
month = time_str[5:7]
return hour, month
def get_window_features(self, time_str, time_load_dict):
\"\"\"获取窗口字段\"\"\"
time_dt = pd.to_datetime(time_str)
prev_1_time = (time_dt - pd.Timedelta(hours=1)).strftime('%Y-%m-%d %H:%M:%S')
prev_2_time = (time_dt - pd.Timedelta(hours=2)).strftime('%Y-%m-%d %H:%M:%S')
prev_3_time = (time_dt - pd.Timedelta(hours=3)).strftime('%Y-%m-%d %H:%M:%S')
prev_1 = time_load_dict.get(prev_1_time, 0)
prev_2 = time_load_dict.get(prev_2_time, 0)
prev_3 = time_load_dict.get(prev_3_time, 0)
return prev_1, prev_2, prev_3
def get_yesterday_load(self, time_str, time_load_dict):
\"\"\"获取昨日同时刻负荷\"\"\"
time_dt = pd.to_datetime(time_str)
yesterday_time = (time_dt - pd.Timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')
yesterday_load = time_load_dict.get(yesterday_time, 0)
return yesterday_load
""")
complete_code()
# 8. 总结
def parsing_summary():
"""解析总结"""
print("=" * 50)
print("解析预测特征(下)总结")
print("=" * 50)
print("\n1. 时间特征")
print(" hour: time_str[11:13]")
print(" month: time_str[5:7]")
print("\n2. 窗口字段")
print(" prev_1: 前1小时")
print(" prev_2: 前2小时")
print(" prev_3: 前3小时")
print("\n3. 昨日负荷")
print(" yesterday_load: 昨日同时刻")
print("\n4. 一致性")
print(" 与训练阶段特征工程一致")
print("\n" + "=" * 50)
print("解析预测特征(下)完成!")
print("=" * 50)
parsing_summary()
输出示例:
=== 4. 运行特征解析 ===
--- 2. 解析时间特征 ---
时间: 2024-01-15 04:00:00
hour: 04
month: 01
--- 3. 获取窗口字段 ---
prev_1: 712.34
prev_2: 689.12
prev_3: 654.56
--- 4. 获取昨日同时刻负荷 ---
yesterday_load: 698.45
5 重难点与易错提醒
- ❗重点:字符串切片
[11:13]获取hour。 - ❗重点:字符串切片
[5:7]获取month。 - ❗重点:预测阶段特征工程与训练阶段一致。
- ❗重点:窗口字段从数据字典获取。
- ⚠️易错:切片位置错误。
- ⚠️易错:特征顺序不一致。
- 💡深入理解:特征工程一致性是模型预测准确的关键。
6 课堂问答精选
Q: 如何截取hour和month?
A: 方法:字符串切片
- hour:
time_str[11:13] - month:
time_str[5:7]
示例:
- 时间:
'2024-01-15 04:00:00' - hour:
'04' - month:
'01'
Q: 为什么预测阶段特征工程要与训练阶段一致?
A: 原因:
- 模型训练时使用特定特征
- 预测时必须使用相同特征
- 顺序、方法、字段都要一致
- 否则预测结果不准确
7 本课小结
- hour:
time_str[11:13]。 - month:
time_str[5:7]。 - 窗口:prev_1、prev_2、prev_3。
- 昨日:yesterday_load。
- 一致:与训练阶段特征工程一致。
8 延伸思考与实践
- 实践:运行特征解析代码。
- 预习:结果展示。
- 思考:如何保证特征工程一致性?