目录

1、随机森林模型的基本原理和代码实现

(1)集成模型简介

1、Bagging算法

1、Boosting算法

(2)随机森林模型的基本原理

2、量化金融 - 股票数据获取

(1)股票基本数据获取

(2)Tushare库的基本介绍

1、获得日线行情数据

2、想调取超过3年的日线级别数据

3、获得分钟级别的数据

4、获得分笔数据

5、获得指数信息

(3)股票衍生变量生成

1、生成股票基本数据

2、简单衍生变量的计算

3、移动平均线指标MA值

3、量化金融 - 股票涨跌预测模型搭建

(1)多因子模型搭建

1、引入需要用到的库

2、股票数据处理与衍生变量生成

3、特征变量和目标变量提取

4、训练集和测试集数据划分

5、模型搭建

(2)模型使用与评估

1、预测下一天的涨跌情况

2、分析数据特征的重要性

(3)参数调优

(4)收益回测曲线绘制


1、随机森林模型的基本原理和代码实现

(1)集成模型简介

       集成学习模型是机器学习非常重要的一部分。集成学习是使用一系列的弱学习器(或称之为基础模型)进行学习,并将各个弱学习器的结果进行整合从而获得比单个学习器更好的学习效果的一种机器学习方法。

       集成学习模型有两种常见的算法:

Bagging 算法 的典型机器学习模型为本章所讲的随机森林模型
Boosting 算法 的典型机器学习模型则为下两章会讲到的 AdaBoost GBDT XGBoost LightGBM 模型。
1、Bagging算法

       Bagging的想法是采用类似于“民主投票”的方式,即每一个基础模型都有一票,最终结果通过所有基础模型投票,少数服从多数的原则产生预测结果。

       原理:从原始训练数据中(假设共有10000条数据),随机有放回地抽取10000次数据构成一个新的数据集(因为是随机有放回抽样,所以可能出现某一条数据多次被抽中,也有可能某一条数据一次也没有被抽中),每次使用一个训练样本训练一个基础模型。这样进行有放回的随机抽取n次后,训练结束时我们就能获得n个由不同的数据集训练的基础模型,也称之为n个弱学习器,根据这n个弱学习器的结果,我们可以获得一个更加准确合理的结果。

1、Boosting算法

       Boosting算法的本质是将弱学习器提升为强学习器,它和Bagging的区别在于,Bagging对待所有的基础模型一视同仁。而Boosting则做到了对于基础模型的“区别对待”,通俗来讲,Boosting算法注重“培养精英”和“重视错误”。“培养精英”,即每一轮对于预测结果较为准确的基础模型,会给予它一个较大的权重,表现不好的基础模型则会降低它的权重。这样在最终预测时,“优秀模型”的权重是大的,相当于它可以投出多票,而“一般模型”只能在投票时投出一票或不能投票。“重视错误”,即在每一轮训练后改变训练数据的权值或概率分布,通过提高那些在前一轮被基础模型预测错误样例的权值,减小前一轮预测正确样例的权值,来使得分类器对误分的数据有较高的重视程度,从而提升模型的整体效果。

(2)随机森林模型的基本原理

       随机森林Random Forest)是一种经典的Bagging模型,其弱学习器为决策树模型。如下图所示,随机森林模型会在原始数据集中随机抽样,构成n个不同的样本数据集,然后根据这些数据集搭建n个不同的决策树模型,最后根据这些决策树模型的平均值(针对回归模型)或者投票(针对分类模型)情况来获取最终结果。

       随机森林分类模型代码演示如下所示:

from sklearn.ensemble import RandomForestRegressor
X = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
y = [1, 2, 3, 4, 5]

model = RandomForestRegressor(n_estimators=10, random_state=123)
model.fit(X, y)

print(model.predict([[5, 5]]))

      随机森林分类模型代码演示如下所示:

from sklearn.ensemble import RandomForestClassifier
X = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
y = [0, 0, 0, 1, 1]

model = RandomForestClassifier(n_estimators=10, random_state=123)
model.fit(X, y)

print(model.predict([[5, 5]]))

2、量化金融 - 股票数据获取

(1)股票基本数据获取

       想要搭建机器学习模型,首先得有合适的数据,我们这里首先来演示股票基本数据的获取与股票衍生变量生成。我们会使用:Tushare库,应为它是一个免费的财经数据接口包,通过它我们能够免费地调用历史行情数据来进行分析。其官方地址为:Tushare -财经数据接口包,如果是想查看股价行情数据,网址为:TuShare -财经数据接口包

