XGBoost
极端梯度提升(Extreme Gradient Boosting,XGBoost,有时候也直接叫做XGB)和GBDT类似,也会定义一个损失函数。不同于GBDT的是只会用到一阶导数信息,XGBoost会利用泰勒展开式把损失函数展开到二阶之后求导,利用了二阶导数信息,这样在训练集上的收敛就会更快
参数介绍
主要参数 | 解释 |
---|
max_depth | 数的最大深度,一般值为【3,4,5】 | gamma | 学习速率,决定收敛速率以及正确率 | subsample | 训练每棵树时所选样本占总训练集比例 | colsample_bytree | 训练每棵树时所选特征占据总体特征比例 | n_estimators | 迭代次数(树的数量) | min_child_weight | 最小叶子节点样本权重和,值越大泛化能力越强 |
项目实战(股票风险走势预测)
方法讨论
其实针对这个问题我知道的最好办法就是用LSTM循环神经网络去处理(但是毕竟我们在讲XGBoost,所以不要在意这些细节【狗头】)
利用XGBoost处理这类时间序列问题我能想到的有两种方法
-
将前几天的数据作为特征集,今天的股票close列作为标签,这种方法的优点就是准确率高,但是缺点也很明显, 他只能预测未来一天。。。。。。
-
用当天的股票数据作为特征,当天的close列作为标签,用来训练模型(就像咱们普通的回归预测一样),然后将所有选取的特征各自建立时间序列模型,预测他们未来几天的数据,然后将该数据作为特征集,用训练好的模型predict,得到的就是咱们要预测的未来几天的数据 ,这个方法的优点就是能够预测未来几天的数据嘿嘿,缺点就是正确率不如前者,往后预测的天数越多,误差越大,而且非常麻烦!(这里有一段非常凄惨的故事)
因为时间有限(其实是懒【狗头】),咱们今天用第一种方法来预测(其实是因为懒【狗头保命】)
利用tushare模块导入股票数据
import tushare as ts
#选取股票代码为600000的股票从2020年1月1日到2021年10月28日的数据
data=ts.get_k_data('600000',start='2020-01-01',end='2021-10-28')
#将数据保存到指定路径(不建议像我这样路径含有中文,血的教训呜呜呜)
#这种带有日期的数据建议储存到csv格式而不是excel格式,因为会乱码
data.to_csv(r'C:\Users\74581\OneDrive - xmu\桌面\600000.csv')
-
得到以下部分数据
import pandas as pd
#将日期设置为index,并且转化为datatime格式(时间序列里一定要转换!!!!)
data=pd.read_csv(r'C:\Users\74581\OneDrive - xmu\桌面\600000.csv',index_col='date',parse_dates=['date'])
?
data=data.drop(columns='code')
排除异常值
-
处理完数据的基本操作之后,我们得检查异常值,看看数据方面是否出了一些问题,如果出现了1000一股的数据我们还fit进了模型里,那可就糟糕了(血的教训嘤嘤嘤) -
我们可以先用describe函数直接构造 排除异常值 -
处理完数据的基本操作之后,我们得检查异常值,看看数据方面是否出了一些问题,如果出现了1000一股的数据我们还fit进了模型里,那可就糟糕了(血的教训嘤嘤嘤) -
我们可以先用describe函数直接构造 -
print(data.describe().loc[['min','max','mean'],:])#其实大概检测只要看这三个数据就行啦(菜鸡看法) -
? -
-
得到了以上的数据,最大值和最小值好像都没有差均值太多,也没有出现负值,说明这个数据还是没有什么问题的
数据特征处理
#数据特征处理
base1=data['close']
base2=data.shift(1)
base2.columns=[f'v{j}-1' for j in range(len(data.columns))]
base3=pd.concat([base1,base2],axis=1)
for i in range(2,7):
base4=data.shift(i)
base4.columns=[f'v{j}-{i}' for j in range(len(data.columns))]
base3=pd.concat([base3,base4],axis=1)
base3.dropna(inplace=True)
x=base3.drop(columns=['close'])
y=base3['close']
测试集,训练集的分割
from sklearn.preprocessing import StandardScaler‘
#数据分割
x_train,x_test=x.iloc[:int(len(x)*0.8),:],x.iloc[int(len(x)*0.8):,:]
y_train,y_test=y[:int(len(x)*0.8)],y[int(len(x)*0.8):]
特征选择
#数据特征处理
model1=XGBRegressor()
rfa=RFECV(model1,cv=5,scoring='neg_mean_absolute_error')
rfa.fit(x_train,y_train)
#特征权重数据可视化
plt.bar(x_train.columns,rfa.grid_scores_)
plt.show()
?
-
没有出现过拟合的现象,完美!
-
接下来选取最优特征就行啦!!
#特征选择
col_select=x_train.columns[rfa.support_]
x_train,x_test=x_train.loc[:,col_select],x_test.loc[:,col_select]
数据标准化
#数据标准化
from sklearn.preprocessing import StandardScaler
std=StandardScaler()
std.fit(x_train)
x_train_std,x_test_std=std.transform(x_train),std.transform(x_test)
模型调参
#模型调参
from sklearn.model_selection import GridSearchCV
params=dict(gamma=[0.1,0.5,0.7,0.05],min_child_weight=[1,3,5],subsample=[0.2,0.4,0.7],colsample_bytree=[0.2,0.4,0.7],n_estimators=[100,200,300],max_depth=[3,4,5])
model=GridSearchCV(XGBRegressor(),params,scoring='neg_mean_squared_error',n_jobs=5,cv=5)
模型拟合
#模型拟合
model.fit(x_train_std,y_train)
print(model.best_params_)
结果预测
#结果预测
from sklearn.metrics import mean_absolute_error
plt.plot(y_test.index,y_test,label='True')
y_pred=(model.predict(x_test_std)*0.7+model_.predict(x_test_std)*0.3)
plt.plot(y_test.index,y_pred,label='pred')
plt.title('mae:%.2f'%(mean_absolute_error(y_test,y_pred)))
gca=plt.gca()
mul=plt.MultipleLocator(45)
gca.xaxis.set_major_locator(mul)
plt.legend()
plt.show()
?
可以看到,在2021年7月2号左右的时候,股票数据比较平稳,模型预测情况也很理想,但是过了一段时间之后股市出现波动(我查阅了相关资料,据说是那段时间颁布了相关政策打击到了白酒行业,导致股票下跌,所以投资还是有风险呀),出现剧烈波动之后的数据预测情况就没有那么理想了,所以时间序列分析最理想的情况就是稳定的数据,像这种股票之类不太稳定的数据,就得用到我们的LSTM模型(个人觉得ARIMA有点过时,毕竟数据准备的时间成本太高了呜呜呜)。mae大概是0.19左右,对于股票预测分析来说,已经很好了,但是,能不能再降低一点呢,我们这里用Stacking聚合一下,看看能不能把mae再降低一点
#导入模型
from sklearn.ensemble import RandomForestRegressor,GradientBoostingRegressor,StackingRegressor
model1=RandomForestRegressor()
model2=GradientBoostingRegressor()
model3=XGBRegressor()
model4=StackingRegressor([('m1',model1),('m2',model3)],cv=5,n_jobs=10)
model4.fit(x_train_std,y_train)
#结果预测
from sklearn.metrics import mean_absolute_error
plt.plot(y_test.index,y_test,label='True')
y_pred=model4.predict(x_test_std)
plt.plot(y_test.index,y_pred,label='pred')
plt.title('mae:%.2f'%(mean_absolute_error(y_test,y_pred)))
gca=plt.gca()
mul=plt.MultipleLocator(45)
gca.xaxis.set_major_locator(mul)
plt.legend()
#置信区间
import scipy.stats as st
num=np.random.normal(loc=y_test.values,scale=np.ones(len(y_test))*0.1,size=(1000,len(y_test)))
l,u=st.t.interval(0.95,len(y_test)-1,loc=np.mean(num,axis=0),scale=np.std(num,axis=0))
plt.fill_between(y_test.index,l,u,alpha=0.4,color='r')
plt.show()
可以看到,我们这里mae下降了6个百分点,说明Stacking在这里还是挺有效的,其实事实上,我们还可以通过GridSearchCV对各个进行Stacking聚合的模型进行进一步调参,但是今天时间不太够【其实是我太懒,毕竟好麻烦qwq
?
模型的维护和预测
-
因为时间序列模型需要与时俱进不断迭代数据,所以建议建立好模型之后每隔一段时间再重新给模型拟合一批数据,这个时间根据自己直觉决定(我一般是半个月重新训练一次) -
再者,我们一定要保留建立模型时所选择的特征数据以及标准化数据,当我们需要调用建立的模型去预测的时候,需要先用这些数据去处理(千万不要直接上来就直接fit进模型) -
这个模型只适合预测未来一天的数据,所以想多预测几天的话,咱们就要用到第二种方法(有时间我也会分享出来嘿嘿) -
股市有风险,投资需谨慎。
结束
股票亏了千万不要来找我呜呜呜
|