电价数据分析笔记
基本信息
在电价数据分析中,我们首先需要了解数据的基本信息,包括数据的时间范围、数据的分辨率(如小时、天、月等)、包含的变量(如电价、总负荷、发电类型等)。这些基本信息为后续的分析奠定基础。
统计指标分析
对数据进行统计指标分析可以帮助我们了解数据的总体特征。常见的统计指标包括:
从总负荷和出清价格的数值分布来看,可以发现以下几个特点:
-
数据的集聚趋势
-
均值:
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()
计算公式为 (x2-x1)/x1 -
总负荷基本服从正态分布,符合现实中的耗电规律
-
出清价格中有大量的异常负价格
-
1-100之间的低价格较多,表明这些时候火电有一定的异常高价(800以上)
不同小时的总负荷和电价
分析不同小时的总负荷和电价,可以帮助我们了解电价和负荷的日内波动规律。通常情况下,不同小时的电价和负荷会呈现出一定的规律性:
- 高峰时段:通常在早上和傍晚,电价和负荷较高。
- 低谷时段:通常在深夜和午后,电价和负荷较低。
鸭子曲线:由于火电和光伏发电互为替代品,当一天太阳出来后,太阳能逐渐开始替代火电,并在14点达到最大,进而导致火电受光伏发电竞争而降价。而在傍晚时太阳落山,光伏机组迅速减小发电,此时火电开始集中发电,价格迅速上升,形成了一天中典型的“两高峰,一低谷”的态势。
通过绘制24小时的电价和负荷曲线,可以直观地看到这些变化规律。
负电价与高电价形成原因分析
在数据分析过程中,我们发现了负电价和异常高电价的现象。为了更好地理解这些现象的形成原因,我们需要进行详细的探索和分析。
负电价:
- 出现频数:低谷期的负电价较为明显,可能是受市场竞争导致电价中标失败,只能亏本售出。
- 假期影响:例如,2022年的五一假期和春节假期期间,负电价出现频繁。这可能是由于假期期间火力发电量下降,导致负电价。
高电价:
- 时间分布:高电价主要集中在日落后,此时光伏发电下降,火电有较大的竞价空间。
- 外部因素:例如,2022年8月3日-8月6日的高电价可能受到了外部因素的影响,如天气状况。
通过对比不同时间段的电价和负荷数据,以及结合外部数据(如天气数据),可以更深入地理解负电价和高电价的形成原因。
总结
综合以上分析,我们可以总结出以下几点:
- 气象状况对出清价格有较大影响。
- 节假日对出清价格有较大影响,易于出现负值。
- 总负荷与出清价格线性关系很高,但总体呈现分段线性的特征。
- 不同月份/小时下的出清价格受市场竞争影响较大。
- 随着碳中和不断发展,火电价格有总体下降的趋势。
本次案例中的EDA(探索性数据分析)只是一部分,旨在提供探索性数据分析的一般步骤。可以自行尝试使用 seaborn
,plotly
等Python库做进一步的可视化,挖掘序列的更多信息,从而指导后续的特征构造。
下面是随机森林模型,但是结果不如线性回归模型:
import numpy as np
import pandas as pd
from pathlib import Path
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import train_test_split
# 设置数据路径
base_path = Path("data")
# 读取市场数据
electricity_price = pd.read_csv(base_path / "electricity price.csv")
# 读取市场主体(各发电机组)数据
unit = pd.read_csv(base_path / "unit.csv")
# 准备示例提交数据sample_submit
sample_submit = electricity_price[electricity_price["clearing price (CNY/MWh)"].isna()].drop(columns="demand")
sample_submit.to_csv(base_path / "sample_submit.csv", index=False)
# 将day和time列合并成timestamp列,便于提取时间戳特征
electricity_price["timestamp"] = pd.to_datetime(
electricity_price["day"] + " " + electricity_price["time"].str.replace("24:00:00", "00:00"))
# 处理24:00:00的情况,即表示第二天的00:00:00
mask = electricity_price['timestamp'].dt.time == pd.Timestamp('00:00:00').time()
# 需要将这些行的日期部分加一天
electricity_price.loc[mask, 'timestamp'] += pd.Timedelta(days=1)
# 设置列的顺序,同时去除day和time列
electricity_price = electricity_price[["timestamp", "demand", "clearing price (CNY/MWh)"]]
# 准备训练数据
train_length = 55392
features = ['demand'] # 这里只使用'demand'作为特征,可以加入更多特征
X = electricity_price[features][:train_length]
y = electricity_price["clearing price (CNY/MWh)"].iloc[:train_length]
# 将数据分成训练集和验证集
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)
# 定义和训练模型
gbr_model = GradientBoostingRegressor(random_state=42)
gbr_model.fit(X_train, y_train)
# 验证模型
y_val_pred = gbr_model.predict(X_val)
print("Validation R^2: ", gbr_model.score(X_val, y_val))
# 准备测试数据
X_test = electricity_price[features][train_length:]
# 进行预测
y_test_pred = gbr_model.predict(X_test)
# 填充预测结果
sample_submit["clearing price (CNY/MWh)"] = y_test_pred
# 保存提交文件
sample_submit.to_csv("submit.csv", index=False)