GBDT+LR介绍
由ypyu创建,最终由qxiao 被浏览 296 用户
GBDT+LR策略理论和思路介绍
GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Regression Tree),是一种迭代的决策树算法,该算法由多棵决策树组成,所有树的结论累加起来做最终答案。它在被提出之初就和SVM一起被认为是泛化能力(generalization)较强的算法,它每棵树进行训练的对象都是上一颗树的残差。GBDT模型是非线性关系。 每一颗决策树都是由你输入一个样本开始,根据一定的准则(枝丫节点)将输入的样本给出最后的预测结果,而GBDT由多棵树组成,你输入一个样本,就会产生多组预测结果,这多组结果在GBDT+LR模型中就被用于作为一组新的解释变量。
LR(Logistic Regression)算法解决主要解决分类问题的判别概率问题。现在常用在垃圾邮件判别、推荐系统、疾病预测等场景中。一般用来判决某件 事情属于某个分类的概率来确定类别,但作为一个回归模型,它模型中的因变量和自变量之间的关系是线性的。
GBDT + LR 就是将通过GBDT的非线性模型组合生成的新的变量,再通过LR线性模型进行参数估计训练得出LR模型,然后用于预测;
具体示例如下: 下图是一个GBDT+LR 模型结构,设GBDT有两个弱分类器,分别以蓝色和红色部分表示,其中蓝色弱分类器的叶子结点个数为3,红色弱分类器的叶子结点个数为2,并且蓝色弱分类器中对0-1 的预测结果落到了第二个叶子结点上,红色弱分类器中对0-1 的预测结果也落到了第二个叶子结点上。那么我们就记蓝色弱分类器的预测结果为[0 1 0],红色弱分类器的预测结果为[0 1],综合起来看,GBDT的输出为这些弱分类器的组合[0 1 0 0 1] ,或者一个稀疏向量(数组)。
策略模块介绍和输出结果展示
如何将GBDT+LR 模型应用到股票价格预测上呢?股票模型往往有大量的特征,我们先用GBDT模型对特征进行筛选,转换后变成哑变量,然后通过这些哑变量来进行预测股票是涨是跌。
构建特征和数据标注
所谓特征的构建就是解释变量的选取,数据的标注就是被解释变量,在这里我们的解释变量均存储在m3输入特征列表中,我们通过m2自动标注数据进行数据标注,最后将两部分数据进行合并连接并对缺失值进行处理后我们得到了原始数据;
对于训练集数据我们这样进行数据准备,对于测试集数据我们准备得方法是同步的: 只不过在这里我们并没有将特征和标签按股票链接在一起;
模型的训练预测和评估
m4 m5 m6 三个自定义模块是用于模型的训练,预测和评估 如图所示,我们通过输入的左侧的训练集数据输入m4自定义模块进行模型的训练,训练出GBDT+LR模型的参数和决策树的权重节点; 将训练出的模型和预测集的特征数据分别输入到m5自定义模块的左右并通过模型进行预测 将预测出来的结果和m10数据输出的预测集的标签进行比对,以获得模型的评估;
模型评估部分我们输出如下数据,总的准确率0.4930
我们画出混淆矩阵和ROC Curve,用于对涨跌的精准度预测做更精细的展示,
以上模型的评估告诉我们我们的模型并不具有预测涨跌的效力,这主要是由输入的特征质量决定的。
交易与回测
根据该算法进行交易的收益与回测结果如下:尽管模型预测结果不好,但是预测成功的收益比预测失败的成本高,所以总的收益>0
策略代码分析
在最后一部分,我们对代码做出解析,便于大家的改写和优化:
(有兴趣看代码和中间结果展示的用户可以阅读以下内容) 模型训练部分
def bigquant_run(input_1, input_2, input_3):
# 包的加载
# Package loaded
import numpy as np
np.random.seed(10)
from sklearn.linear_model import LogisticRegression # 逻辑回归包
from sklearn.ensemble import GradientBoostingClassifier # GBDT包
from sklearn.preprocessing import OneHotEncoder # 存储分类结果的编辑器
from sklearn.model_selection import train_test_split # 划分预测集和训练集
from sklearn.pipeline import make_pipeline #做模型之间的链接
## 设置机器学习的参数,区分预测集和训练集
## Set parameters and load data
Data = input_1.read_df() #获取全部数据
# X 是我们的训练集特征,y是我们的顺序一致的标签,被解释变量
X = Data[input_2.read_pickle()]
y = pd.DataFrame(Data['label'])
#print(y.columns)
#print(X.columns)
n_estimator = 5
# 在这里我们实际上不需要做测试集和训练集的区分,因为本部分本来就是训练的部分
X_train = X
y_train = y
# 需要将对 LR和GBDT的训练集给区分开来,因为两个模型尽量不用交叉训练
# It is important to train the ensemble of trees on a different subset of the training data than the linear regression model to avoid overfitting, in particular if the total number of leaves is similar to the number of training samples
X_train, X_train_lr, y_train, y_train_lr = train_test_split(X_train, y_train, test_size=0.7)
# Supervised transformation based on gradient boosted trees
# 这里是训练好的模型,GBDT模型,编码模型和逻辑回归模型,建立三个模型对象
grd = GradientBoostingClassifier(n_estimators=n_estimator)
grd_enc = OneHotEncoder(categories='auto')
grd_lm = LogisticRegression(solver='lbfgs', max_iter=1000)
# 拟合数据,获取模型参数
grd.fit(X_train, y_train)
grd_enc.fit(grd.apply(X_train)[:, :, 0])
grd_lm.fit(grd_enc.transform(grd.apply(X_train_lr)[:, :, 0]), y_train_lr)
# 创建一个字典用来打包存储模型
Model = dict()
Model['grd'] = grd
Model['grd_enc'] = grd_enc
Model['grd_lm'] = grd_lm
T = DataSource.write_pickle(Model)
return Outputs(data_1=T, data_2=None, data_3=None)
这里创建了m2对象,存储着需要抓取的股票数据的信息,读取m2数据的结果如下图 (有兴趣看代码和中间结果展示的用户可以阅读以下内容 模型预测部分)
\
def bigquant_run(input_1, input_2, input_3):
# 三个模型从这个字典结构里面拿出来
Model = input_1.read_pickle()
# 获取已经训练好的模型
grd = Model['grd']
grd_enc = Model['grd_enc']
grd_lm = Model['grd_lm']
# 获取测试集的特征数据并预测
X_test = input_2.read_df()
X_test1 = X_test[input_3.read_pickle()]
y_pred_grd_lm = grd_lm.predict_proba(grd_enc.transform(grd.apply(X_test1)[:, :, 0]))[:, 1]
Y = pd.DataFrame(y_pred_grd_lm,columns=['prediction'])
Y['date'] = X_test['date']
Y['instrument'] = X_test['instrument']
Y = DataSource.write_df(Y)
return Outputs(data_1=Y, data_2=None, data_3=None)
(有兴趣看代码和中间结果展示的用户可以阅读以下内容 模型评价部分)
\
def bigquant_run(input_1, input_2, input_3):
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix
# 本部分的主要功能是对模型的预测效果进行分析
# 模型的真实值和模型的预测值分别读取
Data_pre = input_1.read_df()
Data_real = input_2.read_df()
# 将两个数据合并,并根据预测结果是否>0.5来判断涨跌标签
Data = pd.merge(Data_pre,Data_real,how='inner',on = ['date','instrument'])
Pred = np.where(Data['prediction']>0.5,1,0)
Real = np.array(Data['label'])
cm = confusion_matrix(Real, Pred)
cm_normalized = cm.astype('float')/cm.sum(axis=1)[:, np.newaxis]
print(cm_normalized)
import seaborn as sn
# 画出混淆矩阵
df_cm = pd.DataFrame(cm_normalized)
plt.figure(figsize = (15,10))
sn.heatmap(df_cm, annot=True)
print('准确率')
c = (Real == Pred)
print(len(c[c])/len(c))
print('预测涨结果涨')
P = Real[c]
L11 = len(P[P==1])
print(L11)
print('预测跌结果跌')
L00 = len(P[P==0])
print(L00)
print('预测涨结果跌')
L10 = len(Real[Real==0])-len(P[P==0])
print(L10)
print('预测跌结果涨')
L01 = len(Real[Real==1])-len(P[P==1])
print(L01)
print('\n')
print('查准率\n')
print('预测涨的准确率\n')
print(L11/(L11+L10))
print('预测跌的准确率\n')
print(L00/(L01+L00))
print('\n')
print('查全率\n')
print('涨的股票中预测准确率\n')
print(L11/(L11+L01))
print('跌的股票中预测准确率\n')
print(L00/(L00+L10))
from sklearn.metrics import roc_curve
fpr_grd_lm, tpr_grd_lm, _ = roc_curve(Real, Pred)
plt.figure()
plt.plot(fpr_grd_lm, tpr_grd_lm, label='GBT')
plt.xlabel('False positive rate')
plt.ylabel('True positive rate')
plt.title('ROC curve')
plt.legend(loc='best')
plt.show()
return Outputs(data_1=DataSource.write_pickle(Real), data_2=DataSource.write_pickle(Pred), data_3=None)
\
策略案例1
https://bigquant.com/experimentshare/daeefd42c3e64cfaa9725c72dfc2efcb
策略案例2
https://bigquant.com/experimentshare/cf4efb929b9648eab04da842cadd0854
\