说明: 这里再百度的 Codelab 上面运行的话会很慢,我在Deepln 上面运行的。虽然它是个跑深度学习的平台。
一、对于数据简单的了解
需要导入的库:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import lightgbm as lgb
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline
from sklearn.metrics import mean_squared_error
sns.set(style='white', context='notebook', palette='deep')
操作的代码:
# 获取 df 中的一些基本信息
def get_cols_info(df):
print(f"df 数据集中有 {df.shape[0]} 个样本值。")
for col in df.columns:
print(f"{col} 中有 {df[col].nunique()} 个不同值, 有 {df[col].isnull().sum()} 个缺失值。")
# 获取 trian 中的基本信息
get_cols_info(train)
print(" ----------\|/----------")
# 获取 test 中的基本信息
get_cols_info(test)
运行结果如下:
可以看到,train 和 test 的 id 这一列都 5832 个不同值,那我们应该是根据每个 id 在训练集给定的结果去预测测试集中的结果。
二、对于特征 type 的简单探索
type 代表的房屋类型,根据常识可知不同的房屋类型对于电力的消耗肯定是不同的。
2.1 对于 type 的简单统计操作:
操作代码:
train['type'].value_counts()
运行结果:
这里我们统计的是不同的房屋类型在训练集中的数目。使用的是 pandas 中的 ```value_counts()```函数。
2.2, 对于 type 的更进一步探索
操作代码:
### 查看不同房屋类型对应的 target 的一些属性
agg_results = train.groupby('type')['target'].agg(
mean='mean',
max='max',
min='min',
std='std',
count='size'
)
# 显示结果
agg_results
运行结果:
这里我们统计了不同类型房屋对应的 target 的值对应的均值、最大值、最小值、方差和总数。可以看到不同房屋对应的的 target 均值不同,有的最大值和最小值相差还比较大,这里可以理解,毕竟每种 type 可能对应着很多不同的 id。
三、特征工程
3.1 根据 task2 对应的教程进行
3.1.1 首先将训练集测试集合并:
# 合并训练集和测试集
data = pd.concat([train, test], axis=0, ignore_index=True)
data = data.sort_values(['id', 'dt'], ascending=False).reset_index(drop=True)
3.1.2
# 历史平移
for i in range(10, 30):
data[f"last{i}_target"] = data.groupby(['id'])['target'].shift(i)
# 窗口统计
data[f"win3_mean-target"] = (data['last10_target'] + data['last11_target'] + data['last12_target']) / 3
3.2. 这里简单进行拓展
3.2.1 做一些统计特征:
window_columns = [f"last{i}_target" for i in range(10, 16)] # 选择过去6个时间步
# 计算均值
data[f"win3_mean_target"] = data[window_columns].mean(axis=1)
# 计算最大值
data['win3_max_target'] = data[window_columns].max(axis=1)
# 计算最小值
data['win3_min_target'] = data[window_columns].min(axis=1)
# 计算标准差
data['win3_std_target'] = data[window_columns].std(axis=1)
# 计算中位数
data['win3_median_target'] = data[window_columns].median(axis=1)
3.2.2 计算滚动窗口均值和指数加权均值特征
def calculate_features(data):
result = data.copy()
batch_ids = data['id'].unique()
for batch_id in batch_ids:
# 按ID筛选数据
chunk = data[data['id'] == batch_id].copy()
# 计算滚动窗口均值和指数加权均值
chunk[f"win10_mean_target"] = chunk['target'].rolling(10).mean().shift(10)
chunk[f"ewm10_target"] = chunk['target'].ewm(span=13).mean().shift(10)
# 更新原始 DataFrame
result.loc[result['id'] == batch_id, [f"win10_mean_target", f"ewm10_target"]] = chunk[[f"win10_mean_target", f"ewm10_target"]]
return result
这里:
1. win10_mean_target
: target
列的滚动窗口(窗口大小为10)的均值,并向前移动10个位置。
2. ewm10_target
: target
列的指数加权移动平均值(跨度为13),并向前移动10个位置。
这一步也可以多尝试不同的窗口大小。这一步是很费时间的,运行时间比较长,目前正在想有什么办法能够减少计算的时间。
四、 划分数据集并且使用 Lightgbm 训练
4.1 划分数据集
操作代码:
train = data[data.target.notnull()].reset_index(drop=True)
test = data[data.target.isnull()].reset_index(drop=True)
# 确定输入特征
train_cols = [f for f in data.columns if f not in ['id','target']]
4.2 使用 Lightgbm 训练
操作代码:
import lightgbm as lgb
from sklearn.metrics import mean_squared_error
def time_model(lgb, train_df, test_df, cols):
# 训练集和验证集切分
trn_x, trn_y = train_df[train_df.dt>=31][cols], train_df[train_df.dt>=31]['target']
val_x, val_y = train_df[train_df.dt<=30][cols], train_df[train_df.dt<=30]['target']
# 构建模型输入数据
train_matrix = lgb.Dataset(trn_x, label=trn_y)
valid_matrix = lgb.Dataset(val_x, label=val_y)
# lightgbm参数
lgb_params = {
'boosting_type': 'gbdt',
'objective': 'regression',
'metric': 'mse',
'min_child_weight': 5,
'num_leaves': 2 ** 5,
'lambda_l2': 10,
'feature_fraction': 0.8,
'bagging_fraction': 0.8,
'bagging_freq': 8,
'learning_rate': 0.05,
'seed': 2024,
'nthread' : -1,
'verbose' : -1,
'n_jobs': 64,
'early_stopping_rounds': 500,
}
# 训练模型
model = lgb.train(lgb_params, train_matrix, 25000, valid_sets=[train_matrix, valid_matrix],
categorical_feature=[])
# 验证集和测试集结果预测
val_pred = model.predict(val_x, num_iteration=model.best_iteration)
test_pred = model.predict(test_df[cols], num_iteration=model.best_iteration)
# 离线分数评估
score = mean_squared_error(val_pred, val_y)
print(score)
return val_pred, test_pred
lgb_oof, lgb_test = time_model(lgb, train1, test1, train_cols)
# 保存结果文件到本地
test['target'] = lgb_test
test[['id','dt','target']].to_csv('submit1.csv', index=None)
这里我稍微改了几个参数,而且这一步训练模型,在百度的 Codelab 上面训练的好久都没训练出来,我在 Deepln 上面训练的,训练了大概8分钟左右就完成了,结果我忘了保存训练参数了,直接就拿 submit1.csv 提交了。
这是提交的成绩:
五、改进于反思的地方
1. 对于特征工程这一部分,还需要去了解更多的关于时间序列方面的别的做法,而且得益于 Lightgbm 我没有去处理缺失值,下面可以试着填充缺失值。
2. 对于模型,还可以去尝试 Xgboost、catboost。使用深度学习的方法去预测,这里我持否定的态度,因为每个 id 下对应的 dt 最多才有496 个。
3. 还需要去了解更多模型的细节,以及如何知道模型训练的程度和 tqdm 库的使用。
完结。