数据挖掘实战之随机森林算法使用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据挖掘实战之随机森林算法使用相关的知识,希望对你有一定的参考价值。

参考技术A

阅读路线:

近来有同学问道,有没有数据挖掘的案例可以来练习下,主要是来通过案例来知道算法是如何使用的。

下面就以 港股打新 这个金融项目为例,来做个预测,先来说下什么是打新;打新,就是用资金参与新股申购,如果中签的话,就买到了即将上市的股票。

此次分析的目的是为了深入打新数据,找到最优算法,挖掘出影响打新的关键因素,找到可能要破发的新股,从而减少新股破发的风险,提高盈利。

打新的本质,也即是在股票上市后卖出,赚取其中的差价。一般在买到的第一天就会卖掉,当然第一天上升的股票有涨有跌,为了能够减少风险,会根据历史数据来做个预判,这里把涨幅10%以下记为0,涨幅10%以上记为1,很明显这也是二分类的预测问题

对于本项目而言,最终的评价标准是要求在精确度达到97%的情况下,最大化召回率。这里是要求尽可能提高召回率,自己本身对风险比较厌恶,宁可错杀,也不会愿意申购上市就要的破发的新股

对于评价标准,一般用的是PR曲线和ROC曲线。ROC曲线有一个突出优势,就是不受样本不均衡的影响 ROC曲线不受样本不均衡问题的影响

1.数据总体情况

港股数据主要来自两个方面, 利弗莫尔证券数据 和 阿思达克保荐人近两年数据 ,处理之后是这样的:

数据一共有17个特征,除了目标变量is_profit,还有16个特征。

以上的数据指标可以梳理为两类,一类是股票相,如 关,一类是保荐人指标,

2.数据处理方面不用管
一般特征工程主要从以下方面来进行:衍生特征、异常值处理、缺失值处理、连续特征离散化、分类变量one-hot-encode、标准化等,本篇文章主要讲解随机森林算法使用,暂不对特征工程做过多的展示了

使用随机森林默认的参数 带来的模型结果来看,auc指标是0.76,效果还可以。

为了更好的理解上述,这里有几个知识点需要来解释下:

返回的是一个n行k列的数组,第i行第j列上的数值是模型预测第i个预测样本的标签为j的概率。所以每一行的和应该等于1;本文中predict_proba(x_test)[:,1]返回的是标签为0的概率。

(a).混淆矩阵

混淆矩阵如下图分别用”0“和”1“代表负样本和正样本。FP代表实际类标签为”0“,但预测类标签为”1“的样本数量。其余,类似推理。

(b).假正率和真正率

假正率(False Positive Rate,FPR)是实际标签为”0“的样本中,被预测错误的比例。真正率(True Positive Rate,TPR)是实际标签为”1“的样本中,被预测正确的比例。其公式如下:

(3).ROC曲线

下图的黑色线即为ROC曲线,ROC曲线是一系列threshold下的(FPR,TPR)数值点的连线。此时的threshold的取值分别为测试数据集中各样本的预测概率。但,取各个概率的顺序是从大到小的。然后也就是有了不同的RPR、TPR,且测试样本中的数据点越多,曲线越平滑:

AUC(Area Under roc Cure),顾名思义,其就是ROC曲线下的面积,在此例子中AUC=0.62。AUC越大,说明分类效果越好。

下面我们来看看RF重要的Bagging框架的参数,主要有以下几个:

(1) n_estimators:

也就是最大的弱学习器的个数。一般来说n_estimators太小,容易欠拟合,n_estimators太大,计算量会太大,并且n_estimators到一定的数量后,再增大n_estimators获得的模型提升会很小,所以一般选择一个适中的数值。默认是100。

(2) oob_score:

即是否采用袋外样本来评估模型的好坏。默认识False。个人推荐设置为True,因为袋外分数反应了一个模型拟合后的泛化能力。

(3) criterion:

即CART树做划分时对特征的评价标准。分类模型和回归模型的损失函数是不一样的。分类RF对应的CART分类树默认是基尼系数gini,另一个可选择的标准是信息增益。回归RF对应的CART回归树默认是均方差mse,另一个可以选择的标准是绝对值差mae。一般来说选择默认的标准就已经很好的。