Python安装Tushare库(可以使用PIP安装法来安装):

          1.通过win +R组合键调出运行框,

          2.输入cmd后回车,

          3.然后在弹出框中输入pip install tushare的方法来进行安装。

(2)Tushare库的基本介绍

1、获得日线行情数据

       使用tushare试着调用万科的历史数据:万科的股票代码为000002start的意思是开始日期,end是最终日期,具体代码如下(注意:如不写startendPython会从当天往前3年的数据):

import tushare as ts
df = ts.get_hist_data('000002', start='2018-01-01', end='2019-01-31')
df.head()

2、想调取超过3年的日线级别数据

       因为ts.get_hist_data()函数不仅获得了股票的基本价格信息,还获取了价格变化、均线价格等衍生变量,所以它最多也只能调取当天往前3年的数据。如果想调取超过3年的日线级别数据,得用ts.get_k_data()函数,它只获取股价的基本数据,df.head()弹出的结果:

       通过get_k_data()函数获取的数据不会将日期默认设为行索引,如果想把这里的date列转为行索引,可以使用设置索引的set_index()函数。代码如下:

df = df.set_index('date')  

       如果不想重新赋值,可以在set_index()函数中设置inplace参数为True,代码如下:

df.set_index('date', inplace=True)
3、获得分钟级别的数据

       可以使用ktype=‘分钟’函数,如果把分钟改成5,可以调用5分钟级别的数据。还能设置为每15,3060分钟级别数据。一旦要求获取分钟级别的数据的话,再写起始日期和结束日期就没有效果了,使用ktype=5’弹出来的结果如下:

       如果想获取当时的股价信息需要使用ts.get_realtime_quote()函数,如果觉得列数过多,可以通过DataFrame选取列的方法选取相应的列,代码如下:

df = df[['code','name','price','bid','ask','volume','amount','time']]
df

       可以用ts.get_realtime_quote()函数如果想同时获得多个股票代码的实时数据,只需要在括号里添加股票的编号,例如下:

df = ts.get_realtime_quotes(['000002','000980','000981'])
4、获得分笔数据

       通过如下代码可以获得历史分笔数据,分笔数据也即每笔成交的信息:

df = ts.get_tick_data('000002', date='2018-12-12', src='tt')
df.head()

       运行结果如下图所示:

5、获得指数信息

       通过如下代码可以获得上证指数等指数信息:

df = ts.get_index()
df.head() 

(3)股票衍生变量生成

1、生成股票基本数据

       首先get_k_data()函数获取从2015-01-012019-12-31的股票基本数据:

df = ts.get_k_data('000002',start='2015-01-01',end='2019-12-31')
df.head()

2、简单衍生变量的计算

       将设置以下列:

       pre_close代表的是昨日收盘价,是通过shift()函数将'close'这一列所有数往下移动一行并形成新的一列,正数1表示往下移动一行,如果是-1则表示往上移动一行;

       通过如下代码我们可以先构造一些简单的衍生变量:

df['close-open'] = (df['close'] - df['open'])/df['open']
df['high-low'] = (df['high'] - df['low'])/df['low']

df['pre_close'] = df['close'].shift(1)  
df['price_change'] = df['close']-df['pre_close']
df['p_change'] = (df['close']-df['pre_close'])/df['pre_close']*100

df.head()
3、移动平均线指标MA

       通过如下代码可以获得股价的5日移动平均值和10日移动平均值:

df['MA5'] = df['close'].rolling(5).mean()
df['MA10'] = df['close'].rolling(10).mean()

df.head(15)  

       由于当我们在计算像MA5这样的数据时,数据前四天对应的平均值是无法计算出来的(因为最开始的4天数据量不够去计算5日均值),所以会产生空值NaN,我们通常会通过dropna()函数删除空值,以免在后续计算中出现空值造成的问题。代码如下:

df.dropna(inplace=True) 
df.head()

       因为这里是使用get_k_data()函数获取股票基本数据,日期是默认从小到大排列,如果是通过get_hist_data()函数获取股票基本数据,get_hist_data()函数是默认根据日期由近及远(由大到小)的方式来排列,所以在通过rolling()mean()函数求移动平均值的时候,要先通过sort_index()函数将日期由开始日期到结束日期进行正序排列。

3、量化金融 - 股票涨跌预测模型搭建

