基于第二届世界科学智能大赛社会科学赛道:市场博弈和价格预测
数据加载与预处理
base_path = Path("data") # 确保数据都放在同级的data目录下
# 读取市场数据
electricity_price = pd.read_csv(base_path / "electricity price.csv")
# 读取市场主体(各发电机组)数据
unit = pd.read_csv(base_path / "unit.csv")
解析:
base_path = Path("data")
: 定义了一个路径变量base_path
指向"data"目录,确保所有的数据文件都位于这个目录下。pd.read_csv(base_path / "electricity price.csv")
: 使用pandas
的read_csv
函数读取名为"electricity price.csv"的CSV文件,并将数据存储在名为electricity_price
的DataFrame对象中。pd.read_csv(base_path / "unit.csv")
: 类似地,读取名为"unit.csv"的CSV文件,并将数据存储在名为unit
的DataFrame对象中。
知识点:
- 路径操作: 使用
pathlib.Path
来处理文件路径,这提供了更现代和跨平台的方式来处理文件路径。 - 数据加载:
pandas
库中的read_csv
函数用于加载CSV文件中的数据,并将其转换为DataFrame对象,便于后续的数据处理和分析。
创建示例提交文件
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)
解析:
electricity_price["clearing price (CNY/MWh)"].isna()
: 选择electricity_price
DataFrame中"clearing price (CNY/MWh)"列中值为NaN(缺失值)的行。.drop(columns="demand")
: 删除这些行中的"demand"列。sample_submit.to_csv(base_path / "sample_submit.csv", index=False)
: 将处理后的DataFrame保存为CSV文件,文件名为"sample_submit.csv",并且不包含索引列。
知识点:
- 缺失值处理: 使用
isna()
函数来选择缺失值,这对于电力市场的预测任务很重要,因为我们需要预测缺失的出清价格。 - 数据子集: 通过
.drop(columns="demand")
选择DataFrame的子集,删除不需要的列。 - CSV文件保存: 使用
to_csv
函数保存DataFrame为CSV文件,这是一个常见的数据输出方式。
时间特征处理
electricity_price["timestamp"] = pd.to_datetime(
electricity_price["day"] + " " + electricity_price["time"].str.replace("24: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)
electricity_price = electricity_price[["timestamp", "demand", "clearing price (CNY/MWh)"]]
解析:
pd.to_datetime(electricity_price["day"] + " " + electricity_price["time"].str.replace("24:00:00", "00:00"))
: 将"day"和"time"列合并成一个时间戳格式的列,同时将"24:00:00"替换为"00:00",以确保时间戳的正确性。mask = electricity_price['timestamp'].dt.time == pd.Timestamp('00:00:00').time()
: 创建一个布尔掩码,用于标识那些时间戳为"00:00:00"的行。electricity_price.loc[mask, 'timestamp'] += pd.Timedelta(days=1)
: 对于所有时间戳为"00:00:00"的行,将时间戳增加一天。electricity_price = electricity_price[["timestamp", "demand", "clearing price (CNY/MWh)"]]
: 重新组织DataFrame,只保留"timestamp"、"demand"和"clearing price (CNY/MWh)"这三列。
知识点:
- 时间戳转换: 使用
pd.to_datetime
函数将日期和时间字符串转换为时间戳格式,这对于时间序列分析至关重要。 - 时间处理: 使用
pd.Timestamp
和pd.Timedelta
处理特殊时间点(如"24:00:00"),确保时间连续性。 - DataFrame列选择: 使用
DataFrame
的列名选择特定的列,这是数据清洗和预处理中的常见操作。
特征构造与排序
sorted_unit = unit.sort_values("coal consumption (g coal/KWh)")
sorted_unit['cumulative_capacity'] = sorted_unit['Capacity(MW)'].cumsum()
解析:
unit.sort_values("coal consumption (g coal/KWh)")
: 按照"coal consumption (g coal/KWh)"列的值对unit
DataFrame进行升序排序。sorted_unit['cumulative_capacity'] = sorted_unit['Capacity(MW)'].cumsum()
: 计算累积容量,即将"Capacity(MW)"列的值进行累加,得到每个发电机组累计的容量。
知识点:
- 排序: 使用
sort_values
函数对DataFrame进行排序,这对于电力市场的分析非常重要,因为出清价格通常与发电成本有关。 - 累积和: 使用
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)
解析:
- 循环遍历
electricity_price
DataFrame中的"demand"`列:sorted_unit[sorted_unit['cumulative_capacity'] >= demand]
: 对于每个需求值,找到能够满足该需求的最小累积容量的发电机组。["coal consumption (g coal/KWh)"].iloc[0]
: 获取第一个满足条件的发电机组的耗煤量,作为该需求水平下的价格。prices.append(price)
: 将计算出的价格添加到prices
列表中。
知识点:
- 需求匹配: 通过遍历电力需求,找到能够满足该需求的最小耗煤量发电机组,将其耗煤量作为价格。这一步骤利用了电力市场的基本原理之一:边际成本定价。
- 循环: 使用Python的
for
循环来迭代DataFrame中的行,这是一种常见的数据处理技术。
模型训练与预测
from sklearn.ensemble import GradientBoostingRegressor
model = GradientBoostingRegressor(
n_estimators=100, learning_rate=0.1, random_state=42)
model.fit(X, y)
解析:
from sklearn.ensemble import GradientBoostingRegressor
: 导入GradientBoostingRegressor
类,这是Scikit-Learn库中的一个梯度提升回归器模型,比原版的线性回归更有效。- 初始化模型:
n_estimators=100
: 指定模型中决策树的数量为100。learning_rate=0.1
: 指定模型的学习率为0.1,这影响了每次迭代时模型更新的程度。random_state=42
: 设置随机种子为42,以确保结果的可重复性。
model.fit(X, y)
: 使用X
(特征矩阵)和y
(目标向量)来训练模型。
知识点:
-
梯度提升回归算法: 一种机器学习模型,可以捕捉复杂的关系,并且不需要复杂的特征工程。它通过构建多个弱学习器(通常是决策树)并结合它们的结果来提高整体预测性能。
梯度提升回归树(Gradient Boosting Regression Trees,简称GBRT或GBR)是一种迭代的回归算法,属于集成学习方法,主要用于解决回归问题。它通过构建一系列的弱学习器(通常是决策树),然后将这些弱学习器组合起来形成一个强学习器。GBRT的工作原理是基于梯度下降的概念,它通过最小化损失函数的梯度来构建每棵树,以逐渐减小预测误差。- -
算法流程如下:
假设我们有一个损失函数 L ( y , F ( x ) ) L(y, F(x)) L(y,F(x)),其中 y y y是真实值, F ( x ) F(x) F(x)是模型的预测值。GBRT的目标是最小化损失函数的期望值。
在第(m)轮迭代中,我们已经有了一组弱学习器 { T 1 ( x ) , T 2 ( x ) , … , T m − 1 ( x ) } \{T_1(x), T_2(x), \ldots, T_{m-1}(x)\} {T1(x),T2(x),…,Tm−1(x)},并构建了预测函数 F ( m − 1 ) ( x ) = ∑ k = 1 m − 1 γ k T k ( x ) F^{(m-1)}(x) = \sum_{k=1}^{m-1} \gamma_k T_k(x) F(m−1)(x)=∑k=1m−1γkTk(x),其中 γ k \gamma_k γk是每个弱学习器的权重。
在第(m)轮,我们想要找到一个新的弱学习器 T m ( x ) T_m(x) Tm(x)和权重 γ m \gamma_m γm,使得损失函数 L ( y , F ( m ) ( x ) ) L(y, F^{(m)}(x)) L(y,F(m)(x))最小化,其中 F ( m ) ( x ) = F ( m − 1 ) ( x ) + γ m T m ( x ) F^{(m)}(x) = F^{(m-1)}(x) + \gamma_m T_m(x) F(m)(x)=F(m−1)(x)+γmTm(x)。
为了找到 T m ( x ) T_m(x) Tm(x)和 γ m \gamma_m γm,我们使用梯度下降的思想。具体来说,我们找到一个函数 h m ( x ) h_m(x) hm(x)来近似损失函数关于 F ( m − 1 ) ( x ) F^{(m-1)}(x) F(m−1)(x)的负梯度:
h
m
(
x
)
≈
−
[
∂
L
(
y
i
,
F
(
x
i
)
)
∂
F
(
x
i
)
]
F
(
x
)
=
F
(
m
−
1
)
(
x
)
h_m(x) \approx -\left[\frac{\partial L(y_i, F(x_i))}{\partial F(x_i)}\right]_{F(x)=F^{(m-1)}(x)}
hm(x)≈−[∂F(xi)∂L(yi,F(xi))]F(x)=F(m−1)(x)
然后,我们将
h
m
(
x
)
h_m(x)
hm(x)作为目标来构建决策树
T
m
(
x
)
T_m(x)
Tm(x)。一旦
T
m
(
x
)
T_m(x)
Tm(x)构建完成,我们可以通过线性搜索找到最佳的
γ
m
\gamma_m
γm,使得
L
(
y
,
F
(
m
)
(
x
)
)
L(y, F^{(m)}(x))
L(y,F(m)(x))最小化。
最终的预测函数为:
F ( x ) = F ( 0 ) ( x ) + ∑ m = 1 M γ m T m ( x ) F(x) = F^{(0)}(x) + \sum_{m=1}^M \gamma_m T_m(x) F(x)=F(0)(x)+m=1∑MγmTm(x)
其中 F ( 0 ) ( x ) F^{(0)}(x) F(0)(x)是初始预测值, M M M是弱学习器的总数。
- 模型参数:
n_estimators
、learning_rate
和random_state
是梯度提升回归器的重要参数,它们决定了模型的复杂性和随机性。 - 模型训练: 使用
fit
方法来训练模型,这是机器学习中常见的步骤。
预测与结果输出
y_pred = model.predict(prices[train_length:])
y_pred = y_pred.flatten()
sample_submit["clearing price (CNY/MWh)"] = y_pred
sample_submit.head()
sample_submit.to_csv("submit.csv", index=False)
解析:
model.predict(prices[train_length:])
: 使用训练好的模型对测试集中的数据进行预测。y_pred.flatten()
: 将预测结果转换为一维数组。sample_submit["clearing price (CNY/MWh)"] = y_pred
: 将预测的价格添加到samples_submit
数据框中。sample_submit.head()
: 显示samples_submit
数据框的前几行。sample_submit.to_csv("submit.csv", index=False)
: 将samples_submit
数据框保存为CSV文件,文件名为"submit.csv",并且不包含索引列。
知识点:
- 模型预测: 使用训练好的模型对新的数据进行预测,这是机器学习的核心应用之一。
- 结果输出: 使用
to_csv
函数将预测结果保存为CSV文件,以便提交给比赛平台。