从上面可以看出,RF重要的框架参数比较少,主要需要关注的是 n_estimators ,即RF最大的决策树个数。

下面我们再来看RF的决策树参数,它要调参的参数如下:

(1) RF划分时考虑的最大特征数max_features:

(2) 决策树最大深度max_depth:

默认可以不输入,如果不输入的话,决策树在建立子树的时候不会限制子树的深度。一般来说,数据少或者特征少的时候可以不管这个值。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值10-100之间。

(3) 内部节点再划分所需最小样本数min_samples_split:

这个值限制了子树继续划分的条件,如果某节点的样本数少于min_samples_split,则不会继续再尝试选择最优特征来进行划分。默认是2.如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。

(4) 叶子节点最少样本数min_samples_leaf:

这个值限制了叶子节点最少的样本数,如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝。 默认是1,可以输入最少的样本数的整数,或者最少样本数占样本总数的百分比。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。

(5)叶子节点最小的样本权重和min_weight_fraction_leaf:

这个值限制了叶子节点所有样本权重和的最小值,如果小于这个值,则会和兄弟节点一起被剪枝。 默认是0,就是不考虑权重问题。一般来说,如果我们有较多样本有缺失值,或者分类树样本的分布类别偏差很大,就会引入样本权重,这时我们就要注意这个值了。

(6) 最大叶子节点数max_leaf_nodes:

通过限制最大叶子节点数,可以防止过拟合,默认是"None”,即不限制最大的叶子节点数。如果加了限制,算法会建立在最大叶子节点数内最优的决策树。如果特征不多,可以不考虑这个值,但是如果特征分成多的话,可以加以限制,具体的值可以通过交叉验证得到。

(7) 节点划分最小不纯度min_impurity_split:
这个值限制了决策树的增长,如果某节点的不纯度(基于基尼系数,均方差)小于这个阈值,则该节点不再生成子节点。即为叶子节点 。一般不推荐改动默认值1e-7。

上面决策树参数中最重要的包括最大特征数 max_features , 最大深度 max_depth , 内部节点再划分所需最小样本数 min_samples_split 和叶子节点最少样本数 min_samples_leaf

GridSearchCV的名字其实可以拆分为两部分,GridSearch和CV,即网格搜索和交叉验证。这两个名字都非常好理解。网格搜索,搜索的是参数,即在指定的参数范围内,按步长依次调整参数,利用调整的参数训练学习器,从所有的参数中找到在验证集上精度最高的参数,这其实是一个训练和比较的过程。

GridSearchCV可以保证在指定的参数范围内找到精度最高的参数,但是这也是网格搜索的缺陷所在,他要求遍历所有可能参数的组合,在面对大数据集和多参数的情况下,非常耗时。

通过RF框架以及RF决策树参数能够了解到重点需要调节以下的参数

主要需要关注的是 n_estimators ,即RF最大的决策树个数。

决策树参数中最重要的包括最大特征数 max_features , 最大深度 max_depth , 内部节点再划分所需最小样本数 min_samples_split 和叶子节点最少样本数 min_samples_leaf

输出结果为:

6.3最佳的弱学习器迭代次数,接着我们对决策树最大深度max_depth和内部节点再划分所需最小样本数min_samples_split进行网格搜索

输出结果

6.4最大特征数max_features做调参

输出结果:

6.5根据模型最佳参数进行测试

输出结果:0.7805947388486466,相比没有调参前,模型有不少的提高的,方便观察,用图形来看下ROC曲线图

6.6观察模型的重要特征

6.7最大召回率

最后得出我们想要的结果,精准率在 0.97 下,召回率 0.046

参考文章:

1.sklearn中predict_proba的用法例子

2.Python机器学习笔记 Grid SearchCV(网格搜索)

3.scikit-learn随机森林调参小结

4.ROC曲线和AUC值的计算

一看就懂的Tensorflow实战(随机森林)

随机森林简介

