target
根据electricity price.csv(其中包括:
电力市场的市场出清价格,市场需求等信息),unit.csv
(存放市场供给者(各发电机组)的参数信息)两个文件,对electricity price.csv
剩下的时长出清价格进行预测。
electricity price.csv:文件中包括以下几种数据:
-
Day/Time:交易时间,中国电力现货市场15分钟结算一次,一天共96个交易点
-
demand:区域内电力总负荷(总需求),单位为MW
-
clearing price (CNY/MWh):市场出清电价,单位为元/MW·h
day | time | demand | clearing price (CNY/MWh) |
2021/12/1 | 0:15 | 40334.18 | 350.8 |
2021/12/1 | 0:30 | 40523.15 | 350.8 |
2021/12/1 | 0:45 | 40374.74 | 350.8 |
unit.csv
:存放市场供给者(各发电机组)的参数信息,包括:
-
unit ID:每个机组唯一的ID
-
Capacity(MW):机组的额定容量(额定功率),越高机组的发电能力越强
-
utilization hour (h) :电厂的年平均运行小时数,需要注意多个机组可能共同属于一个电厂,有相同的值
-
coal consumption (g coal/KWh):每发一度电需要耗费多少煤炭,为成本参数
-
power consumption rate:电厂单位时间内耗电量与发电量的百分比,例如单位时间耗电量为500度电,发电量为10000度电,利用率就是500/10000=5%。
unit ID | Capacity (MW) | Utilization Hour (h) | Coal Consumption (g coal/KWh) | Power Consumption Rate (%) |
1 | 110 | 2069.12 | 266.07 | 6.91 |
2 | 160 | 5509.22 | 292.7 | 6.91 |
3 | 160 | 3562.79 | 293.35 | 6.91 |
Evaluation
最终评价指标为MSE(均方误差)和RMSE(均方根误差)的均值(事实上这和只用RMSE或者MSE是一样的),值越小越好,公式如下:
其中:
-
为真实市场出清价格
-
为预测的市场出清价格
-
为样本数量,这里是测试集的大小28228
Method
剥离题目的描述背景,我们可以将问题抽象为一个回归问题,即已知2021年12月1日-2023年7月1日的出清价格,需要对2023年7月1日-2024年4月18日的出清价格进行预测。可以首先使用表格中的各个变量与出清价格进行相关性检测,之后挑选合适的变量构造回归方程,即可解决问题。
同样可以使用人工智能的方法,构造多层的神经网络结构,对出清价格进行预测。
总而言之,纯粹依靠构造时间序列模型可以完成这个任务。
使用ABM(Agent-Based-Modeling)解决该问题的方法
首先介绍一个概念即边际成本:生产额外一单位产品(这里是一度电)带来的成本增加
出清价格是如何形成的呢?
-
所有发电机组申报自己卖出的电价和电量
-
市场根据机组报价,从低到高排序,依次从低价开始成交
-
当成交的容量和大于等于总需求时,达到市场出清(供需平衡),这时候最后一个达成交易的机组报价为市场出清价格
从上述过程来看,每一个机组都希望自己的报价都近似于最终的出清价格。如果报价高于出清价格,那么竞标失败,没有卖出任何电力。如果低于竞标价格,那么就少赚钱甚至亏本了。
但是,各个机组间存在竞争关系,各个机组并不清楚其他机组的报价。 为了保证自己的电力可以卖出去,并且不亏本。我们可以认为机组的报价为额外生产一度电带来的成本增加,即报价边际成本(当然实际情况并非如此)
最终的出清价格就是边际成本的最大值。因此,问题就转化为边际成本的最大值是多少。
下面从代码出发,解决问题:
1.导入库
import numpy as np
import pandas as pd
from pathlib import Path
from sklearn.linear_model import LinearRegression
2.数据预处理
由于最终提交的数据格式为:日期,时间,出清价格。因此删去demand列并保留未知出清价格的日期。
base_path = Path("data") # 确保数据都放在同级的data目录下
# 读取市场数据
electricity_price = pd.read_csv(base_path / "electricity price.csv")
# 读取市场主体(各发电机组)数据
unit = pd.read_csv(base_path / "unit.csv")
"""
准备示例提交数据sample_submit
1. electricity_price["clearing price (CNY/MWh)"].isna()找到出清价格为缺失值的行,即要预测的目标
2. 去除demand列,符合最后的提交格式
"""
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)
将日期和时间列合并为时间戳列。需要对24:00:00的情况特判。pandas无法处理24:00:00的情况。具体做法即将24:00:00字符串替换为00:00:00,同时日期+1
# 将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)"]]