(1)多因子模型搭建

1、引入需要用到的库

      首先通过如下代码引入代码需要用到的相关库:

import tushare as ts  # 股票基本数据相关库
import numpy as np  # 科学计算相关库
import pandas as pd  # 科学计算相关库  
import talib  # 股票衍生变量数据相关库
import matplotlib.pyplot as plt  # 引入绘图相关库
from sklearn.ensemble import RandomForestClassifier  # 引入分类决策树模型
from sklearn.metrics import accuracy_score  # 引入准确度评分函数
import warnings
warnings.filterwarnings("ignore") # 忽略警告信息,警告非报错,不影响代码执行
2、股票数据处理与衍生变量生成

       将股票基本数据和股票衍生变量数据的相关代码汇总:

# 1.股票基本数据获取
df = ts.get_k_data('000002',start='2015-01-01',end='2019-12-31')
df = df.set_index('date')  # 设置日期为索引

# 2.简单衍生变量构造
df['close-open'] = (df['close'] - df['open'])/df['open']
df['high-low'] = (df['high'] - df['low'])/df['low']

df['pre_close'] = df['close'].shift(1)  # 该列所有往下移一行形成昨日收盘价
df['price_change'] = df['close']-df['pre_close']
df['p_change'] = (df['close']-df['pre_close'])/df['pre_close']*100

# 3.移动平均线相关数据构造
df['MA5'] = df['close'].rolling(5).mean()
df['MA10'] = df['close'].rolling(10).mean()
df.dropna(inplace=True)  # 删除空值

# 4.通过Ta_lib库构造衍生变量
df['RSI'] = talib.RSI(df['close'], timeperiod=12)  # 相对强弱指标
df['MOM'] = talib.MOM(df['close'], timeperiod=5)  # 动量指标
df['EMA12'] = talib.EMA(df['close'], timeperiod=12)  # 12日指数移动平均线
df['EMA26'] = talib.EMA(df['close'], timeperiod=26)  # 26日指数移动平均线
df['MACD'], df['MACDsignal'], df['MACDhist'] = talib.MACD(df['close'], fastperiod=12, slowperiod=26, signalperiod=9)  # MACD值
df.dropna(inplace=True)  # 删除空值
3、特征变量和目标变量提取

       首先我们来进行特征变量和目标变量的提取,代码如下:

X = df[['close', 'volume', 'close-open', 'MA5', 'MA10', 'high-low', 'RSI', 'MOM', 'EMA12', 'MACD', 'MACDsignal', 'MACDhist']]

       通过今天的股价信息来预测下一天的股价涨跌情况,相对应的代码如下所示:

y = np.where(df['price_change'].shift(-1)> 0, 1, -1)

       其中Numpy库中的where()函数的使用方法如下图所示:

其中 df [' price_change '].shift(-1) 则是利用 shift() 函数将 price_change (股价变化)这一列往上移动一行,这样就获得了每一行对应的下一天股价涨跌情况
下一天股价涨了的我们则 y 赋值为数字 1
下一天股价跌了的我们则 y 赋值为数字 -1
4、训练集和测试集数据划分

       将原始数据集进行分割,训练集与测试集的划分要按照时间序列划分,而不是像之前利用train_test_split()函数进行划分。原因在于股票价格的变化趋势具有时间性,如果我们随机划分,则会破坏时间性特征,因为我们是根据当天数据来预测下一天的股价涨跌情况,而不是任意一天的股票数据来预测下一天的股价涨跌情况。因此,我们将前90%的数据作为训练集,后10%的数据作为测试集,代码如下:

X_length = X.shape[0]  # shape属性获取X的行数和列数,shape[0]即表示行数 
split = int(X_length * 0.9)

X_train, X_test = X[:split], X[split:]
y_train, y_test = y[:split], y[split:]
5、模型搭建

       划分好训练集和测试集之后,我们开始构建模型,代码如下:

model = RandomForestClassifier(max_depth=3, n_estimators=10, min_samples_leaf=10, random_state=1)
model.fit(X_train, y_train)

       引入模型并设置好相关参数后,通过fit()函数即可训练模型。

       其中几个参数的含义:

max_depth每个决策树的最大深度,这里设置树的最大深度为3,也即共3层;

n_estimators设置基模型:决策树模型的个数,这里设置为数字10,也就是说该随机森林中共有10个决策树;

min_samples_leaf在叶节点处所需的最小样本数,这里设置为数字10,也就是如果叶子节点的样本数小于10则停止分裂;

