Datawhale AI 夏令营机器学习笔记
电力预测赛道
耶耶!第一期AI夏令营结束,收获了很多,所以报名了第二期继续学习。
这是我第一次做时间序列的数据预测,又可以学习新知识喽!
当然还有其他赛道,有余力的同学就同时报名好几个赛道,我就先只报一个赛道学习啦!学新知识总是令人无比地兴奋!
如果有想参加的可以私信我报名
有什么疑问可以评论区互相交流讨论呀,share你的最佳分数!
赛题思考
- 阅读赛题要求 核心:给定多个房屋对应电力消耗历史N天的相关序列数据,预测房屋对应电力的消耗,以MSE作为衡量标准。
- 下载数据 查看数据
train = pd.read_csv('./data/data283474/train.csv')
test = pd.read_csv('./data/data283474/test.csv')
submit = pd.read_csv('./data/data283474/sample_submit.csv')print(train)print(test)print(submit)
输出
观察数据
可以发现是做连续值预测
提交文件格式也很清楚
然后我们在具体看看train数据一些值
从id这列数据,可以发现,不同id有不一样长度的时间序列数据
总5832个样本,大部分id是496条数据,最多是506条
其他列包括test数据也可以稍微通过这种统计去观察数据形式
3. 先套个机器学习方法跑一下
# 1. 导入需要用到的相关库import pandas as pd
from lightgbm import LGBMRegressor
# 2. 读取训练集和测试集
train = pd.read_csv('./data/data283474/train.csv')
test = pd.read_csv('./data/data283474/test.csv')# 3. 检查数据for col in train.columns[:-1]:if train[col].dtype ==objector test[col].dtype ==object:
train[col]= train[col].isnull()
test[col]= test[col].isnull()# 4. 加载决策树模型进行训练
model = LGBMRegressor(verbosity=-1)
model.fit(train.iloc[:,:-1].values, train['target'])
pred = model.predict(test.values)# 5. 保存结果文件到本地
pd.DataFrame({'id': test['id'],'dt': test['dt'],'target': pred
}).to_csv('LGBMRegressor.csv', index=None)
提交后七百多分哈哈哈哈
但不知道为什么跑出来是同一个房屋的预测值是一样的
既然如此那还不如直接取均值呢
所以就取均值看看
import pandas as pd
# 读取数据
train = pd.read_csv('./data/data283474/train.csv')
test = pd.read_csv('./data/data283474/test.csv')# 计算train中每个id对应的target的平均值
id_to_mean_target = train.groupby("id")["target"].mean().reset_index()# 将平均值与test数据集合并
test_with_pred = test.merge(id_to_mean_target, on="id", suffixes=("","_pred"))# 以指定格式保存预测结果到CSV文件
result = pd.DataFrame({'id': test_with_pred['id'],'dt': test_with_pred['dt'],'target': test_with_pred['target']})
result.to_csv('clq_mean.csv', index=False)
提交上去后分数确实也有所提升
后续又改了一些别的方法,XGB什么的,效果不行
所以觉得应该用时序特征一些处理方法
import pandas as pd
import numpy as np
from sklearn.metrics import mean_squared_error
from lightgbm import LGBMRegressor
import lightgbm as lgb
import matplotlib.pyplot as plt
from prophet import Prophet
# 读取数据
train = pd.read_csv('./data/data283474/train.csv')
test = pd.read_csv('./data/data283474/test.csv')# 数据预处理
train['dt']= pd.to_datetime(train['dt'],format='%Y%m%d')
train = train.sort_values('dt')# 特征工程deffeature_engineering(df):
df['year']= df['dt'].dt.year
df['month']= df['dt'].dt.month
df['day']= df['dt'].dt.day
df['weekday']= df['dt'].dt.weekday
return df
train = feature_engineering(train)
test = feature_engineering(test)# 使用Prophet提取特征defextract_prophet_features(df):
df = df[['dt','target']]
df.columns =['ds','y']
model = Prophet()
model.fit(df)
future = model.make_future_dataframe(periods=0, freq='D')
forecast = model.predict(future)return forecast[['ds','yhat','yhat_lower','yhat_upper']].tail()
train_prophet_features = extract_prophet_features(train)
test_prophet_features = extract_prophet_features(test)# 合并特征
train = pd.merge(train, train_prophet_features, left_on='dt', right_on='ds', how='left')
train = train.drop(columns=['ds'])
test = pd.merge(test, test_prophet_features, left_on='dt', right_on='ds', how='left')
test = test.drop(columns=['ds'])# 训练LightGBM模型
lgbm = LGBMRegressor()
lgbm.fit(train.drop(columns=['target','id','type']), train['target'])# 预测
predictions = lgbm.predict(test.drop(columns=['id','type']))# 计算MSE
mse = mean_squared_error(test['target'], predictions)print('MSE:', mse)
由于不了解这个方法,还有不清楚时序特征一般怎么处理
我就先放着了,坐等官方baseline学习学习
Baseline尝试
无比丝滑!
核心idea是计算训练数据最近11-20单位时间内对应id的目标均值
Task2尝试
画个图观察目标数据,直观多了
原来还能这么观察数据呢
学到了
重点学习特征工程
历史平移特征、差分特征、和窗口统计特征
- 历史平移特征:通过历史平移获取上个阶段的信息;如下图所示,可以将d-1时间的信息给到d时间,d时间信息给到d+1时间,这样就实现了平移一个单位的特征构建。
- 差分特征:可以帮助获取相邻阶段的增长差异,描述数据的涨减变化情况。在此基础上还可以构建相邻数据比值变化、二阶差分等;
- 窗口统计特征:窗口统计可以构建不同的窗口大小,然后基于窗口范围进统计均值、最大值、最小值、中位数、方差的信息,可以反映最近阶段数据的变化情况。如下图所示,可以将d时刻之前的三个时间单位的信息进行统计构建特征给我d时刻。 跑通task2
优化方向
还有一些可以考虑的优化点来降低MSE:
- 特征工程:- 考虑添加更多的时间序列特征,如滚动均值、滚动标准差、滚动中位数等。- 尝试不同的窗口大小,不仅仅是3天的窗口。- 添加趋势特征,如前n天的斜率。- 考虑添加周期性特征,如星期几、月份等。
- 模型调优:- 使用网格搜索或随机搜索来优化LightGBM的超参数。- 尝试其他模型,如XGBoost、CatBoost,或者尝试模型集成。
- 交叉验证:- 实现时间序列交叉验证,而不是简单的训练-验证集分割。
- 处理异常值和缺失值:- 检查并处理可能的异常值。- 考虑更复杂的缺失值填充方法。
- 特征选择:- 使用特征重要性来选择最相关的特征。
- 目标变量转换:- 尝试对目标变量进行对数转换或其他转换,可能会改善模型性能。
- 增加历史数据:- 如果可能,尝试使用更多的历史数据来创建特征。
- 差分特征:- 考虑添加差分特征,捕捉变化率。
- 调整学习率:- 尝试使用学习率衰减策略。
- 增加迭代次数:- 可能需要增加
early_stopping_rounds
和最大迭代次数。 - 尝试不同的评估指标:- 除了MSE,也可以尝试RMSE或MAE作为评估指标。
- 数据归一化:- 对某些特征进行归一化处理可能会有帮助。
具体的代码示例。需要逐步实施并评估效果。
- 增加更多的时间序列特征:
# 添加更多的滚动统计特征for window in[3,7,14,30]:
data[f'rolling_mean_{window}']= data.groupby('id')['target'].rolling(window=window).mean().reset_index(0,drop=True)
data[f'rolling_std_{window}']= data.groupby('id')['target'].rolling(window=window).std().reset_index(0,drop=True)
data[f'rolling_median_{window}']= data.groupby('id')['target'].rolling(window=window).median().reset_index(0,drop=True)# 添加趋势特征
data['trend']= data.groupby('id')['target'].diff(periods=1)# 添加周期性特征
data['day_of_week']= pd.to_datetime(data['dt']).dt.dayofweek
data['month']= pd.to_datetime(data['dt']).dt.month
- 特征选择:
from sklearn.feature_selection import SelectKBest, f_regression
defselect_features(X, y, k=20):
selector = SelectKBest(score_func=f_regression, k=k)
selector.fit(X, y)
cols = selector.get_support(indices=True)return X.columns[cols].tolist()# 在模型训练之前使用
selected_features = select_features(train[train_cols], train['target'])
train_cols = selected_features
- 目标变量转换:
import numpy as np
train['target_log']= np.log1p(train['target'])
test['target_log']= np.log1p(test['target'])# 在预测后需要进行逆变换
test['target']= np.expm1(lgb_test)
- 实现时间序列交叉验证:
from sklearn.model_selection import TimeSeriesSplit
deftime_series_cv(clf, train_df, test_df, cols, n_splits=5):
oof = np.zeros(len(train_df))
predictions = np.zeros(len(test_df))
tscv = TimeSeriesSplit(n_splits=n_splits)for fold,(train_index, val_index)inenumerate(tscv.split(train_df)):print(f"Fold {fold +1}")
trn_x, trn_y = train_df.iloc[train_index][cols], train_df.iloc[train_index]['target']
val_x, val_y = train_df.iloc[val_index][cols], train_df.iloc[val_index]['target']
train_matrix = clf.Dataset(trn_x, label=trn_y)
valid_matrix = clf.Dataset(val_x, label=val_y)
model = clf.train(lgb_params, train_matrix,50000, valid_sets=[train_matrix, valid_matrix],
categorical_feature=[], verbose_eval=500, early_stopping_rounds=500)
oof[val_index]= model.predict(val_x, num_iteration=model.best_iteration)
predictions += model.predict(test_df[cols], num_iteration=model.best_iteration)/ n_splits
score = mean_squared_error(oof, train_df['target'])print(f"Overall MSE: {score}")return oof, predictions
lgb_oof, lgb_test = time_series_cv(lgb, train, test, train_cols)
- 调整LightGBM参数:
from sklearn.model_selection import RandomizedSearchCV
from sklearn.model_selection import TimeSeriesSplit
param_dist ={'num_leaves':[31,127],'max_depth':[-1,5,8],'learning_rate':[0.01,0.1],'n_estimators':[100,1000],'min_child_samples':[5,10,20],'subsample':[0.6,0.8,1.0],'colsample_bytree':[0.6,0.8,1.0],}
tscv = TimeSeriesSplit(n_splits=5)
lgb_model = lgb.LGBMRegressor(random_state=42)
random_search = RandomizedSearchCV(lgb_model, param_distributions=param_dist,
n_iter=100, cv=tscv, verbose=1,
scoring='neg_mean_squared_error', n_jobs=-1)
random_search.fit(train[train_cols], train['target'])print("Best parameters found: ", random_search.best_params_)print("Best MSE found: ",-random_search.best_score_)# 使用最佳参数更新lgb_params
lgb_params.update(random_search.best_params_)
这些优化应该能帮助改善模型性能。但是要逐步实施这些更改,并在每一步评估其对模型性能的影响。同时,要注意避免过拟合,确保模型在测试集上的表现也有相应的提升。
我自己先进一步尝试,等有好的结果再继续写本帖
这是目前我的成绩
任何好的结果都不是一蹴而就的
唯有一次次不断的尝试,总结,提高,才能不断地突破,超越自己
进阶尝试
- 首先,我尝试寻找lgbm的最佳参数
但我try了五六次,都因为超过平台负荷而终止
一开始是500fits至少跑三四个小时都没跑下来
后来改成50fits也没跑下来
所以就手动调参吧!分数有一定提高的
试试别的优化方法先。
可以看到手动调参,因为我缺乏经验,只能瞎调,而且非常耗费时间,效果只提高了一点点
- 增加特征 感觉这个效果应该会很不错 好吧结果效果特别差,一千多分呢
- 交叉验证 浅浅提升了三分 三分也是爱啊 就这样,我继续优化吧! 后面我跑了三折交叉和五折 三折效果太差了 我又重新换回之前的参数 发现五折分数有所提高 所以有一定变动,我们参数不断调整还是可以使得结果有一定改善 当然我们微调参数这一步可能来说没有太大优化空间了 下一步要思考的可以显著提高分数的,可以做一些特征工程优化,正则化 持续更新,今天的提交次数达到上限啦!期待分享交流会大佬们分享进阶方法
感悟
非常开心
参考
参考了官方文档
[1]: https://mp.weixin.qq.com/s/d7dXGYnF4NZuuazktK4SXQ
[2]: https://mp.weixin.qq.com/s/2-V1kFbSzi3Z5UJ7GV_WBw
[3]: https://mp.weixin.qq.com/s/KeD9kPG8PowlKrz69zSHNQ
[4]: https://mp.weixin.qq.com/s/4NSVh1HniNT4CGakzHxm1w
[5]: https://mp.weixin.qq.com/s/JY9RcZ-EquNWdT5k6tLEWg
[6]: https://book.douban.com/subject/35595757/
[7]: https://zhuanlan.zhihu.com/p/67832773
版权归原作者 chrisleequeen 所有, 如有侵权,请联系我们删除。