|
[size=1.1em]模型设置本模块根据预设的机器学习方法和参数,调用相应包并建立模型对象 model。
代码实例
[url=]Uploading: image.png…[/url]
代码分析
if para.method == ‘SVM’:
调用 para 类中的 method。变量 method 表示使用何种机器学习方法。该语句判断是否为 使用支持向量机模型。
from sklearn import svm
若判断条件通过,进入 if 语句内部。使用 from 导入 sklearn 包中的 svm 模块。
model = svm.SVC(kernel=para.svm_kernel, C=para.svm_c)
使用 svm.SVC 函数,构建 SVM 分类器,赋予模型对象 model。参数 kernel 为核函数类 型,此处我们调用 para 类中预设的核函数类型 svm_kernel;参数 C 为惩罚系数,此处我 们调用 para 类中预设的惩罚系数 svm_c。
其余变式
如果我们希望使用线性回归模型,我们仍以 if 命令判断是否使用线性回归模型,随后以 import 导入 linear_model 模块,并使用 linear_model.LinearRegression 构建模型赋予模 型对象 model。注意到线性回归的参数设置和支持向量机不同,参数 fit_intercept 表示线性回归是否包含截距项。
image.png[size=1em]724x216 39.5 KB
同样的,如果我们需要使用 SGD 模型,整体框架和前两者相同,只是调用的模块为 linear_model.SGDClassifier。参数 loss 表示损失函数类型,这里采用 hinge 损失;alpha 为正则项前的权重;penalty 为正则化方法,这里采用 L2 正则化;max_iter 为最大迭代次 数; random_state 为随机数种子值,目的是使结果可重复。
模型训练本模块根据训练集的特征和标签训练 SVM 模型,随后使用训练完成的模型对训练集和交 叉验证集进行预测。
代码实例
代码分析
model.fit(X_train,y_train)
用训练集的特征 X_train 和标签 y_train 训练模型对象 model。其中函数 fit 的两个参数分别为特征和标签,训练结果保存在模型对象 model 中。
y_pred_train = model.predict(X_train) y_score_train = model.decision_function(X_train)
用训练好的模型对象 model 在训练集 X_train 上做预测,预测结果用于模型评估。其中, 函数 predict 给出的结果是二值化的整数[0,1],表示样本对应的标签(涨或跌);函数 decision_function 给出的决策函数值是连续的浮点数,用于刻画样本点涨跌的“概率”, 不同模型计算结果的意义不同。例如 SVM 的结果表示样本点到分类超平面的“距离”(可 正可负,可大于 1),越正表示涨的概率越大,越负表示跌的概率越大。变量 y_pred_train 是预测标签(二值),变量 y_score_train 是预测的决策函数值(连续),可理解为涨跌的 概率。
y_pred_cv = model.predict(X_cv) y_score_cv = model.decision_function(X_cv)
用模型对象 model 在交叉验证集 X_cv 上做预测,结果同第 2,3 行,预测结果常用于调参。 其中,变量 y_pred_cv 和 y_score_cv 分别表示交叉验证集上的预测标签和预测的决策函数值。
其余变式
特别地,当我们需要使用线性回归模型时,回归模型不存在预测标签和决策函数的概念, 而是直接以 model.predict 的方法给出预测值。
使用 SGD 模型时,模型训练的命令和 SVM 模型完全相同。
模型预测本模块使用训练完成的模型在测试集上做预测。首先,创建三个空数据集 y_true_test、 y_pred_test 和 y_score_test,分别用于存储预测集上的真实收益、预测标签和预测的决 策函数值。随后对测试集中的每个月进行预测,使用 for 循环遍历测试集的每个月。
代码实例
image.jpg[size=1em]736x686 127 KB
代码分析
y_true_test = pd.DataFrame([np.nan] * np.ones((para.n_stock,para.month_test[-1]))) y _pred_test = pd.DataFrame([np.nan] * np.ones((para.n_stock,para.month_test[-1])) y _score_test = pd.DataFrame([np.nan] * np.ones((para.n_stock,para.month_test[-1])))
三个数据集的类型均为 pandas 中的 DataFrame,数据集初始化为 nan;行数为股票的个 数 para.n_stock,每一行代表一只股票的信息;列数为测试集最后一个月的月份 para.month_test[-1],每一列代表一个截面(月)。
for i_month in para.month_test:
para.month_test 为测试集的所有月份,类型为列表。i_month 为循环变量,代表当前月份。
file_name = para.path_data + str(i_month) + ‘.csv’ data_curr_month = pd.read_csv(file_name, header = 0)
从 csv 文件中读取当前月份 i_month 的数据,返回变量 data_curr_month 的类型为 DataFrame。其中,函数 read_csv 用来读取 csv 文件,参数 file_name 表示 csv 文件的 存储路径,字符串类型,使用+号运算符拼接字符串时需要把 i_month 从 int 型强制转化 为 string 类型;header = 0 表示 csv 文件索引为 0 的行作为返回值的列名,此外 header 还可以取 None,表示返回值没有列名。
data_curr_month = data_curr_month.dropna(axis=0) #-- remove nan
删除数据集 data_curr_month 中含有缺失值 nan 元素所在的行,返回结果仍保存在 data_curr_month 中。一般来说,删除缺失值后,data_curr_month 的行数会变少,但是 每一行的索引同原来的,于是 data_curr_month.index 不为连续自然数列。
X_curr_month = data_curr_month.loc[:,‘EP’:‘bias’] #-- generate X
提取 70 个因子值,也即 data_curr_month 的第’EP’列到’bias’列。注意,函数 loc 是按列 名获取切片,函数 iloc 是按索引获取切片
X_curr_month = pca.transform(X_curr_month) #-- pca
对因子数据集 X_curr_month 做主成分分析,返回结果仍保存在 X_curr_month 中。一般 来说,主成分分析后 X_curr_month 的列数会变少,起到降维和去除因子共线性的作用。
if para.method == ‘SVM’:
para.method 用于选择不同的机器学习方法,SVM 代表支持向量机模型。
y_pred_curr_month = model.predict(X_curr_month) y_score_curr_month = model.decision_function(X_curr_month)
根据当前月份的因子值 X_curr_month 做 预测,变量 y_pred_curr_month 和 y_score_curr_month 分别表示样本点的预测标签和预测的决策函数值。
y_true_test.iloc[data_curr_month.index,i_month-1] = data_curr_month[‘return’][data_curr_month.index]
保存真实收益。将 data_curr_month 的第’return’列(下月的超额收益率)的所有行的值存 储到 y_true_test 的相应位置。变量 y_true_test 表示所有股票的真实收益,每一行代表一 只股票,每一列代表一个月份。这里变量 y_true_test 的列为 i_month-1 是因为列的索引 从 0 开始;行为 data_curr_month.index 是因为只保存进行预测的股票的收益率,没有进 行预测的股票收益率仍取为缺失值 nan。注意到,data_curr_month 在去除缺失值 nan 后 行数会变少,因此 data_curr_month.index 是 y_true_test.index 的子集。
y_pred_test.iloc[data_curr_month.index,i_month-1] = y_pred_curr_month y_score_test.iloc[data_curr_month.index,i_month-1] = y_score_curr_month
将当前月份的预测标签 y_pred_curr_month 和预测的决策函数值 y_score_curr_month 保 存到相应位置。
其余变式
和模型训练模块类似,使用线性回归模型时,直接以 model.predict 的方法给出预测值。
使用 SGD 模型时,预测标签和决策函数的获取命令和 SVM 模型完全相同。
模型评价模型评估部分主要计算:训练集、交叉验证集和测试集(每月)的正确率和 AUC。
代码实例
image.jpg[size=1em]758x723 150 KB
代码分析
from sklearn import metrics
从 sklearn 包中导入 metrics 模块,该模块覆盖了分类任务中大部分常用的验证指标, 比如正确率、ROC、AUC、混淆矩阵、分类精度、f1-score 等。
print(‘training set, accuracy = %.2f’%metrics.accuracy_score(y_train, y_pred_train))
print(‘training set, AUC = %.2f’%metrics.roc_auc_score(y_train, y_score_train))
计算训练集上的正确率和 AUC,其中,y_train 为真实标签(二值) ,y_pred_train 为预测 标签(二值),y_score_train 为预测的决策函数值(连续),函数 accuracy_score 用以计 算正确率,函数 roc_auc_score 用以计算 AUC。
print(‘cv set, accuracy = %.2f’%metrics.accuracy_score(y_cv, y_pred_cv))
print(‘cv set, AUC = %.2f’%metrics.roc_auc_score(y_cv, y_score_cv))
计算交叉验证集上的正确率和 AUC,其中 y_cv 为真实标签(二值) ,y_pred_cv 为预测标 签(二值),y_score_cv 为预测的决策函数值(连续) 。运行上述程序片段后,将在命令行 窗口显示如下的结果:
for i_month in para.month_test:
循环遍历回测区间的所有月份,计算每个月的正确率和 AUC。
y_true_curr_month = pd.DataFrame({‘return’:y_true_test.iloc[:,i_month-1]})
y_pred_curr_month = y_pred_test.iloc[:,i_month-1] y_score_curr_month = y_score_test.iloc[:,i_month-1]
获取测 试 集 中 当 前 月 份 的 真实收益 y_true_curr_month ( 连 续 )、 预 测 标 签 y_pred_curr_month(二值)和预测的决策函数值 y_score_curr_month(连续),都是只 有一列的 DataFrame 类型。
y_true_curr_month = y_true_curr_month.dropna(axis=0)
删除当前月份真实收益 y_true_curr_month 中的缺失值 nan 所在的行,函数 dropna 已经 多次用到,不做赘述。
y_curr_month = label_data(y_true_curr_month)[‘return_bin’]
给真实收益 y_true_curr_month 加标签。函数 label_data(y_true_curr_month)返回一个 DataFrame,两列为’return’和’return_bin’,分别表示真实收益(连续)和真实标签(二值, 0,1);此外,该函数对行也进行了处理,即先按照真实收益降序排列,然后取前后 30%的 股票,这样做的好处是尽量减少噪音影响,因为中间 40%的收益很有可能在噪音的影响下 变号,从而改变类别。y_curr_month 是 y_true_curr_month 的第’return_bin’列,表示真实 标签, 鉴于函数 label_data 对 行 进 行 了 筛选,因此 y_curr_month.index 是 y_true_curr_month.index 的子集。
y_pred_curr_month = y_pred_curr_month[y_curr_month.index]
y_score_curr_month = y_score_curr_month[y_curr_month.index]
获取收益最好和最差的 30%股票的预测标签 y_pred_curr_month(二值)和预测的决策函 数值 y_score_curr_month(连续)。其中,y_curr_month.index 是收益最好和最差的 30% 股票的索引,也是当前月份所有股票索引 y_true_curr_month.index 的子集。
print(‘test set, month %d, accuracy = %.2f’%(i_month,
metrics.accuracy_score(y_curr_month, y_pred_curr_month)))
print(‘test set, month %d, AUC = %.2f’%(i_month, metrics.roc_auc_score(y_curr_month, y_score_curr_month)))
计算测试集中每个月的正确率和 AUC,分别由函数 accuracy_score 和 roc_auc_score 给 出。其中 y_curr_month 为真实标签(二值) ,y_pred_curr_month 为预测标签(二值)
, y_score_curr_month 为预测的决策函数值(连续)。 运行上述程序片段后,将在命令行窗 口显示如下的模型评估结果:
[url=]Uploading: image.png(1)…[/url]
策略构建本模块围绕线性 SVM 模型的预测结果,构建了一个简单策略:选取每个月最可能涨的 100 只股票,等权配置资产。随后计算该策略的收益和净值。
代码实例
image.jpg[size=1em]719x599 98.4 KB
代码分析
para.n_stock_select = 100
strategy = pd.DataFrame({‘return’:[0] * para.month_test[-1],‘value’:[1] * para.month_test[-1]})
设置选股个数为 100,初始化策略的收益和净值。变量 strategy 是 DataFrame 类型,有 两列’return’和’value’,分别表示策略的每月收益和每月净值。'return’列的初始值均为 0, 'value’列的初始值均为 1。
for i_month in para.month_test:
遍历回测区间的所有月份,计算每个月的策略收益和净值。
y_true_curr_month = y_true_test.iloc[:,i_month-1] y_score_curr_month = y_score_test.iloc[:,i_month-1] y_true_curr_month
为当前月份的真实收益,y_score_curr_month 为当前月份的预测的决 策函数值,均为只包含一列的 DataFrame 类型。其中,函数 iloc 是按索引获取切片,列 为 i_month-1 是因为列的索引从 0 开始。
y_score_curr_month = y_score_curr_month.sort_values(ascending=False) 将当前月份的预测的决策函数值 y_score_curr_month 降序排列。其中,函数 sort_values 为排列函数,参数 ascending 用于指定排序方式(参数 True 表示升序,False 表示降序), 参数 by 用于指定按哪一列排序。注意,无论按照升序还是降序排列,nan 始终排在最后, 并且每行的索引始终不变。
index_select = y_score_curr_month[0:para.n_stock_select].index
选取上涨概率最大的前 100 只股票。上一句命令将预测的决策函数值降序排列后,越靠前 的股票上涨概率越大,并且在 dropna 和 sort_values 操作后,每只股票的索引不变,故可 将索引看做股票的唯一标识,用于选股。
strategy.loc[i_month-1,‘return’] = np.mean(y_true_curr_month[index_select])
策略的每月收益为当前选取的 100 只股票的收益均值。其中,np.mean 是计算均值的函数, 参数为数组型变量。
strategy[‘value’] = (strategy[‘return’]+1).cumprod()
计算策略的每月净值:将当前月份之前所有月(包括当前月)的收益加 1,然后累乘。其 中,strategy[‘return’]表示按列名访问这一列,函数 cumprod 表示累乘,参数为数组型变 量。
策略评价本模块我们将绘制上述策略的净值曲线,并计算年化超额收益,年化超额收益波动率,信 息比率等指标用以评价策略。
image.jpg[size=1em]658x536 73.2 KB
代码分析
import matplotlib.pyplot as plt 导入 matplotlib 包中的 pyplot 模块,并将其简记为 plt。
plt.plot(para.month_test,strategy.loc[para.month_test,‘value’],‘r-’) plt.show()
利用函数 plot 画图,第一个参数 para.month_test 为横轴,表示月份;第二个参数 strategy.loc[para.month_test,‘value’]为纵轴,表示回测区间上每个月的净值;第三个参数 'r-'为曲线的颜色和线型,这里指红色的直线。最后通过函数 show 将绘制的图像显示出来。 运行程序时,命令行窗口将显示下图所示的净值曲线。
image.png[size=1em]795x470 27.7 KB
ann_excess_return = np.mean(strategy.loc[para.month_test,‘return’]) * 12
计算策略的年化超额收益:所有月份收益的均值乘以 12。其中,函数 np.mean 表示计算 一组数的均值。
ann_excess_vol = np.std(strategy.loc[para.month_test,‘return’]) * np.sqrt(12)
计算策略的年化超额收益波动率:所有月份收益的方差乘以 12 再开根号,等价于,所有 月份收益的标准差乘以根号 12。其中,函数 np.std 表示计算一组数的标准差,函数 np.sqrt 表示开根号。
info_ratio = ann_excess_return/ann_excess_vol
计算策略的信息比率 IR:超额收益除以超额收益波动率。用于评估策略好坏,含义是承担 单位主动风险所获得的超额收益,IR 越大则策略越好,反之越差。
print(‘annual excess return = %.2f’%ann_excess_return) print(‘annual excess volatility = %.2f’%ann_excess_vol) print(‘information ratio = %.2f’%info_ratio)
输出策略的评估结果。其中,函数 print 用于打印结果;’%.2f’是格式符,用于控制输出格 式,这里表示保留两位小数的浮点数,此外格式符还有’%d’(整型)、’%s’(字符串)等; 单引号之后的’%'是格式化操作的标志,表示用之后的变量值依次代替输出格式中格式符的 位置。运行程序后在命令行窗口将显示如下的策略评价结果:
数据保存本模块介绍如何保存数据,将每个月的预测值以 csv 格式保存在某个路径下。
代码分析
import os 导入输出模块 os,用来完成数据输出的操作。os 模块提供了一些统一的操作系统接口函 数,这些函数通常是平台指定的,os 模块能在不同操作系统平台如 nt 或 posix 中的特定 函数间自动切换,从而能实现跨平台操作。os 模块包含了普遍的操作系统功能,如果你希 望程序能够与平台无关的话,这个模块尤为重要。
if not os.path.exists(para.path_results): os.makedirs(para.path_results)
建立数据的输出目录,如果没有该目录,则新建。函数 os.path.exists 用来判断目录是否 存在,函数 os.makedirs 用来新建目录。如果不写这两句话,直接往一个不存在的目录下 输出数据,则会报错。
filename = para.path_results + ‘dataTestYhat.csv’
建立输出文件的文件名,即 para.path_results 目录下的’dataTestYhat.csv’文件。
y_score_test.to_csv(filename,header=0,index=False)
将测试集上预测的决策函数值 y_score_test 保存到输出文件 filename 中,其中,header=0 表示列名保存在第 0 行,index=False 表示不保存索引。最终保存的 csv 文件如下图所示, 包含 3410 行和 232 列,每行代表 1 只股票,每列代表 1 个月末截面期。每个元素代表该 月末截面期对股票下月收益的预测值(SVM 模型为决策函数值)。
image.jpg[size=1em]806x406 152 KB
总结以上我们对基于 Python 语言的机器学习选股代码进行了详细介绍。软件开发者的一个共 识是不要重复造轮子。我们希望上述的分享能够节省读者的研究时间,帮助读者迅速上手 Python 机器学习框架。我们也欢迎感兴趣的读者以此为蓝本进行优化和改造,开发新的 机器学习多因子选股策略。
附录XGBoost 安装方法
XGBoost 是重要的 Boosting 集成学习模型,在最近几年获得了长足的发展。目前 scikit-learn 包并没有包含 XGBoost,需要手动安装,过程较为繁琐。我们总结了 XGBoost 在 Windows 系统下的详细安装方法,供读者参考。
安装 Git
Git 是一个分布式版本控制系统,可以对项目版本进行高效的管理。GitHub 是一个软件项 目托管平台,使用 Git 可以从 GitHub 中下载或上传开源程序。我们将使用 Git 从 GitHub 上获取最新版的 XGBoost。首先我们需要下载 Git for Windows,安装 Git。 下载链接:https://git-for-windows.github.io/ [size=0.7579em]2
下载 XGBoost
Git 安装完成后,打开 Git Bash,在命令行中依次输入: git clone --recursive https://github.com/dmlc/xgboost git submodule init git submodule update 运行完成后,将在用户文件夹中(例如 C:/Users/用户名/)生成一个 xgboost 文件夹。
编译
下面我们将使用 MinGW 编译 XGBoost。首先下载 mingw-w64。下载链接: https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Pe rsonal%20Builds/mingw-builds/5.3.0/threads-win32/seh/ 点击下载 x86_64-5.3.0-release-win32-seh-rt_v4-rev0.7z,解压放置于 C 盘根目录。
随后配置环境变量:将 C:/mingw64/bin 粘贴到 path 环境变量下。接下来在命令行运行 mingw32-make 调用该命令,如下图所示:
image.jpg[size=1em]730x269 41.7 KB
编译结果如下:
image.jpg[size=1em]800x430 129 KB
拷贝 xgboost.dll
将~/xgboost/lib 目录下的 xgboost.dll 文件拷贝到~/xgboost/python-package/xgboost 下。
安装 setup.py
在命令行中进入~/xgboost/python-package,执行命令: python setup.py install 结果如下:
image.png[size=1em]802x345 66.3 KB
查看安装结果
在命令行中进入 Python,输入: import xgboost help(xgboost)
可以查看 xgboost module 的信息:
image.jpg[size=1em]817x442 54.9 KB
尝试在 Python 里导入 xgboost 包,如果程序没有报错则安装完成。
如果提示找不到这个包,那么将目录:
C:/Program Files/Anaconda3/Lib/site-packages/xgboost-0.6-py3.6.egg
下的 xgboost 文件夹拷贝到目录: C:/Program Files/Anaconda3/Lib/site-packages
下(即将 xgboost 文件夹移动到 xgboost-0.6-py3.6.egg 文件夹外部;这里我们假设 C:/Program Files/Anaconda3 为 Anaconda 的安装路径) ,这是因为 site-packages 下的 module 才是 Python 可以直接访问的目录。
风险提示通过 Python 编写人工智能选股算法受到数据库架构、网络环境、计算机硬件条件限制, 报告中代码经移植后可能不能正常运行;通过人工智能算法构建选股策略是历史经验的总 结,存在失效的可能。
|
|