random_state随机状态参数,使得每次运行的结果都是一样的,数字1没有特殊含义,可以换成其他数字。

(2)模型使用与评估

1、预测下一天的涨跌情况

       通过predict()函数可以直接预测结果,代码如下:

y_pred = model.predict(X_test)

       用list()函数将其转换为列表,代码如下:

a = pd.DataFrame()  # 创建一个空DataFrame 
a['预测值'] = list(y_pred)
a['实际值'] = list(y_test)
a.head()

       通过predict_proba()则可以预测属于各个分类的概率,代码如下:

y_pred_proba = model.predict_proba(X_test)
y_pred_proba[0:5]

分类为-1的概率

分类为1的概率

0.52

0.48

0.52

0.48

0.53

0.47

0.51

0.49

0.47

0.53

2、分析数据特征的重要性

       通过如下代码我们可以分析各个特征变量的特征重要性:

model.feature_importances_

      如下代码可以更好的展示特征及其特征重要性:

features = X.columns  
importances = model.feature_importances_
a = pd.DataFrame()
a['特征'] = features
a['特征重要性'] = importances
a = a.sort_values('特征重要性', ascending=False)
a

(3)参数调优

       通过如下代码导入GridSearchCV库。设置分类器中调参的范围,并设置'n_estimators'的参数选择为{51020}三个选项,'max_depth'的取值范范围{234 5}'min_samples_leaf'取值范围{5102030}


from sklearn.model_selection import GridSearchCV  # 网格搜索合适的超参数
# 指定分类器中参数的范围
parameters = {'n_estimators':[5, 10, 20], 'max_depth':[2, 3, 4, 5], 'min_samples_leaf':[5, 10, 20, 30]}
new_model = RandomForestClassifier(random_state=1)  # 构建分类器
grid_search = GridSearchCV(new_model, parameters, cv=6, scoring='accuracy')  # cv=6表示交叉验证6次,scoring='roc_auc'表示以ROC曲线的AUC评分作为模型评价准则, 默认为'accuracy', 即按准确度评分

       将新构建的分类器和预选参数送入GridSearchCV,其中cv=6表示交叉验证6次。模型评价准则scoring参数这里选择默认参数:'accuracy', 即按准确度评分,如果设置成'roc_auc'表示以ROC曲线的AUC评分作为模型评价准则。通过如下代码传入训练数据,并查看调参的最优结果:

grid_search.fit(X_train, y_train)  # 传入数据
grid_search.best_params_  # 输出参数的最优值

(4)收益回测曲线绘制

       已经评估了模型的预测准确度,不过在实际应用中,我们更关心它的收益回测曲线,也就是看根据我们搭建的模型,最终获得结果是否比不利用模型获得的结果更好。计算通过预测后一只股票的价格变化与原数据的价格变化,采用如下代码获取预测值,这里再次强调,这里是根据当天股价预测第二天的股价涨跌情况。计算每天的股票价格变化率,用当天收盘价与前一天收盘价的差价比上前一天的收盘价。例如,5号收盘价1.0元,6号收盘价1.2元,则6号的变化率为:

       已知了预测结果,以及每天的股价变化率,我们就能来计算累计的收益率了,并根据收益率来绘制收益回测曲线,或者叫作净值曲线了。首先计算原始股票价格的收益率情况,这里主要用到了cumprod()函数,cumprod()函数是累乘函数,例如初始价格是12天内的价格变化率为10%,那么通过comproud()函数可以求得两天后的价格为:

       此时也表明两天的收益率为21%,然后计算根据策略预测后的收益率情况。

X_test['prediction'] = model.predict(X_test)
X_test['p_change'] = (X_test['close'] - X_test['close'].shift(1)) / X_test['close'].shift(1)

X_test['origin'] = (X_test['p_change'] + 1).cumprod()
X_test['strategy'] = (X_test['prediction'].shift(1) * X_test['p_change'] + 1).cumprod()

X_test[['strategy', 'origin']].tail()

       通过X_test[['strategy', 'origin']].tail()我们可以查看最后5行的收益情况,也即我们开始设定的结束日期2019-12-31时的收益情况,如下图所示:

       通过如下代码将收益情况删除空值后可视化,并设置X轴刻度自动倾斜:

X_test[['strategy', 'origin']].dropna().plot()
plt.gcf().autofmt_xdate()
plt.show()

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