随机森林是一种集成学习方法。训练时每个树分类器从样本集里面随机有放回的抽取一部分进行训练。预测时将要分类的样本带入一个个树分类器,然后以少数服从多数的原则,表决出这个样本的最终分类类型。[4]

设有N个样本,M个变量(维度)个数,该算法具体流程如下:

  1. 确定一个值m,它用来表示每个树分类器选取多少个变量;

  2. 从数据集中有放回的抽取 k 个样本集,用它们创建 k 个树分类器。另外还伴随生成了 k 个袋外数据,用来后面做检测。

  3. 输入待分类样本之后,每个树分类器都会对它进行分类,然后所有分类器按照少数服从多数原则,确定分类结果。

重要参数:

  1. 预选变量个数 (即框架流程中的m);

  2. 随机森林中树的个数。

Tensorflow 随机森林

from __future__ import print_function

import tensorflow as tf
from tensorflow.python.ops import resources
from tensorflow.contrib.tensor_forest.python import tensor_forest

# Ignore all GPUs, tf random forest does not benefit from it.
import os
os.environ["CUDA_VISIBLE_DEVICES"] = ""

补充:__futrure__[1]
简单来说,Python 的每个新版本都会增加一些新的功能,或者对原来的功能作一些改动。有些改动是不兼容旧版本的。从 Python 2.7 到 Python 3 就有不兼容的一些改动,如果你想在 Python 2.7 中使用 Python 3 的新特性,那么你就需要从__future__模块导入。

  • division
    python2.7 中,不导入__future__,10/3 = 3
    python2.7 中,导入__future__,10/3 = 3.3333333333333335
    很容易看出来,2.7中默认的整数除法是结果向下取整,而导入了 __future__ 之后除法就是真正的除法了。

  • absolute_import
    python2.7 中,默认导入模块是相对导入的(relative import),即以'.'点导入:
    from . import json
    from .json import json_dump
    绝对导入(absolute import)则是指从系统路径sys.path最底层的模块导入:
    import os
    from os import sys

  • print_function
    python2 中 print 不需要括号,而在 python3 中则需要。
    print "Hello world" # python2.7
    print("Hello world") # python3

导入数据集

# Import MNIST data
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("./data/", one_hot=False)

Extracting ./data/train-images-idx3-ubyte.gz
Extracting ./data/train-labels-idx1-ubyte.gz
Extracting ./data/t10k-images-idx3-ubyte.gz
Extracting ./data/t10k-labels-idx1-ubyte.gz

设置参数

# Parameters
num_steps = 500 # Total steps to train
batch_size = 1024 # The number of samples per batch
num_classes = 10 # The 10 digits
num_features = 784 # Each image is 28x28 pixels
num_trees = 10
max_nodes = 1000

补充:Estimator API
Estimator 跟 Dataset 都是 Tensorflow 中的高级API。
Estimator 是一种创建 TensorFlow 模型的高级方法,它包括了用于常见机器学习任务的预制模型,当然,你也可以使用它们来创建你的自定义模型。[3]

contrib.tensor_forest 详细的实现了随机森林算法(Random Forests)评估器,并对外提供 high-level API。你只需传入 params 到构造器,params 使用 params.fill() 来填充,而不用传入所有的超参数,Tensor Forest 自己的 RandomForestGraphs 就能使用这些参数来构建整幅图。[2]

# Input and Target data
X = tf.placeholder(tf.float32, shape=[None, num_features])
# For random forest, labels must be integers (the class id)
Y = tf.placeholder(tf.int32, shape=[None])

# Random Forest Parameters
hparams = tensor_forest.ForestHParams(num_classes=num_classes,
                                     num_features=num_features,
                                     num_trees=num_trees,
                                     max_nodes=max_nodes).fill()
# Build the Random Forest
forest_graph = tensor_forest.RandomForestGraphs(hparams)

