前言
基于挑战赛“市场博弈和价格预测”
使用探索性数据分析(EDA)深入理解赛题。
对数据做尽可能多的探索,
了解数据所在的领域先验知识,数据本身的特性等,
(发现数据的结构、异常值、模式、趋势、关系以及变量之间的相互作用)
并总结为一系列有用的信息
0 编程准备
!pip install numpy pandas seaborn matplotlib statsmodels
import pandas as pd
import seaborn as sns
import matplotlib.pylab as plt
from pathlib import Path
import warnings
warnings.filterwarnings('ignore')
plt.style.use('ggplot')
plt.rcParams['font.sans-serif'] = ['WenQuanYi Micro Hei',"SimHei"]
plt.rcParams['axes.unicode_minus'] = False
base_path=Path("data")
请将数据文件electricity_price_parsed放在代码文件同级的data文件夹路径
下载链接:https://linklearner.com/activity/12/2/2 => 左上角打开面板 => 选择“Tsak 2”
1 数据基本信息
代码
electricity_price = pd.read_csv(base_path/"electricity_price_parsed.csv", parse_dates=["timestamp"], index_col=0)
electricity_price.columns = ["demand", "price"]
electricity_price.head()
# 创建测试集掩码,标记出所有价格为 NaN 的数据行
test_mask = electricity_price["price"].isna()
# 创建训练集掩码,标记出所有价格不为 NaN 的数据行,其中~代表布尔取反,即True和False互换。 `[True,False]`和 `~[False,True]`一致
train_mask = ~test_mask
# 打印训练集的范围和总长度
# 训练集范围从训练集中最早的日期到最新的日期
print(f"训练集范围:{electricity_price[train_mask].index.min()} --> {electricity_price[train_mask].index.max()}\t总长度{len(electricity_price[train_mask])}")
# 打印测试集的范围和总长度
# 测试集范围从测试集中最早的日期到最新的日期
print(f"测试集范围:{electricity_price[test_mask].index.min()} --> {electricity_price[test_mask].index.max()}\t总长度{len(electricity_price[test_mask])}")
electricity_price.info()
electricity_price.head(12)
回显
代码
def check_repeated(data, repeat_count=4):
"""
检查给定数据序列中是否存在元素不断重复的情况。
参数:
data (list): 要检查的序列数据。
repeat_count (int): 每个元素应重复的次数。默认值为4。
返回:
None
"""
# 以步长 repeat_count 遍历 data 的索引
for i in range(0, len(data), repeat_count):
# 从索引 i 开始,取长度为 repeat_count 的子序列
subsequence = data[i:i + repeat_count]
# 如果子序列的独特元素数量不等于 1,则表示不是同一元素重复
if len(set(subsequence)) != 1:
print(f"序列数据不是元素不断重复 {repeat_count} 次")
return # 发现不满足条件的情况后,直接返回
# 如果遍历完所有子序列,未发现不满足条件的情况,则输出满足条件的信息
print(f"序列数据是元素不断重复 {repeat_count} 次")
# 调用函数并传入特定的电价数据
check_repeated(electricity_price[train_mask]["price"])
回显
序列数据是元素不断重复 4 次
代码
# 使用loc方法选择指定日期的数据,绘制价格图表
electricity_price.loc["2023-01-03"].plot(y="price", figsize=(18, 5), marker='o')
# 设置图表的标题
plt.title("2023年1月3日出清价格走势")
回显
Text(0.5, 1.0, ‘2023年1月3日出清价格走势’)
2 统计指标分析
鼠标右键 -> 在新标签页中打开图像
可以使用electricity_price.describe()
快速生成描述性统计信息
中心趋势
- 均值:
df[feature].mean()
- 中位数
df[feature].median()
- 最大值
df[feature].max()
- 最小值
df[feature].min()
- 众数
df[feature].mode()
变异程度
- 标准差
df[feature].std()
- 极差
df[feature].apply(lambda x: x.max() - x.min())
- 四分位数
df[feature].quantile([0.25, 0.5, 0.75])
- 变异系数
df[feature].std()/df[feature].mean()
- 偏度和峰度
df[feature].skew()
,df[feature].kurtosis()
变化率:df[feature].pct_change()
- 计算公式为 x 2 − x 1 x 1 \frac{x_2 - x_1}{x_1} x1x2−x1
代码
# 使用 Seaborn 库绘制总负荷数值的分布图
# sns.displot(...) 函数用于绘制数据的分布图
ax = sns.displot(
electricity_price, # 输入数据,包含绘制所需的列
x="demand", # 指定绘图的列,这里是 "demand" 列
aspect=1.5, # 图形的宽高比,1.5 表示宽度是高度的 1.5 倍
height=5, # 图形的高度设置为 5 英寸
kde=True # 启用核密度估计(KDE),用于绘制数据的平滑概率密度曲线
)
# 设置图形的标题
ax.set(title="总负荷数值分布")
回显
代码
ax=sns.displot(electricity_price,x="price",aspect=1.5,height=5,kde=True);
ax.set(title="出清价格数值分布")
回显
3 分时统计指标分析
线图
鼠标右键 -> 在新标签页中打开图像
代码
# 从 DataFrame 的索引中提取时间信息,并添加为新的列
# 假设索引为 DatetimeIndex 类型
# 提取小时信息,并创建一个新列 "hour"
electricity_price["hour"] = electricity_price.index.hour
# 提取月份信息,并创建一个新列 "month"
electricity_price["month"] = electricity_price.index.month
# 提取日期信息,并创建一个新列 "day"
electricity_price["day"] = electricity_price.index.day
# 提取星期几的信息(0 = 周一, 6 = 周日),并创建一个新列 "weekday"
electricity_price["weekday"] = electricity_price.index.weekday
# 提取年份信息,并创建一个新列 "year"
electricity_price["year"] = electricity_price.index.year
# 创建一个包含两个子图的绘图区域,图形大小为 20x9 英寸,并启用约束布局
fig, ax = plt.subplots(
1, # 子图的行数为 1
2, # 子图的列数为 2
figsize=(20, 9), # 设置整个图形的大小为 20x9 英寸
constrained_layout=True # 启用约束布局以自动调整子图位置和大小
)
# 绘制不同年份的分时电价线图
sns.lineplot(
electricity_price.groupby(["hour", "year"])["price"].mean().reset_index(), # 按小时和年份分组,计算每组的平均电价,并重置索引
x="hour", # x 轴数据为小时
y="price", # y 轴数据为平均电价
ax=ax[0], # 将图绘制到第一个子图 (ax[0])
marker="o", # 数据点标记为圆圈
hue="year", # 根据年份不同设置不同的颜色
palette="Set1" # 使用 "Set1" 调色板
)
ax[0].set_title("不同年份的分时电价") # 设置第一个子图的标题
ax[0].set_xticks(range(24)) # 设置 x 轴刻度为 0 到 23(小时范围)
# 绘制不同年份的分时总负荷线图
sns.lineplot(
electricity_price.groupby(["hour", "year"])["demand"].mean().reset_index(), # 按小时和年份分组,计算每组的平均总负荷,并重置索引
x="hour", # x 轴数据为小时
y="demand", # y 轴数据为平均总负荷
ax=ax[1], # 将图绘制到第二个子图 (ax[1])
marker="o", # 数据点标记为圆圈
hue="year", # 根据年份不同设置不同的颜色
palette="Set1" # 使用 "Set1" 调色板
)
ax[1].set_title("不同年份的分时总负荷") # 设置第二个子图的标题
ax[1].set_xticks(range(24)); # 设置 x 轴刻度为 0 到 23(小时范围)
回显
透视表&热力图
鼠标右键 -> 在新标签页中打开图像
代码
# 创建一个透视表,计算不同月份和时间下的电价
pivot = pd.pivot_table(
electricity_price, # 输入的 DataFrame
values="price", # 透视表中要填充的值,这里是 "price"
index="month", # 设置行索引为月份
columns="hour" # 设置列索引为小时
)
# 将透视表中的数据类型转换为整数
pivot = pivot.astype(int)
pivot
回显
代码
# 创建一个图形,大小为 17x10 英寸
plt.figure(figsize=(17, 10))
# 绘制热图,显示不同月份和时间下的电价
sns.heatmap(
pivot, # 透视表数据
cmap="coolwarm", # 使用 "coolwarm" 调色板,显示热图的颜色
linewidths=0.5, # 设置单元格之间的分隔线宽度为 0.5
annot=True, # 启用单元格值的注释
fmt=".0f", # 注释的格式为整数
annot_kws={"size": 12, # 注释文本的大小设置为 12
"weight": "bold", # 注释文本的字体加粗
"color": "black"} # 注释文本的颜色为黑色
)
# 设置图形的标题
plt.title("不同月份和时间下的电价")
回显
Read more
- Datawhale AI 夏令营 第三期 数学建模(市场博弈和价格预测)
https://linklearner.com/activity/12/2/2