0


Datawhale AI 夏令营 市场博弈和价格预测 EDA 探索性数据分析

前言

基于挑战赛“市场博弈和价格预测”
使用探索性数据分析(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 数据基本信息

在这里插入图片描述
读取数据,并按照 NAN 划分训练集&测试集
代码

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)

回显
在这里插入图片描述
自定义函数 确认
代码

defcheck_repeated(data, repeat_count=4):"""
    检查给定数据序列中是否存在元素不断重复的情况。

    参数:
    data (list): 要检查的序列数据。
    repeat_count (int): 每个元素应重复的次数。默认值为4。

    返回:
    None
    """# 以步长 repeat_count 遍历 data 的索引for i inrange(0,len(data), repeat_count):# 从索引 i 开始,取长度为 repeat_count 的子序列
        subsequence = data[i:i + repeat_count]# 如果子序列的独特元素数量不等于 1,则表示不是同一元素重复iflen(set(subsequence))!=1:print(f"序列数据不是元素不断重复 {repeat_count} 次")return# 发现不满足条件的情况后,直接返回# 如果遍历完所有子序列,未发现不满足条件的情况,则输出满足条件的信息print(f"序列数据是元素不断重复 {repeat_count} 次")# 调用函数并传入特定的电价数据
check_repeated(electricity_price[train_mask]["price"])

回显

序列数据是元素不断重复 4 次

使用 matplotlib.pylab 库画图确认
代码

# 使用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} x1​x2​−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,# 子图的行数为 12,# 子图的列数为 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("不同月份和时间下的电价")

回显

在这里插入图片描述

4 负电价形成原因分析

鼠标右键 -> 在新标签页中打开图像
在这里插入图片描述
负电价频数 出现的小时分布
代码

minus_mask = electricity_price["price"]<0

plt.figure(figsize=(12,7))
ax = sns.countplot(electricity_price[minus_mask], x="hour")
ax.set(title="负电量频数出现的小时分布")

回显

在这里插入图片描述

负电价频数 出现的月分布
代码

plt.figure(figsize=(12,7))
ax = sns.countplot(electricity_price[minus_mask], x="month")
ax.set(title="负电量频数出现的月分布")

回显

在这里插入图片描述

负电价频数 出现的日期排序数表
代码

(# 选择不满足 minus_mask 条件的数据
    electricity_price[minus_mask]# 按月份和日期分组,计算每个组合的记录数量.groupby(["month","day"]).size()# 计算每个分组的大小(即每个分组的记录数).reset_index(name='count')# 重置索引,使 groupby 结果成为 DataFrame,并保留分组字段为列.sort_values("count",# 按 "count" 列排序
                 ascending=False)# 降序排序.head(15)# 选择排序后的前 15 行)

回显

在这里插入图片描述

2022年5月1日 - 2022年5月9日 电价 线图
代码