INFO:tensorflow:Constructing forest with params =
INFO:tensorflow:{'num_trees': 10, 'max_nodes': 1000, 'bagging_fraction': 1.0, 'feature_bagging_fraction': 1.0, 'num_splits_to_consider': 28, 'max_fertile_nodes': 0, 'split_after_samples': 250, 'valid_leaf_threshold': 1, 'dominate_method': 'bootstrap', 'dominate_fraction': 0.99, 'model_name': 'all_dense', 'split_finish_name': 'basic', 'split_pruning_name': 'none', 'collate_examples': False, 'checkpoint_stats': False, 'use_running_stats_method': False, 'initialize_average_splits': False, 'inference_tree_paths': False, 'param_file': None, 'split_name': 'less_or_equal', 'early_finish_check_every_samples': 0, 'prune_every_samples': 0, 'num_classes': 10, 'num_features': 784, 'bagged_num_features': 784, 'bagged_features': None, 'regression': False, 'num_outputs': 1, 'num_output_columns': 11, 'base_random_seed': 0, 'leaf_model_type': 0, 'stats_model_type': 0, 'finish_type': 0, 'pruning_type': 0, 'split_type': 0}

损失函数

# Get training graph and loss
train_op = forest_graph.training_graph(X, Y)
loss_op = forest_graph.training_loss(X, Y)

# Measure the accuracy
infer_op, _, _ = forest_graph.inference_graph(X)
correct_prediction = tf.equal(tf.argmax(infer_op, 1), tf.cast(Y, tf.int64))
accuracy_op = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

训练

# Initialize the variables (i.e. assign their default value) and forest resources
init_vars = tf.group(tf.global_variables_initializer(),
   resources.initialize_resources(resources.shared_resources()))

# Start TensorFlow session
sess = tf.train.MonitoredSession()

# Run the initializer
sess.run(init_vars)

# Training
for i in range(1, num_steps + 1):
   # Prepare Data
   # Get the next batch of MNIST data (only images are needed, not labels)
   batch_x, batch_y = mnist.train.next_batch(batch_size)
   _, l = sess.run([train_op, loss_op], feed_dict={X: batch_x, Y: batch_y})
   if i % 50 == 0 or i == 1:
       acc = sess.run(accuracy_op, feed_dict={X: batch_x, Y: batch_y})
       print('Step %i, Loss: %f, Acc: %f' % (i, l, acc))

# Test Model
test_x, test_y = mnist.test.images, mnist.test.labels
print("Test Accuracy:", sess.run(accuracy_op, feed_dict={X: test_x, Y: test_y}))

INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
Step 1, Loss: -1.000000, Acc: 0.411133
Step 50, Loss: -254.800003, Acc: 0.892578
Step 100, Loss: -538.799988, Acc: 0.915039
Step 150, Loss: -826.599976, Acc: 0.922852
Step 200, Loss: -1001.000000, Acc: 0.926758
Step 250, Loss: -1001.000000, Acc: 0.919922
Step 300, Loss: -1001.000000, Acc: 0.933594
Step 350, Loss: -1001.000000, Acc: 0.916992
Step 400, Loss: -1001.000000, Acc: 0.916992
Step 450, Loss: -1001.000000, Acc: 0.927734
Step 500, Loss: -1001.000000, Acc: 0.917969
Test Accuracy: 0.9212

参考

[1] Python __future__ 模块:https://blog.csdn.net/langb2014/article/details/53305246#t1

[2] 【机器学习】在TensorFlow中构建自定义Estimator:深度解析TensorFlow组件Estimator:http://www.doc88.com/p-1834979585771.html

[3] TensorFlow 1.3的Datasets和Estimator知多少?谷歌大神来解答:http://www.sohu.com/a/191717118_390227

[4] 穆晨:随机森林(Random Forest):https://www.cnblogs.com/muchen/p/6883263.html


-长按关注-


以上是关于数据挖掘实战之随机森林算法使用的主要内容,如果未能解决你的问题,请参考以下文章

决策树算法之随机森林

机器学习实战之 第七章 集成方法(随机森林和 AdaBoost)

tensorflow基础模型之RandomForest(随机森林)算法

机器学习分类算法之随机森林(集成学习算法)

机器学习算法 - 随机森林之决策树初探

数据分析系列 之python中随机森林算法的应用