目录
1.题目理解
“本次比赛要求针对电力现货市场价格和市场博弈主体(549个发电机组)的信息,用ABM方法建模这些机组在报价上的博弈行为,使最终模拟的市场出清报价接近现实中的市场出清价格。”
提供了两组数据:
electricity price.csv
:
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 |
2021/12/1 | 1:00 | 40111.55 | 350.8 |
2021/12/1 | 1:15 | 40067.5 | 348.93 |
记录了每15分钟的电力需求(MW)及市场出清电价(元/MW·h)。
其中,训练集范围为2021年12月1日到2023年7月1日,共计55392个点;测试集范围为2023年7月1日到2024年4月18日,共计28228个点
unit.csv
:
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 |
4 | 160 | 5684.12 | 284.88 | 6.91 |
5 | 220 | 2231.35 | 323.08 | 8.54 |
记录了各发电机组的额定容量(MW)、电厂的年平均运行小时数、每发一度电的煤耗成本(g coal/KWh)及电厂单位时间内耗电量与发电量的百分比。
提供了评价指标:
真实市场出清价格和预测市场出清价格间MSE(均方误差)和RMSE(均方根误差)的均值,值越小越好。
概括:
要预测2023年7月1日到2024年4月18日每15分钟的市场出清价格,可以依靠时间序列模型完成,题目要求使用ABM模型建模获取市场出清价格,可以将二者结合。
2.ABM相关
ABM(Agent-Based Modeling,基于代理的建模),是一种用于模拟复杂系统的方法,它通过模拟多个自主行为体(即代理)的交互,来研究整个系统的行为和涌现现象。ABM常用于社会科学、经济学、生态学等领域,用以理解和预测复杂系统中的动态变化。
主要组成部分
-
代理(Agent):
- 自主实体:每个代理是一个自主的个体,可以是人、动物、公司、国家等。
- 属性与状态:代理具有一组属性(如年龄、财富、位置等)和状态(如健康状况、决策等)。
- 行为规则:代理依据预定义的规则或策略进行决策和行动。
-
环境(Environment):
- 代理所在的虚拟空间,可以是物理空间(如地理区域)或抽象空间(如社交网络)。
- 环境对代理的行为有影响,如资源分布、地形等。
-
交互(Interaction):
- 代理之间以及代理与环境之间的互动方式。
- 交互可以包括信息交换、交易、竞争、合作等。
ABM的工作原理
-
初始化:
- 定义代理及其属性和行为规则。
- 设置初始环境条件和代理分布。
-
仿真过程:
- 在每个仿真步骤中,代理根据其行为规则和当前状态做出决策和行动。
- 代理的行动会影响环境和其他代理,环境也会反馈到代理。
- 仿真持续进行,直到达到预定的终止条件(如时间步数、稳定状态等)。
-
结果分析:
- 收集仿真过程中的数据,分析系统行为和涌现现象。
- 可以通过调整参数、改变规则等方式进行多次仿真,以研究不同条件下的系统表现。
优点
- 灵活性:可以模拟各种复杂系统和多样化的行为规则,适用于广泛的应用领域。
- 涌现现象:能够捕捉个体行为对整体系统的影响,揭示系统中难以预见的涌现现象。
- 动态变化:可以处理动态变化的环境和规则,适应性强。
概括:
基于代理的建模是一种强大的工具,用于理解和预测复杂系统中的动态行为。通过模拟多个自主代理的交互,ABM能够揭示系统中个体行为对整体结果的影响,提供深刻的洞察和决策支持。
3.市场出清价格
概念:
市场出清价格(Market Clearing Price,MCP)是在电力市场中,通过市场机制确定的电力价格,在这个价格下电力的供给与需求达到平衡。形成市场出清价格的过程通常包括以下几个步骤:
-
供给和需求的申报:
- 发电厂申报:发电厂根据其发电成本、容量等因素向市场申报其发电量和价格。这些申报通常是按照价格从低到高排列的,即价格越低的发电厂越优先被调度。
- 需求方申报:电力需求方(如电力公司、用电企业等)申报其用电需求量。这些需求通常是固定的,因为用电方希望满足其用电需求。
-
需求曲线和供给曲线:
- 需求曲线:需求曲线表示在不同价格水平下的电力需求量。通常电力需求量对价格变化不敏感,所以需求曲线较为陡峭。
- 供给曲线:供给曲线表示在不同价格水平下的电力供给量。供给曲线通常是向上倾斜的,因为发电成本较低的电厂优先提供电力。
-
出清过程:
- 市场出清是通过将供给曲线和需求曲线交汇点来确定的。交汇点的价格就是市场出清价格,交汇点的数量就是市场出清的电量。
- 在这个价格下,电力市场的供给和需求相等,也就是所有需求方愿意以这个价格购买电力,所有供给方愿意以这个价格出售电力。
-
确定发电调度:
- 根据市场出清价格,市场运营机构(如电网公司)确定哪些发电厂需要发电。通常是按照价格优先原则,即价格低的发电厂优先发电。
- 调度的结果就是供需平衡,同时保证市场中所有的电力需求都得到了满足。
例子
假设有三个发电厂 A、B 和 C,它们的发电成本分别为 50 元/MWh、70 元/MWh 和 90 元/MWh。它们的发电量上限分别为 100 MWh、150 MWh 和 200 MWh。市场上的需求量为 250 MWh。
-
发电厂申报:
- 发电厂 A:50 元/MWh,100 MWh
- 发电厂 B:70 元/MWh,150 MWh
- 发电厂 C:90 元/MWh,200 MWh
-
供给曲线:
- 按照价格从低到高排列:发电厂 A(100 MWh),发电厂 B(150 MWh),发电厂 C(200 MWh)
-
需求曲线:
- 总需求量为 250 MWh
-
出清过程:
- 在 50 元/MWh 的价格下,供给量为 100 MWh(只有发电厂 A)
- 在 70 元/MWh 的价格下,供给量为 250 MWh(发电厂 A + 发电厂 B)
- 在 90 元/MWh 的价格下,供给量为 450 MWh(发电厂 A + 发电厂 B + 发电厂 C)
当价格为 70 元/MWh 时,供给量正好等于需求量(250 MWh),因此市场出清价格为 70 元/MWh。可以发现,发电厂C由于过高的价格竞标失败,导致没有卖出任何电力,最终只能亏本卖出,所以表格中部分电价是负数值。因此
因此,市场上必然会存在部分公司定价与实际情况存在偏差的博弈行为。
4.baseline策略
读取数据并处理至符合最后的提交格式
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)
预处理,优化时间处理
# 将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)"]]
此时的表格:
timestamp | demand | clearing price (CNY/MWh) |
2021-12-01 00:15:00 | 40334.18 | 350.80 |
2021-12-01 00:30:00 | 40523.15 | 350.80 |
2021-12-01 00:45:00 | 40374.74 | 350.80 |
2021-12-01 01:00:00 | 40111.55 | 350.80 |
2021-12-01 01:15:00 | 40067.50 | 348.93 |
以煤耗量为成本价,进而类比报价信息(多数情况下,二者正相关)。按报价从低到高排序,依次接受报价,直到累计的功率超过了总需求,市场达到出清状态,并以最后一个满足的报价作为市场出清价格的估计。
sorted_unit = unit.sort_values("coal consumption (g coal/KWh)") # 按照一度电的耗煤量(近似为边际成本)降序排序
# 预先计算 sorted_unit 的累积和
sorted_unit['cumulative_capacity'] = sorted_unit['Capacity(MW)'].cumsum()
prices = []
# 找到最后一个满足总需求的机组报价
for demand in electricity_price["demand"]:
price = sorted_unit[sorted_unit['cumulative_capacity'] >= demand]["coal consumption (g coal/KWh)"].iloc[0]
prices.append(price)
由于这里耗煤量单位是g,虽然和成本正相关但不能等同于报价(事实上应该考虑煤价和其他固定资产开销成本)。由于不知道如何将耗煤量转为报价,因此简单地使用线性回归,拟合估计价格到真实市场出清价格。
model = LinearRegression()
# 55392为训练集的长度
train_length = 55392
prices = np.array(prices).reshape(-1, 1)
X = prices[:train_length]
y = electricity_price["clearing price (CNY/MWh)"].iloc[:train_length].values.reshape(-1, 1)
model.fit(X, y)
预测并保存
y_pred = model.predict(prices[train_length:])
y_pred = y_pred.flatten() # 2维矩阵转为1维
sample_submit["clearing price (CNY/MWh)"] = y_pred
sample_submit.to_csv("submit.csv", index=False)
5.实践感想
本次实践首先弄清楚了赛题和基本逻辑,并且在baseline的基础上,通过前馈神经网络拟合代替简单的线性回归,略提升了表现。
希望后续通过更好的回归策略及对ABM的深入研究,结合市场上复杂的报价策略,进一步提升模型效果。