# 创建一个图形,大小为 20x8 英寸
plt.figure(figsize=(20,8))# 绘制从 2022年5月1日到2022年5月9日的电价数据的折线图
ax = sns.lineplot(
    electricity_price.loc["2022-05-01":"2022-05-09"]["price"],# 从 DataFrame 中选择时间范围内的电价数据
    color="black"# 设置折线的颜色为黑色)# 在每一天的 10:00 到 15:00 之间添加黄色半透明的高亮区域for i inrange(1,10):
    ax.axvspan(f"2022-05-0{i} 10:00:00",# 高亮区域的开始时间f"2022-05-0{i} 15:00:00",# 高亮区域的结束时间
        color='yellow',# 高亮区域的颜色为黄色
        alpha=0.2# 高亮区域的透明度设置为 0.2(0 完全透明,1 完全不透明))# 添加一条红色的虚线,y 值为 0,用于显示负电价的参考线
plt.axhline(
    y=0,# y 轴的值为 0
    color="red",# 虚线的颜色为红色
    linestyle="--"# 虚线的线型为虚线)# 设置 x 轴刻度标签的旋转角度为 45 度,并且水平对齐方式为右对齐
plt.setp(
    ax.get_xticklabels(),# 获取 x 轴刻度标签
    rotation=45,# 设置标签的旋转角度为 45 度
    ha='right'# 设置标签的水平对齐方式为右对齐)# 设置图形的标题
plt.title("一段比较典型的负电价趋势:2022年5月1日 - 2022年5月9日")

回显

在这里插入图片描述

2022年1月28日 - 2022年2月6日 电价 线图
代码

plt.figure(figsize=(20,8))
ax = sns.lineplot(electricity_price.loc["2023-01-21":"2023-02-02"]["price"], color="black")
plt.axhline(y=0, color="red", linestyle="--")
plt.setp(ax.get_xticklabels(), rotation=45, ha='right')
plt.title("假期对负电价的影响 2022年1月28日 - 2022年2月6日")

回显

在这里插入图片描述

5 高电价形成原因分析

鼠标右键 -> 在新标签页中打开图像
在这里插入图片描述
高电价频数 出现的小时分布
代码

# 计算电价的上限阈值,使用 3 标准差原则来检测异常值
upper_threshold =(
    electricity_price["price"].mean()+# 电价的均值3* electricity_price["price"].std()# 加上 3 倍的电价标准差)# 创建一个布尔型掩码,用于标识电价高于上限阈值的异常值
high_abnormal_mask =(
    electricity_price["price"]> upper_threshold  # 判断电价是否大于计算得到的上限阈值)

plt.figure(figsize=(12,7))
ax = sns.countplot(electricity_price[high_abnormal_mask], x="hour")
ax.set(title="高电量频数出现的小时分布")

回显

在这里插入图片描述

高电价频数 出现的月分布
代码


plt.figure(figsize=(12,7))
ax=sns.countplot(electricity_price[high_abnormal_mask],x="month")
ax.set(title="高电量频数出现的月分布");

回显

在这里插入图片描述

高电价频数 出现的日期排序数表
代码

# 从电价数据中筛选出高于上限阈值的异常值(
electricity_price[high_abnormal_mask]# 按月份和日期分组,并计算每个组合的异常值记录数量.groupby(["month","day"]).size()# 计算每个分组的大小(即每个分组的记录数).reset_index(name="count")# 重置索引,将分组字段转换为 DataFrame 的列.sort_values("count",# 按 "price" 列排序
        ascending=False)# 降序排序.head(15)# 选择排序后的前 15 行)

回显

在这里插入图片描述

2022年8月1日 - 2022年8月8日 总需求 线图
代码

plt.figure(figsize=(20,8))
ax = sns.lineplot(electricity_price.loc["2022-08-01":"2022-08-08"]["demand"], color="black")
plt.setp(ax.get_xticklabels(), rotation=45, ha='right')
plt.axvspan("2022-08-03","2022-08-06", color="yellow", alpha=0.2)
plt.title("2022年8月1日 - 2022年8月8日 总需求")

回显

在这里插入图片描述

2022年8月1日 - 2022年8月8日 电价 线图
代码

plt.figure(figsize=(20,8))
ax = sns.lineplot(electricity_price.loc["2022-08-01":"2022-08-08"]["price"], color="black")
plt.axhline(y=upper_threshold, color="red", linestyle="--")
plt.setp(ax.get_xticklabels(), rotation=45, ha='right')
plt.title("典型高电价时间段 2022年8月1日 - 2022年8月8日 中的3-6日")

回显

在这里插入图片描述

6 双变量分析

鼠标右键 -> 在新标签页中打开图像
在这里插入图片描述
pandas 库 编程实现 皮尔逊相关系数(r)
代码

electricity_price[["demand","price"]].corr()

回显

在这里插入图片描述

numpy 库 编程实现 皮尔逊相关系数(r)
代码

import numpy as np
ar_1=electricity_price[train_mask][["demand"]].values
ar_2=electricity_price[train_mask][["price"]].values
np.corrcoef(np.column_stack((ar_1, ar_2)).T)

回显

在这里插入图片描述

回归图(散点图及拟合线)
代码

# 创建一个图形,大小为 8x10 英寸
plt.figure(figsize=(8,10))# 绘制回归图(散点图及拟合线)
sns.regplot(
    data=electricity_price.loc["2022"],# 选择2022年的数据
    x="demand",# x 轴的变量为 "demand"
    y="price",# y 轴的变量为 "price"
    scatter_kws={# 设置散点图的样式"s":0.5,# 散点的大小设置为 0.5"alpha":0.6,# 散点的透明度设置为 0.6"color":"black"# 散点的颜色设置为黑色},
    color="red",# 拟合线的颜色设置为红色
    lowess=True# 启用局部加权回归(Lowess)以拟合数据)

回显

在这里插入图片描述

EDA 总结

在这里插入图片描述

Read more


本文转载自: https://blog.csdn.net/sk8Love956/article/details/140834330
版权归原作者 机动人心 所有, 如有侵权,请联系我们删除。

“Datawhale AI 夏令营 市场博弈和价格预测 EDA 探索性数据分析”的评论:

还没有评论