电力负荷案例之按照月份、假日可视化数据
1 课程概览
本课讲解电力负荷案例的月份和假日数据可视化。包括按月份分组求平均负荷、按工作日和周末分组分析。强调weekday和apply的使用。
2 核心概念与定义
- 月份分析:按月份分组求平均负荷。
- 假日分析:按工作日和周末分组。
- weekday:获取一周中的第几天。
- apply:对每个值做操作。
- pd.to_datetime:转成datetime类型。
3 算法与模型详解
3.1 按月份可视化
步骤:
- 提取month特征
- 按month分组求平均
- 绘制折线图
提取month:
analysis_data['month'] = analysis_data['time'].str[5:7]
说明:
- 字符串切片
[5:7]:包左不包右 - 0-1-2-3-4-5,到5是第6个字符
- 5-6是我们要的月份
分组求平均:
month_load = analysis_data.groupby('month')['power_load'].mean()
绘制折线图:
- 子图位置:
add_subplot(4, 1, 3) - X轴:月份
- Y轴:平均负荷
3.2 月份分析结论
观察:
- 7月、8月用电量较多
- 从4月到7月递增
- 原因:夏天天气热,要降温,电器多
建议:
- 这几个月生产的电能尽量多一些
- 做好电力储备
3.3 按假日(工作日/周末)可视化
问题:不能直接从数据截出工作日和周末
解决方法:
- 使用
pd.to_datetime转成datetime - 使用
weekday获取一周中的第几天 - 使用
apply对每个值操作
实现:
analysis_data['weekday'] = analysis_data['time'].apply(
lambda x: pd.to_datetime(x).weekday()
)
说明:
apply:把每个值传给lambda函数pd.to_datetime(x):转成datetime.weekday():获取一周中的第几天(0-6,0是周一)
3.4 weekday说明
weekday返回值:
- 0:周一
- 1:周二
- 2:周三
- 3:周四
- 4:周五
- 5:周六
- 6:周日
工作日:0-4(周一到周五) 周末:5-6(周六、周日)
3.5 Jupyter Notebook优势
说明:
- 可以分段式执行
- 避免重复执行前面代码
- 适合数据探索和分析
4 代码示例
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 解决中文乱码
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 1. 生成模拟数据
print("=== 1. 生成模拟数据 ===")
def generate_power_load_data(n_days=90):
"""生成电力负荷数据"""
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.3 # 夏季用电更多
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
data = generate_power_load_data(n_days=90)
print(f"数据形状: {data.shape}")
# 2. 按月份可视化
print("\n=== 2. 按月份可视化 ===")
def visualize_by_month(data):
"""按月份可视化"""
analysis_data = data.copy()
# 方法1:字符串切片(如果time是字符串)
# analysis_data['month'] = analysis_data['time'].str[5:7]
# 方法2:使用dt(如果time是datetime)
analysis_data['month'] = analysis_data['time'].dt.month
# 按月份分组求平均
month_load = analysis_data.groupby('month')['power_load'].mean()
print("各月份平均负荷:")
for month, load in month_load.items():
print(f" {month:2d}月: {load:.2f}")
# 绘制折线图
plt.figure(figsize=(12, 6))
plt.plot(month_load.index, month_load.values, 'bo-', linewidth=2, markersize=8)
plt.xlabel('月份')
plt.ylabel('平均负荷')
plt.title('各月份平均负荷分布')
plt.grid(True, alpha=0.3)
plt.xticks(range(1, 13))
plt.savefig('month_load.png', dpi=100)
print("月份负荷图已保存")
return month_load
month_load = visualize_by_month(data)
# 3. 月份分析结论
print("\n=== 3. 月份分析结论 ===")
def month_analysis_conclusions(month_load):
"""月份分析结论"""
peak_month = month_load.idxmax()
peak_load = month_load.max()
valley_month = month_load.idxmin()
valley_load = month_load.min()
print(f"""
月份分析结论:
1. 高峰月份
- 月份: {peak_month}月
- 平均负荷: {peak_load:.2f}
- 原因: 夏季降温用电多
2. 低谷月份
- 月份: {valley_month}月
- 平均负荷: {valley_load:.2f}
- 原因: 气候适宜,用电少
3. 趋势分析
- 从4月到7月递增
- 7月、8月用电量最多
- 建议夏季做好电力储备
""")
month_analysis_conclusions(month_load)
# 4. 按假日(工作日/周末)可视化
print("\n=== 4. 按假日(工作日/周末)可视化 ===")
def visualize_by_weekday(data):
"""按工作日/周末可视化"""
analysis_data = data.copy()
# 方法1:使用apply和weekday
analysis_data['weekday'] = analysis_data['time'].apply(
lambda x: pd.to_datetime(x).weekday()
)
# 方法2:使用dt(更高效)
# analysis_data['weekday'] = analysis_data['time'].dt.dayofweek
print("weekday前10条:")
print(analysis_data[['time', 'weekday']].head(10))
# 按weekday分组求平均
weekday_load = analysis_data.groupby('weekday')['power_load'].mean()
days = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
print("\n各天平均负荷:")
for i, day in enumerate(days):
load = weekday_load.iloc[i] if i < len(weekday_load) else 0
print(f" {day} (weekday={i}): {load:.2f}")
# 绘制柱状图
plt.figure(figsize=(10, 6))
colors = ['blue'] * 5 + ['red'] * 2 # 工作日蓝色,周末红色
plt.bar(days, weekday_load.values, color=colors, edgecolor='black')
plt.xlabel('星期')
plt.ylabel('平均负荷')
plt.title('工作日和周末平均负荷')
plt.grid(True, alpha=0.3, axis='y')
plt.savefig('weekday_load.png', dpi=100)
print("工作日/周末负荷图已保存")
return weekday_load
weekday_load = visualize_by_weekday(data)
# 5. 工作日 vs 周末对比
print("\n=== 5. 工作日 vs 周末对比 ===")
def compare_weekday_weekend(data):
"""对比工作日和周末"""
analysis_data = data.copy()
analysis_data['weekday'] = analysis_data['time'].dt.dayofweek
# 判断是否周末
analysis_data['is_weekend'] = analysis_data['weekday'].isin([5, 6]).astype(int)
# 分组求平均
weekend_load = analysis_data.groupby('is_weekend')['power_load'].mean()
print("工作日 vs 周末:")
print(f" 工作日 (is_weekend=0): {weekend_load.iloc[0]:.2f}")
print(f" 周末 (is_weekend=1): {weekend_load.iloc[1]:.2f}")
# 计算差异
diff = weekend_load.iloc[0] - weekend_load.iloc[1]
pct = diff / weekend_load.iloc[0] * 100
print(f"\n 差异: {diff:.2f} ({pct:.2f}%)")
print(f" 工作日比周末{'高' if diff > 0 else '低'} {abs(pct):.2f}%")
# 可视化
plt.figure(figsize=(8, 6))
labels = ['工作日', '周末']
plt.bar(labels, weekend_load.values, color=['blue', 'red'], edgecolor='black')
plt.xlabel('日期类型')
plt.ylabel('平均负荷')
plt.title('工作日 vs 周末平均负荷')
plt.grid(True, alpha=0.3, axis='y')
# 添加数值标签
for i, v in enumerate(weekend_load.values):
plt.text(i, v + 10, f'{v:.2f}', ha='center', va='bottom')
plt.savefig('weekday_vs_weekend.png', dpi=100)
print("对比图已保存")
compare_weekday_weekend(data)
# 6. 综合可视化
print("\n=== 6. 综合可视化 ===")
def comprehensive_visualization(data):
"""综合可视化"""
analysis_data = data.copy()
analysis_data['hour'] = analysis_data['time'].dt.hour
analysis_data['month'] = analysis_data['time'].dt.month
analysis_data['weekday'] = analysis_data['time'].dt.dayofweek
analysis_data['is_weekend'] = analysis_data['weekday'].isin([5, 6]).astype(int)
fig = plt.figure(figsize=(20, 40))
# 子图1:负荷整体分布(直方图)
ax1 = fig.add_subplot(4, 1, 1)
ax1.hist(analysis_data['power_load'], bins=50, color='skyblue', edgecolor='black')
ax1.set_xlabel('电力负荷')
ax1.set_ylabel('频数')
ax1.set_title('负荷整体分布')
ax1.grid(True, alpha=0.3)
# 子图2:各小时平均负荷(柱状图)
ax2 = fig.add_subplot(4, 1, 2)
hourly_avg = analysis_data.groupby('hour')['power_load'].mean()
ax2.bar(hourly_avg.index, hourly_avg.values, color='lightgreen', edgecolor='black')
ax2.set_xlabel('小时')
ax2.set_ylabel('平均负荷')
ax2.set_title('各小时平均负荷分布')
ax2.set_xticks(range(24))
ax2.grid(True, alpha=0.3)
# 子图3:各月份平均负荷(折线图)
ax3 = fig.add_subplot(4, 1, 3)
monthly_avg = analysis_data.groupby('month')['power_load'].mean()
ax3.plot(monthly_avg.index, monthly_avg.values, 'bo-', linewidth=2, markersize=8)
ax3.set_xlabel('月份')
ax3.set_ylabel('平均负荷')
ax3.set_title('各月份平均负荷分布')
ax3.set_xticks(range(1, 13))
ax3.grid(True, alpha=0.3)
# 子图4:工作日和周末平均负荷(柱状图)
ax4 = fig.add_subplot(4, 1, 4)
weekend_avg = analysis_data.groupby('is_weekend')['power_load'].mean()
labels = ['工作日', '周末']
colors = ['blue', 'red']
ax4.bar(labels, weekend_avg.values, color=colors, edgecolor='black')
ax4.set_xlabel('日期类型')
ax4.set_ylabel('平均负荷')
ax4.set_title('工作日和周末平均负荷')
ax4.grid(True, alpha=0.3, axis='y')
plt.tight_layout()
plt.savefig('comprehensive_distribution.png', dpi=100)
print("综合可视化图已保存")
comprehensive_visualization(data)
# 7. weekday和apply详解
print("\n=== 7. weekday和apply详解 ===")
def weekday_apply_explanation():
"""weekday和apply详解"""
print("""
weekday和apply详解:
1. pd.to_datetime
- 将字符串转成datetime类型
- pd.to_datetime(x)
2. weekday
- 获取一周中的第几天
- 返回值: 0-6
- 0: 周一, 1: 周二, ..., 5: 周六, 6: 周日
3. apply
- 对每个值做操作
- analysis_data['time'].apply(lambda x: ...)
4. 使用方法
# 方法1: apply + weekday
analysis_data['weekday'] = analysis_data['time'].apply(
lambda x: pd.to_datetime(x).weekday()
)
# 方法2: dt.dayofweek (更高效)
analysis_data['weekday'] = analysis_data['time'].dt.dayofweek
5. 判断周末
analysis_data['is_weekend'] = analysis_data['weekday'].isin([5, 6]).astype(int)
""")
weekday_apply_explanation()
# 8. Jupyter Notebook建议
print("\n=== 8. Jupyter Notebook建议 ===")
def jupyter_notebook_tips():
"""Jupyter Notebook建议"""
print("""
Jupyter Notebook建议:
1. 优势
- 分段式执行
- 避免重复执行前面代码
- 适合数据探索和分析
2. 使用场景
- 数据预处理
- 特征工程
- 数据可视化
- 模型调试
3. 建议
- 数据探索时使用Jupyter
- 项目部署时使用.py文件
- 可以拆解步骤,逐步执行
""")
jupyter_notebook_tips()
# 9. 完整可视化代码
print("\n=== 9. 完整可视化代码 ===")
def complete_visualization_code():
"""完整可视化代码"""
print("""
def analysis_data(data):
\"\"\"查看数据分布\"\"\"
analysis_data = data.copy()
# 提取特征
analysis_data['hour'] = analysis_data['time'].dt.hour
analysis_data['month'] = analysis_data['time'].dt.month
analysis_data['weekday'] = analysis_data['time'].dt.dayofweek
analysis_data['is_weekend'] = analysis_data['weekday'].isin([5, 6]).astype(int)
# 创建画布
fig = plt.figure(figsize=(20, 40))
# 子图1: 负荷整体分布
ax1 = fig.add_subplot(4, 1, 1)
ax1.hist(analysis_data['power_load'], bins=50)
ax1.set_title('负荷整体分布')
# 子图2: 各小时平均负荷
ax2 = fig.add_subplot(4, 1, 2)
hourly_avg = analysis_data.groupby('hour')['power_load'].mean()
ax2.bar(hourly_avg.index, hourly_avg.values)
ax2.set_title('各小时平均负荷')
# 子图3: 各月份平均负荷
ax3 = fig.add_subplot(4, 1, 3)
monthly_avg = analysis_data.groupby('month')['power_load'].mean()
ax3.plot(monthly_avg.index, monthly_avg.values, 'bo-')
ax3.set_title('各月份平均负荷')
# 子图4: 工作日和周末
ax4 = fig.add_subplot(4, 1, 4)
weekend_avg = analysis_data.groupby('is_weekend')['power_load'].mean()
ax4.bar(['工作日', '周末'], weekend_avg.values)
ax4.set_title('工作日和周末平均负荷')
plt.tight_layout()
plt.savefig('data_distribution.png', dpi=100)
""")
complete_visualization_code()
# 10. 总结
def visualization_summary():
"""可视化总结"""
print("=" * 50)
print("数据可视化总结")
print("=" * 50)
print("\n1. 按月份可视化")
print(" 提取month: dt.month")
print(" 分组求平均: groupby('month').mean()")
print(" 绘制折线图")
print("\n2. 按假日可视化")
print(" 提取weekday: apply(lambda) 或 dt.dayofweek")
print(" 判断周末: isin([5, 6])")
print(" 分组求平均")
print(" 绘制柱状图")
print("\n3. 分析结论")
print(" 7-8月用电最多(夏季降温)")
print(" 工作日用电比周末多")
print("\n4. 工具建议")
print(" 数据探索用Jupyter Notebook")
print(" 项目部署用.py文件")
print("\n" + "=" * 50)
print("数据可视化完成!")
print("=" * 50)
visualization_summary()
输出示例:
=== 2. 按月份可视化 ===
各月份平均负荷:
1月: 856.78
2月: 845.23
...
12月: 867.90
=== 4. 按假日(工作日/周末)可视化 ===
weekday前10条:
time weekday
0 2024-01-01 00:00:00 0
1 2024-01-01 01:00:00 0
...
各天平均负荷:
周一 (weekday=0): 980.45
周二 (weekday=1): 985.67
...
周日 (weekday=6): 785.23
=== 5. 工作日 vs 周末对比 ===
工作日 vs 周末:
工作日 (is_weekend=0): 982.34
周末 (is_weekend=1): 785.23
差异: 197.11 (20.07%)
工作日比周末高 20.07%
5 重难点与易错提醒
- ❗重点:按月份分组:
groupby('month').mean()。 - ❗重点:weekday返回0-6,0是周一。
- ❗重点:apply对每个值做操作。
- ❗重点:周末判断:
isin([5, 6])。 - ⚠️易错:字符串切片
[5:7]包左不包右。 - ⚠️易错:weekday返回值记错。
- 💡深入理解:数据可视化是特征工程的依据。
6 课堂问答精选
Q: 如何获取一周中的第几天?
A: 两种方法:
方法1(apply + weekday):
analysis_data['weekday'] = analysis_data['time'].apply(
lambda x: pd.to_datetime(x).weekday()
)
方法2(dt.dayofweek,更高效):
analysis_data['weekday'] = analysis_data['time'].dt.dayofweek
返回值:0-6(0是周一,6是周日)
Q: 如何判断是否周末?
A:
analysis_data['is_weekend'] = analysis_data['weekday'].isin([5, 6]).astype(int)
- 5:周六
- 6:周日
isin([5, 6]):判断是否在列表中astype(int):转成0/1
7 本课小结
- 月份:
groupby('month').mean(),折线图。 - 假日:
weekday获取星期几,apply或dt.dayofweek。 - 周末:
isin([5, 6])判断。 - 结论:7-8月用电多,工作日比周末用电多。
- 工具:数据探索用Jupyter Notebook。
8 延伸思考与实践
- 实践:运行月份和假日可视化代码。
- 预习:特征工程(时序数据转宽表)。
- 思考:如何根据可视化结果设计特征?