电力负荷案例之特征工程-添加小时和月份字段
1 课程概览
本课讲解电力负荷案例的特征工程第一步:添加小时和月份字段。包括提取特征、One-Hot编码等。这是特征工程的重点内容。
2 核心概念与定义
- 特征工程:
feature_engineering,重点内容。 - 小时特征:从时间提取小时。
- 月份特征:从时间提取月份。
- One-Hot编码:
pd.get_dummies(),热编码处理。 - 宽表:一列特征转成多列特征。
3 算法与模型详解
3.1 特征工程概述
函数:feature_engineering(data, logger)
参数:
data:数据源(pm.data_source)logger:日志对象(pm.log_file)
返回:处理后的特征数据和标签
重点:特征工程是项目重点
3.2 影响权重分析
结论:
- 小时:影响权重较大
- 月份:影响权重较大
- 工作日/周末:影响权重较小
决策:采纳小时和月份作为分析字段
3.3 提取小时和月份
步骤:
- 拷贝数据(防止修改原数据)
- 提取hour特征
- 提取month特征
代码:
feature_data = data.copy()
feature_data['hour'] = feature_data['time'].str[11:13]
feature_data['month'] = feature_data['time'].str[5:7]
字符串切片说明:
[11:13]:包左不包右,提取小时[5:7]:包左不包右,提取月份
3.4 One-Hot编码
原因:
- hour有24个值
- month有12个值
- 需要转成One-Hot编码
方法:pd.get_dummies()
代码:
feature_data = pd.get_dummies(feature_data, columns=['hour', 'month'])
说明:
columns:要处理的列- 自动生成新的列
- 原列被替换
3.5 查看处理结果
方法:
print(feature_data.head(10))
print(feature_data.info())
4 代码示例
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import logging
# 解决中文乱码
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
})
# 将time转成字符串格式(模拟原始数据)
data['time'] = data['time'].dt.strftime('%Y-%m-%d %H:%M:%S')
return data
data = generate_power_load_data(n_days=30)
print(f"数据形状: {data.shape}")
print(f"数据前5行:")
print(data.head())
# 3. 特征工程函数
print("\n=== 3. 特征工程函数 ===")
def feature_engineering(data, logger=None):
"""
特征工程
Args:
data: 数据源
logger: 日志对象
Returns:
feature_data: 特征数据
target: 标签数据
"""
if logger:
logger.info("开始特征工程")
# 1. 拷贝数据(防止修改原数据)
feature_data = data.copy()
# 2. 提取hour特征
# 字符串切片 [11:13]:包左不包右
feature_data['hour'] = feature_data['time'].str[11:13]
# 3. 提取month特征
# 字符串切片 [5:7]:包左不包右
feature_data['month'] = feature_data['time'].str[5:7]
if logger:
logger.info(f"提取hour和month特征完成")
print("提取hour和month后:")
print(feature_data[['time', 'power_load', 'hour', 'month']].head(10))
# 4. One-Hot编码处理hour和month
feature_data = pd.get_dummies(feature_data, columns=['hour', 'month'])
if logger:
logger.info(f"One-Hot编码完成,特征数: {feature_data.shape[1]}")
print(f"\nOne-Hot编码后数据形状: {feature_data.shape}")
print(f"所有列名: {list(feature_data.columns)}")
return feature_data
# 4. 调用特征工程
print("\n=== 4. 调用特征工程 ===")
# 创建日志对象
log_utils = LogUtils(root_path='./', log_name='feature_engineering')
logger = log_utils.get_log()
# 调用特征工程
feature_data = feature_engineering(data, logger)
# 5. 查看处理结果
print("\n=== 5. 查看处理结果 ===")
def view_results(feature_data):
"""查看处理结果"""
print(f"处理后数据形状: {feature_data.shape}")
print(f"\n数据类型:")
print(feature_data.dtypes)
print(f"\n前5行数据:")
print(feature_data.head())
view_results(feature_data)
# 6. 字符串切片详解
print("\n=== 6. 字符串切片详解 ===")
def string_slicing_explanation():
"""字符串切片详解"""
print("""
字符串切片详解:
时间格式: '2024-01-15 14:30:00'
索引: 0123456789...
提取小时 [11:13]:
- 索引: 0 1 2 3 4 5 6 7 8 9 10 11 12
- 字符: 2 0 2 4 - 0 1 - 1 5 ' ' 1 4
- [11:13] 包左不包右 → '14'
提取月份 [5:7]:
- 索引: 0 1 2 3 4 5 6
- 字符: 2 0 2 4 - 0 1
- [5:7] 包左不包右 → '01'
说明:
- 包左不包右
- 索引从0开始
""")
string_slicing_explanation()
# 7. One-Hot编码详解
print("\n=== 7. One-Hot编码详解 ===")
def one_hot_explanation():
"""One-Hot编码详解"""
print("""
One-Hot编码详解:
1. 为什么需要One-Hot编码?
- hour有24个值(0-23)
- month有12个值(1-12)
- 数值大小没有意义,需要转成0/1
2. pd.get_dummies()
- 自动生成新的列
- 原列被替换
- 列名格式: 原列名_值
3. 示例
原数据:
hour
0 14
1 15
One-Hot后:
hour_14 hour_15
0 1 0
1 0 1
4. 参数
- data: 数据
- columns: 要处理的列
""")
one_hot_explanation()
# 8. 特征工程流程
print("\n=== 8. 特征工程流程 ===")
def feature_engineering_process():
"""特征工程流程"""
print("""
特征工程流程:
1. 拷贝数据
feature_data = data.copy()
2. 提取hour特征
feature_data['hour'] = feature_data['time'].str[11:13]
3. 提取month特征
feature_data['month'] = feature_data['time'].str[5:7]
4. One-Hot编码
feature_data = pd.get_dummies(feature_data, columns=['hour', 'month'])
5. 查看结果
print(feature_data.head())
print(feature_data.info())
""")
feature_engineering_process()
# 9. 完整特征工程代码
print("\n=== 9. 完整特征工程代码 ===")
def complete_feature_engineering_code():
"""完整特征工程代码"""
print("""
def feature_engineering(data, logger):
\"\"\"特征工程\"\"\"
logger.info("开始特征工程")
# 1. 拷贝数据
feature_data = data.copy()
# 2. 提取hour特征
feature_data['hour'] = feature_data['time'].str[11:13]
# 3. 提取month特征
feature_data['month'] = feature_data['time'].str[5:7]
logger.info("提取hour和month特征完成")
# 4. One-Hot编码
feature_data = pd.get_dummies(feature_data, columns=['hour', 'month'])
logger.info(f"One-Hot编码完成,特征数: {feature_data.shape[1]}")
return feature_data
# 调用
feature_data = feature_engineering(pm.data_source, pm.log_file)
""")
complete_feature_engineering_code()
# 10. 总结
def feature_engineering_summary():
"""特征工程总结"""
print("=" * 50)
print("特征工程总结 - 添加小时和月份字段")
print("=" * 50)
print("\n1. 函数名")
print(" feature_engineering")
print("\n2. 参数")
print(" data: 数据源")
print(" logger: 日志对象")
print("\n3. 步骤")
print(" 拷贝数据")
print(" 提取hour: str[11:13]")
print(" 提取month: str[5:7]")
print(" One-Hot编码: pd.get_dummies()")
print("\n4. 重点")
print(" 字符串切片包左不包右")
print(" One-Hot编码处理分类特征")
print("\n" + "=" * 50)
print("特征工程完成!")
print("=" * 50)
feature_engineering_summary()
输出示例:
=== 2. 生成模拟数据 ===
数据形状: (720, 2)
数据前5行:
time power_load
0 2024-01-01 00:00:00 524.56
1 2024-01-01 01:00:00 489.12
...
=== 3. 特征工程函数 ===
提取hour和month后:
time power_load hour month
0 2024-01-01 00:00:00 524.56 00 01
1 2024-01-01 01:00:00 489.12 01 01
...
One-Hot编码后数据形状: (720, 39)
所有列名: ['time', 'power_load', 'hour_00', 'hour_01', ..., 'month_12']
5 重难点与易错提醒
- ❗重点:特征工程是项目重点。
- ❗重点:字符串切片
[11:13]提取小时,[5:7]提取月份。 - ❗重点:One-Hot编码用
pd.get_dummies()。 - ❗重点:先拷贝数据防止修改原数据。
- ⚠️易错:字符串切片索引错误。
- ⚠️易错:忘记拷贝数据。
- 💡深入理解:One-Hot编码将分类特征转成0/1。
6 课堂问答精选
Q: 如何提取小时和月份?
A: 使用字符串切片:
feature_data['hour'] = feature_data['time'].str[11:13]
feature_data['month'] = feature_data['time'].str[5:7]
说明:
[11:13]:包左不包右,提取小时[5:7]:包左不包右,提取月份- 索引从0开始
Q: 为什么需要One-Hot编码?
A: 原因:
- hour有24个值(0-23)
- month有12个值(1-12)
- 数值大小没有意义
- 需要转成0/1表示
7 本课小结
- 函数:
feature_engineering(data, logger)。 - 步骤:拷贝、提取hour、提取month、One-Hot编码。
- 切片:
[11:13]小时,[5:7]月份。 - 编码:
pd.get_dummies()。 - 重点:特征工程是项目核心。
8 延伸思考与实践
- 实践:运行特征工程代码。
- 预习:添加上n小时(窗口字段)。
- 思考:还有哪些特征可以提取?