2021-09-25

一、决策树

1. 什么是决策树

决策树依据的思想:相同/相似的输入,产生相同/相似的输出(同因同果)

决策树是一种常见的机器学习方法,其核心思想是相同(或相似)的输入产生相同(或相似)的输出,通过树状结构来进行决策,其目的是通过对样本不同属性的判断决策,将具有相同属性的样本划分到一个叶子节点下,从而实现分类或回归. 以下是几个生活中关于决策树的示例。

【示例1】

男生看女生与女生看男生的决策树模型

【示例2】

挑选西瓜的决策树模型

在上述示例模型中,通过对西瓜一系列特征(色泽、根蒂、敲声等)的判断,最终我们得出结论:这是否为一个好瓜. 决策过程中提出的每个判定问题都是对某个属性的“测试”,例如“色泽=?”,“根蒂=?”. 每个测试的结果可能得到最终结论,也可能需要进行下一步判断,其考虑问题的范围是在上次决策结果限定范围之内. 例如若在“色泽=青绿”之后再判断“根蒂=?”.

2. 决策树的结构

一般来说,一棵决策树包含一个根节点、若干个内部节点和若干个叶子节点. 叶子节点对应最终的决策结果,其它每个节点则对应与一个属性的测试. 最终划分到同一个叶子节点上的样本,具有相同的决策属性,可以对这些样本的值求平均值来实现回归,对这些样本进行投票(选取样本数量最多的类别)实现分类.

3. 如何构建决策树

1)构建决策树算法

决策树的构建,就是不断选取好的特征作为决策节点,构建一颗泛化能力较强的树结构,其基本算法如下所示:

显然,决策树的构建是一个递归的过程,核心是以下两个问题:

  • 如何选取特征. 决策树构建的每一步,应该挑选最优的特征,进行决策对数据集划分效果最好;

  • 决定何时停止分裂子节点.

2)如何选择特征

① 信息熵

信息熵(information entropy)是度量样本集合纯度的常用指标,该值越大,表示该集合纯度越低(或越混乱),该值越小,表示该集合纯度越高(或越有序).

特征最好:根据特征划分,划分前后熵值减小最快(也就是划分后,纯度变高)

信息熵定义如下:

其中,​表示集合中第i类样本所占比例(0-1之间),当​为1时(只有一个类别,比例为100%), ​的值为0,整个系统信息熵为0;当类别越多,则​的值越接近于0(越混乱),​趋近去负无穷大,整个系统信息熵就越大.以下代码,展示了类别数量从1...10的集合信息熵变化:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500"># 信息熵计算演示</span>
<span style="color:#770088">import</span> <span style="color:#000000">math</span>
<span style="color:#770088">import</span> <span style="color:#000000">numpy</span> <span style="color:#770088">as</span> <span style="color:#000000">np</span>
<span style="color:#770088">import</span> <span style="color:#000000">matplotlib</span>.<span style="color:#000000">pyplot</span> <span style="color:#770088">as</span> <span style="color:#000000">mp</span>
​
<span style="color:#000000">class_num</span> = <span style="color:#116644">10</span>  <span style="color:#aa5500"># 类别最大数量</span>
​
​
<span style="color:#770088">def</span> <span style="color:#0000ff">entropy_calc</span>(<span style="color:#000000">n</span>):
    <span style="color:#000000">p</span> = <span style="color:#116644">1.0</span> <span style="color:#981a1a">/</span> <span style="color:#000000">n</span>  <span style="color:#aa5500"># 计算每个类别的概率</span>
    <span style="color:#000000">entropy_value</span> = <span style="color:#116644">0.0</span>  <span style="color:#aa5500"># 信息熵</span>
​
    <span style="color:#770088">for</span> <span style="color:#000000">i</span> <span style="color:#770088">in</span> <span style="color:#3300aa">range</span>(<span style="color:#000000">n</span>):
        <span style="color:#000000">p_i</span> = <span style="color:#000000">p</span> <span style="color:#981a1a">*</span> <span style="color:#000000">math</span>.<span style="color:#000000">log</span>(<span style="color:#000000">p</span>)
        <span style="color:#000000">entropy_value</span> += <span style="color:#000000">p_i</span>
​
    <span style="color:#770088">return</span> <span style="color:#981a1a">-</span><span style="color:#000000">entropy_value</span>  <span style="color:#aa5500"># 返回熵值</span>
​
​
<span style="color:#000000">entropies</span> = []
<span style="color:#770088">for</span> <span style="color:#000000">i</span> <span style="color:#770088">in</span> <span style="color:#3300aa">range</span>(<span style="color:#116644">1</span>, <span style="color:#000000">class_num</span> <span style="color:#981a1a">+</span> <span style="color:#116644">1</span>):
    <span style="color:#000000">entropy</span> = <span style="color:#000000">entropy_calc</span>(<span style="color:#000000">i</span>)  <span style="color:#aa5500"># 计算类别为i的熵值</span>
    <span style="color:#000000">entropies</span>.<span style="color:#000000">append</span>(<span style="color:#000000">entropy</span>)
​
<span style="color:#3300aa">print</span>(<span style="color:#000000">entropies</span>)
​
<span style="color:#aa5500"># 可视化回归曲线</span>
<span style="color:#000000">mp</span>.<span style="color:#000000">figure</span>(<span style="color:#aa1111">'Entropy'</span>, <span style="color:#000000">facecolor</span>=<span style="color:#aa1111">'lightgray'</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">title</span>(<span style="color:#aa1111">'Entropy'</span>, <span style="color:#000000">fontsize</span>=<span style="color:#116644">20</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">xlabel</span>(<span style="color:#aa1111">'Class Num'</span>, <span style="color:#000000">fontsize</span>=<span style="color:#116644">14</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">ylabel</span>(<span style="color:#aa1111">'Entropy'</span>, <span style="color:#000000">fontsize</span>=<span style="color:#116644">14</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">tick_params</span>(<span style="color:#000000">labelsize</span>=<span style="color:#116644">10</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">grid</span>(<span style="color:#000000">linestyle</span>=<span style="color:#aa1111">'-'</span>)
<span style="color:#000000">x</span> = <span style="color:#000000">np</span>.<span style="color:#000000">arange</span>(<span style="color:#116644">0</span>, <span style="color:#116644">10</span>, <span style="color:#116644">1</span>)
<span style="color:#3300aa">print</span>(<span style="color:#000000">x</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">plot</span>(<span style="color:#000000">x</span>, <span style="color:#000000">entropies</span>, <span style="color:#000000">c</span>=<span style="color:#aa1111">'orangered'</span>, <span style="color:#000000">label</span>=<span style="color:#aa1111">'entropy'</span>)
​
<span style="color:#000000">mp</span>.<span style="color:#000000">legend</span>()
<span style="color:#000000">mp</span>.<span style="color:#000000">show</span>()</span></span>

执行结果:

② 信息增益

决策树根据属性进行判断,将具有相同属性的样本划分到相同节点下,此时,样本比划分之前更加有序(混乱程度降低),信息熵的值有所下降。用划分前的信息熵减去划分后的信息熵,就是决策树获得的信息增益。可以用以下表达式表示:

其中,D表示样本集合,a表示属性,v表示属性可能的取值​, ​表示权重,样本越多的分支对分类结果影响更大,赋予更高的权重, ​表示在样本集合D上使用属性a来划分子节点所获得的信息增益. 以下是一个关于信息增益计算的示例.

说明:

  • 香蕉占2/5,所以​;梨占1/5,所以​;黄瓜占1/5,所以​

  • 根节点信息熵:​

  • 根据颜色划分后:黄色分支信息熵​;绿色分支信息熵​;整个第二层信息熵为​

  • 根据颜色划分后的信息增益:​

由以上示例可知,经过对样本按颜色进行类别划分,划分后的信息熵比原来下降了,下降的值就是信息增益。一般来说,信息增益越大,以该属性划分所获得的“纯度提升”越大. 著名的ID3决策树学习算法就是以信息增益为准则来划分属性.

ID3决策树的缺点:

对于具有很多值的属性它是非常敏感的,例如,如果我们数据集中的某个属性值对不同的样本基本上是不相同的,甚至更极端点,对于每个样本都是唯一的,如果我们用这个属性来划分数据集,它会得到很大的信息增益,但是,这样的结果并不是我们想要的。 ID3算法不能处理具有连续值的属性。 ID3算法不能处理属性具有缺失值的样本。 由于按照上面的算法会生成很深的树,所有容易产生过拟合现象。

③ 增益率

增益率不直接采用信息增益,而采用信息增益与熵值的比率来作为衡量特征优劣的标准. C4.5算法就是使用增益率作为标准来划分属性. 增益率定义为:

其中(划分前的信息熵) --->内在价值

C4.5算法:

ID3算法不能处理具有连续值的属性。而C4.5算法很好地解决了这个问题。(通过二分法将区域进行划分)

ID3算法不能处理具有空值,C4.5可以解决。

④ 基尼系数

基尼系数定义为:(基尼系数越大,不确定性越高,样本越混乱)

直观来说,基尼系数反映了从数据集D中随机抽取两个样本,类别标记不一致的概率. 因此,基尼系数越小,数据集的纯度越高. CART决策树(Classification And Regression Tree)使用基尼系数来选择划分属性,选择属性时,选择划分后基尼值最小的属性作为最优属性. 采用和上式相同的符号表示,数据集D下属性a的基尼系数定义为:

CART决策树:

CART (Classification and Regression Trees)与C4.5算法是非常相似的,但是CART支持预测连续的值(回归),不断通过对连续值的划分,循环划分,最终选出最优质值。CART构建二叉树,而C4.5则不一定。

CART用训练集和交叉验证集不断地评估决策树的性能来修剪决策树,从而使训练误差和测试误差达到一个很好地平衡点。 ————————————————

3)如何停止分裂

以下几种情况会停止决策树子节点的构建:

  • 当前节点所有样本属于同一个类别,无需划分

  • 当前属性集为空,或者所有样本取值相同,无法划分

  • 当前节点包含的样本集合为空,不能划分

  • 当前节点样本数量少于指定数量

4. 如何实现决策树

scikit-learn中决策树相关API:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500"># 模型</span>
<span style="color:#000000">model</span> = <span style="color:#000000">st</span>.<span style="color:#000000">DecisionTreeRegressor</span>(<span style="color:#000000">max_depth</span>=<span style="color:#116644">4</span>)  <span style="color:#aa5500"># 决策树回归器      可用于特征值的提取</span>
<span style="color:#aa5500"># 训练</span>
<span style="color:#000000">model</span>.<span style="color:#000000">fit</span>(<span style="color:#000000">train_x</span>, <span style="color:#000000">train_y</span>)
<span style="color:#aa5500"># 预测</span>
<span style="color:#000000">pre_test_y</span> = <span style="color:#000000">model</span>.<span style="color:#000000">predict</span>(<span style="color:#000000">test_x</span>)</span></span>

【案例】波士顿房价预测

  • 数据集介绍

    该数据集为一个开放房价数据集,包含506笔样本,每个样本包含13个特征和1个标签,具体如下所示:

  • 代码实现

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500"># 决策树回归示例</span>
<span style="color:#aa5500"># 使用决策树预测波士顿房价</span>
​
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">datasets</span> <span style="color:#770088">as</span> <span style="color:#000000">sd</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">utils</span> <span style="color:#770088">as</span> <span style="color:#000000">su</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">tree</span> <span style="color:#770088">as</span> <span style="color:#000000">st</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">ensemble</span> <span style="color:#770088">as</span> <span style="color:#000000">se</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">metrics</span> <span style="color:#770088">as</span> <span style="color:#000000">sm</span>
​
​
<span style="color:#000000">boston</span> = <span style="color:#000000">sd</span>.<span style="color:#000000">load_boston</span>()  <span style="color:#aa5500"># 加载boston地区房价数据</span>
<span style="color:#3300aa">print</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">feature_names</span>)
<span style="color:#3300aa">print</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">data</span>.<span style="color:#000000">shape</span>)
<span style="color:#3300aa">print</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">target</span>.<span style="color:#000000">shape</span>)
​
​
<span style="color:#000000">random_seed</span> = <span style="color:#116644">7</span>  <span style="color:#aa5500"># 随机种子,计算随机值,相同的随机种子得到的随机值一样</span>
<span style="color:#000000">x</span>, <span style="color:#000000">y</span> = <span style="color:#000000">su</span>.<span style="color:#000000">shuffle</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">data</span>, <span style="color:#000000">boston</span>.<span style="color:#000000">target</span>, <span style="color:#000000">random_state</span> = <span style="color:#000000">random_seed</span>)
<span style="color:#aa5500"># 计算训练数据的数量</span>
<span style="color:#000000">train_size</span> = <span style="color:#3300aa">int</span>(<span style="color:#3300aa">len</span>(<span style="color:#000000">x</span>) <span style="color:#981a1a">*</span> <span style="color:#116644">0.8</span>) <span style="color:#aa5500"># 以boston.data中80%的数据作为训练数据</span>
<span style="color:#aa5500"># 构建训练数据、测试数据</span>
<span style="color:#000000">train_x</span> = <span style="color:#000000">x</span>[:<span style="color:#000000">train_size</span>]  <span style="color:#aa5500"># 训练输入, x前面80%的数据</span>
<span style="color:#000000">test_x</span> = <span style="color:#000000">x</span>[<span style="color:#000000">train_size</span>:]   <span style="color:#aa5500"># 测试输入, x后面20%的数据</span>
<span style="color:#000000">train_y</span> = <span style="color:#000000">y</span>[:<span style="color:#000000">train_size</span>]  <span style="color:#aa5500"># 训练输出</span>
<span style="color:#000000">test_y</span> = <span style="color:#000000">y</span>[<span style="color:#000000">train_size</span>:]   <span style="color:#aa5500"># 测试输出</span>
​
<span style="color:#aa5500">######## 单棵树进行预测 ########</span>
<span style="color:#aa5500"># 模型</span>
<span style="color:#000000">model</span> = <span style="color:#000000">st</span>.<span style="color:#000000">DecisionTreeRegressor</span>(<span style="color:#000000">max_depth</span>=<span style="color:#116644">4</span>)  <span style="color:#aa5500"># 决策回归器</span>
​
<span style="color:#aa5500"># 训练</span>
<span style="color:#000000">model</span>.<span style="color:#000000">fit</span>(<span style="color:#000000">train_x</span>, <span style="color:#000000">train_y</span>)
<span style="color:#aa5500"># 预测</span>
<span style="color:#000000">pre_test_y</span> = <span style="color:#000000">model</span>.<span style="color:#000000">predict</span>(<span style="color:#000000">test_x</span>)
<span style="color:#aa5500"># 打印预测输出和实际输出的R2值</span>
<span style="color:#3300aa">print</span>(<span style="color:#000000">sm</span>.<span style="color:#000000">r2_score</span>(<span style="color:#000000">test_y</span>, <span style="color:#000000">pre_test_y</span>))</span></span>
  • 执行结果

<span style="background-color:#f8f8f8"><span style="color:#333333">[<span style="color:#aa1111">'CRIM'</span> <span style="color:#aa1111">'ZN'</span> <span style="color:#aa1111">'INDUS'</span> <span style="color:#aa1111">'CHAS'</span> <span style="color:#aa1111">'NOX'</span> <span style="color:#aa1111">'RM'</span> <span style="color:#aa1111">'AGE'</span> <span style="color:#aa1111">'DIS'</span> <span style="color:#aa1111">'RAD'</span> <span style="color:#aa1111">'TAX'</span> <span style="color:#aa1111">'PTRATIO'</span>
 <span style="color:#aa1111">'B'</span> <span style="color:#aa1111">'LSTAT'</span>]
(<span style="color:#116644">506</span>, <span style="color:#116644">13</span>)
(<span style="color:#116644">506</span>,)
<span style="color:#116644">0.8202560889408634</span></span></span>
  • 特征重要性

作为决策树模型训练过程中的副产品,根据每个特征划分子表前后信息熵减少量就标志了该特征的重要程度,此即为该特征重要性的指标。训练后得到的模型对象提供了属性feature_importances_来存储每个特征的重要性。(是一串数值,可以排序获取它的索引后,通过feature_names[sorted_index]获取特征名)在工程应用上,可以对决策树做一些优化,不必让每一个特征都参与子表划分,而只选择其中较重要的(或者说影响因素较大的)的特征作为子表划分依据。特征重要性的评价指标,就是根据该特征划分子表后所带来的信息熵减少量,熵减越大的就越重要,也就越优先参与子表的划分。

在上述示例中加入如下代码:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">import</span> <span style="color:#000000">matplotlib</span>.<span style="color:#000000">pyplot</span> <span style="color:#770088">as</span> <span style="color:#000000">mp</span>
<span style="color:#770088">import</span> <span style="color:#000000">numpy</span> <span style="color:#770088">as</span> <span style="color:#000000">np</span>
<span style="color:#000000">fi</span> = <span style="color:#000000">model</span>.<span style="color:#000000">feature_importances_</span>  <span style="color:#aa5500"># 获取特征重要性  得到的是值</span>
<span style="color:#3300aa">print</span>(<span style="color:#aa1111">"fi:"</span>, <span style="color:#000000">fi</span>)
​
<span style="color:#aa5500"># 特征重要性可视化</span>
<span style="color:#000000">mp</span>.<span style="color:#000000">figure</span>(<span style="color:#aa1111">"Feature importances"</span>, <span style="color:#000000">facecolor</span>=<span style="color:#aa1111">"lightgray"</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">plot</span>()
<span style="color:#000000">mp</span>.<span style="color:#000000">title</span>(<span style="color:#aa1111">"DT Feature"</span>, <span style="color:#000000">fontsize</span>=<span style="color:#116644">16</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">ylabel</span>(<span style="color:#aa1111">"Feature importances"</span>, <span style="color:#000000">fontsize</span>=<span style="color:#116644">14</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">grid</span>(<span style="color:#000000">linestyle</span>=<span style="color:#aa1111">":"</span>, <span style="color:#000000">axis</span>=<span style="color:#116644">1</span>)
<span style="color:#000000">x</span> = <span style="color:#000000">np</span>.<span style="color:#000000">arange</span>(<span style="color:#000000">fi</span>.<span style="color:#000000">size</span>)
<span style="color:#000000">sorted_idx</span> = <span style="color:#000000">fi</span>.<span style="color:#000000">argsort</span>()[::<span style="color:#981a1a">-</span><span style="color:#116644">1</span>]  <span style="color:#aa5500"># 重要性排序(倒序) 得到的是排序的index</span>
<span style="color:#000000">fi</span> = <span style="color:#000000">fi</span>[<span style="color:#000000">sorted_idx</span>]  <span style="color:#aa5500"># 根据排序索引重新排特征值</span>
<span style="color:#000000">mp</span>.<span style="color:#000000">xticks</span>(<span style="color:#000000">x</span>, <span style="color:#000000">boston</span>.<span style="color:#000000">feature_names</span>[<span style="color:#000000">sorted_idx</span>]) <span style="color:#aa5500">#这里是获取名字</span>
<span style="color:#000000">mp</span>.<span style="color:#000000">bar</span>(<span style="color:#000000">x</span>, <span style="color:#000000">fi</span>, <span style="color:#116644">0.4</span>, <span style="color:#000000">color</span>=<span style="color:#aa1111">"dodgerblue"</span>, <span style="color:#000000">label</span>=<span style="color:#aa1111">"DT Feature importances"</span>)
​
<span style="color:#000000">mp</span>.<span style="color:#000000">legend</span>()
<span style="color:#000000">mp</span>.<span style="color:#000000">tight_layout</span>()
<span style="color:#000000">mp</span>.<span style="color:#000000">show</span>()</span></span>

执行结果:

5. 决策树的剪枝

剪枝(pruning)是决策树学习算法对付“过拟合”的主要手段. 在决策树学习中,为了尽可能正确分类训练样本,节点划分过程将不断重复,有时会造成决策树分支过多,这时就可能因训练样本学的“太好了”,以至于把训练集本身的一些特点当做数据所具有的一般性质而导致过拟合. 因此,可通过主动去掉一些分支来降低过拟合风险.

(1)预剪枝. 决策树生成过程中,对每个节点在划分前进行评估,若当前节点不能带来决策树泛化性能的提升,则停止划分并将当前节点标记为叶子节点.

#先预算生成节点的信息增益,来确定要不要剪枝。占用内存较少。

(2)后剪枝. 先训练为一颗完整的决策树,然后自低向上对非叶子节点进行考察,若将该节点对应的子树替换为叶节点能带来决策树泛化能力提升,则将该子树替换为叶节点.

#生成完整的决策树之后,再计算每个节点根据实际的信息增益来确定剪枝。这种方式更加靠谱,但是它的计算量非常大。

二、集成学习与随机森林

1. 集成学习

集成学习(ensemble learning)通过构建并合并多个模型来完成学习任务,从而获得比单一学习模型更显著优越的泛化性能,简言之,集成学习就是利用模型的“集体智慧”,提升预测的准确率. 根据单个模型方式,集成学习可以分为两大类:

  • 个体间存在强依赖关系,必须串行生成的序列化方法,其代表为Boosting算法;

  • 个体之间不存在强依赖关系,可同时生成的并行化方法,代表是Bagging和随机森林算法.

2. Boosting

1)什么是Boosting

Boosting(直译为推进、提升)是一族可以将弱学习器提升为强学习器的算法,其工作原理是:

  • 先训练出一个初始模型;

  • 根据模型的表现进行调整,使得模型预测错误的数据获得更多的关注,再重新训练下一个模型;(通过权重使得错误样本得到更多的关注,使错误样本在下一轮训练中得到更多的关注)

  • 不断重复第二步,直到模型数量达到预先设定的数目T,最终将这T个模型加权结合.

AdaBoosting是Boosting算法族中最著名的算法,它根据每次训练集之中每个样本的分类是否正确,以及上次的总体分类的准确率,来确定每个样本的权值。将修改过权值的新数据集送给下层分类器进行训练,最后将每次训练得到的分类器最后融合起来,作为最后的决策分类器。

2)实现Boosting

sklearn中,AdaBoosting相关API:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">tree</span> <span style="color:#770088">as</span> <span style="color:#000000">st</span>  <span style="color:#aa5500">#决策树</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">ensemble</span> <span style="color:#770088">as</span> <span style="color:#000000">se</span>  <span style="color:#aa5500">#随机森林</span>
​
<span style="color:#aa5500"># model: 决策树模型(单个模型,基学习器)</span>
<span style="color:#000000">model</span> = <span style="color:#000000">st</span>.<span style="color:#000000">DecisionTreeRegressor</span>(<span style="color:#000000">max_depth</span>=<span style="color:#116644">4</span>)
​
<span style="color:#aa5500"># n_estimators:构建400棵不同权重的决策树,训练模型</span>
<span style="color:#000000">model</span> = <span style="color:#000000">se</span>.<span style="color:#000000">AdaBoostRegressor</span>(<span style="color:#000000">model</span>, <span style="color:#aa5500"># 单模型</span>
                             <span style="color:#000000">n_estimators</span>=<span style="color:#116644">400</span>, <span style="color:#aa5500"># 决策树数量</span>
                             <span style="color:#000000">random_state</span>=<span style="color:#116644">7</span>)<span style="color:#aa5500"># 随机种子</span>
​
<span style="color:#aa5500"># 训练模型</span>
<span style="color:#000000">model</span>.<span style="color:#000000">fit</span>(<span style="color:#000000">train_x</span>, <span style="color:#000000">train_y</span>)
​
<span style="color:#aa5500"># 测试模型</span>
<span style="color:#000000">pred_test_y</span> = <span style="color:#000000">model</span>.<span style="color:#000000">predict</span>(<span style="color:#000000">test_x</span>)</span></span>

代码:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500"># AdaBoosting示例</span>
<span style="color:#aa5500"># 使用AdaBoosting预测波士顿房价</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">datasets</span> <span style="color:#770088">as</span> <span style="color:#000000">sd</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">utils</span> <span style="color:#770088">as</span> <span style="color:#000000">su</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">tree</span> <span style="color:#770088">as</span> <span style="color:#000000">st</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">ensemble</span> <span style="color:#770088">as</span> <span style="color:#000000">se</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">metrics</span> <span style="color:#770088">as</span> <span style="color:#000000">sm</span>
​
<span style="color:#000000">boston</span> = <span style="color:#000000">sd</span>.<span style="color:#000000">load_boston</span>()  <span style="color:#aa5500"># 加载boston地区房价数据</span>
<span style="color:#3300aa">print</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">feature_names</span>)
<span style="color:#3300aa">print</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">data</span>.<span style="color:#000000">shape</span>)
<span style="color:#3300aa">print</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">target</span>.<span style="color:#000000">shape</span>)
​
<span style="color:#000000">random_seed</span> = <span style="color:#116644">7</span>  <span style="color:#aa5500"># 随机种子,计算随机值,相同的随机种子得到的随机值一样</span>
<span style="color:#000000">x</span>, <span style="color:#000000">y</span> = <span style="color:#000000">su</span>.<span style="color:#000000">shuffle</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">data</span>, <span style="color:#000000">boston</span>.<span style="color:#000000">target</span>, <span style="color:#000000">random_state</span> = <span style="color:#000000">random_seed</span>)
<span style="color:#aa5500"># 计算训练数据的数量</span>
<span style="color:#000000">train_size</span> = <span style="color:#3300aa">int</span>(<span style="color:#3300aa">len</span>(<span style="color:#000000">x</span>) <span style="color:#981a1a">*</span> <span style="color:#116644">0.8</span>) <span style="color:#aa5500"># 以boston.data中80%的数据作为训练数据</span>
<span style="color:#aa5500"># 构建训练数据、测试数据</span>
<span style="color:#000000">train_x</span> = <span style="color:#000000">x</span>[:<span style="color:#000000">train_size</span>]  <span style="color:#aa5500"># 训练输入, x前面80%的数据</span>
<span style="color:#000000">test_x</span> = <span style="color:#000000">x</span>[<span style="color:#000000">train_size</span>:]   <span style="color:#aa5500"># 测试输入, x后面20%的数据</span>
<span style="color:#000000">train_y</span> = <span style="color:#000000">y</span>[:<span style="color:#000000">train_size</span>]  <span style="color:#aa5500"># 训练输出</span>
<span style="color:#000000">test_y</span> = <span style="color:#000000">y</span>[<span style="color:#000000">train_size</span>:]   <span style="color:#aa5500"># 测试输出</span>
​
<span style="color:#000000">model2</span> = <span style="color:#000000">se</span>.<span style="color:#000000">AdaBoostRegressor</span>(<span style="color:#000000">st</span>.<span style="color:#000000">DecisionTreeRegressor</span>(<span style="color:#000000">max_depth</span>=<span style="color:#116644">4</span>),
                              <span style="color:#000000">n_estimators</span>=<span style="color:#116644">400</span>,   <span style="color:#aa5500"># 决策树数量</span>
                              <span style="color:#000000">random_state</span>=<span style="color:#000000">random_seed</span>) <span style="color:#aa5500"># 随机种子</span>
<span style="color:#aa5500"># 训练</span>
<span style="color:#000000">model2</span>.<span style="color:#000000">fit</span>(<span style="color:#000000">train_x</span>, <span style="color:#000000">train_y</span>)
<span style="color:#aa5500"># 预测</span>
<span style="color:#000000">pre_test_y2</span> = <span style="color:#000000">model2</span>.<span style="color:#000000">predict</span>(<span style="color:#000000">test_x</span>)
<span style="color:#aa5500"># 打印预测输出和实际输出的R2值</span>
<span style="color:#3300aa">print</span>(<span style="color:#000000">sm</span>.<span style="color:#000000">r2_score</span>(<span style="color:#000000">test_y</span>, <span style="color:#000000">pre_test_y2</span>))</span></span>

执行结果:

<span style="background-color:#f8f8f8"><span style="color:#333333">['CRIM' 'ZN' 'INDUS' 'CHAS' 'NOX' 'RM' 'AGE' 'DIS' 'RAD' 'TAX' 'PTRATIO'
 'B' 'LSTAT']
(506, 13)
(506,)
0.9068598725149652</span></span>

可以看到,通过AdaBoosting算法,回归模型获得了更高的R2值.

3. 随机森林

1)什么是随机森林

随机森林(Random Forest,简称RF)是专门为决策树分类器设计的一种集成方法,是Bagging法的一种拓展,它是指每次构建决策树模型时,不仅随机选择部分样本,而且还随机选择部分特征来构建多棵决策树. 这样不仅规避了强势样本对预测结果的影响,而且也削弱了强势特征的影响,使模型具有更强的泛化能力.

随机森林简单、容易实现、计算开销小,在很多现实任务中展现出强大的性能,被誉为“代表集成学习技术水平的方法”.

2)如何实现随机森林

sklearn中,随机森林相关API:

<span style="background-color:#f8f8f8"><span style="color:#333333">import sklearn.ensemble as se

model = se.RandomForestRegressor(
    max_depth, # 决策树最大深度
    n_estimators, # 决策树数量
    min_samples_split)# 子表中最小样本数 若小于这个数字,则不再继续向下拆分</span></span>

以下是利用随机森林实现波士顿房价预测的代码:

<span style="background-color:#f8f8f8"><span style="color:#333333"># 使用随机森林预测波士顿房价
import sklearn.datasets as sd
import sklearn.utils as su
import sklearn.tree as st
import sklearn.ensemble as se
import sklearn.metrics as sm

boston = sd.load_boston()  # 加载boston地区房价数据
print(boston.feature_names)
print(boston.data.shape)
print(boston.target.shape)

random_seed = 7  # 随机种子,计算随机值,相同的随机种子得到的随机值一样
x, y = su.shuffle(boston.data, boston.target, random_state=random_seed)
# 计算训练数据的数量
train_size = int(len(x) * 0.8)  # 以boston.data中80%的数据作为训练数据
# 构建训练数据、测试数据
train_x = x[:train_size]  # 训练输入, x前面80%的数据
test_x = x[train_size:]  # 测试输入, x后面20%的数据
train_y = y[:train_size]  # 训练输出
test_y = y[train_size:]  # 测试输出

# 创建随机森林回归器,并进行训练
model = se.RandomForestRegressor(max_depth=10,  # 最大深度
                                 n_estimators=1000,  # 树数量
                                 min_samples_split=2)  # 最小样本数量,小于该数就不再划分子节点
model.fit(train_x, train_y)  # 训练

# 基于统计数据的特征重要性
fi_dy = model.feature_importances_
# print(fi_dy)
pre_test_y = model.predict(test_x)
print(sm.r2_score(test_y, pre_test_y))  # 打印r2得分</span></span>

打印输出:

<span style="background-color:#f8f8f8"><span style="color:#333333">['CRIM' 'ZN' 'INDUS' 'CHAS' 'NOX' 'RM' 'AGE' 'DIS' 'RAD' 'TAX' 'PTRATIO'
 'B' 'LSTAT']
(506, 13)
(506,)
0.9271955403309159</span></span>

三、总结

1)什么是决策树:利用样本特征进行决策归类,将具有相同属性的样本划入一个子节点

2)决策树的用途:用作分类器、回归器

3)如何构建决策树:根据信息熵增益构建(不同的决策树的算法不一样,有ID3-->信息商增益 C4.5-->增益率 CART决策树--->基尼系数

4)什么情况下使用决策树:实用性较广,课用于一般回归、分类问题

5)决策树优化:集成学习、随机森林

四、练习

(1)有一批水果(如下图所以),按照形状进行分类,将长条形、椭圆形各划分到不同子节点中,计算划分后的信息增益.

(2)一批样本包含A和B两个类别,计算:当A类别比率依次占0%, 10%, 20%, ..., 100%时,这批样本信息熵值,并以占比作为x轴数值、信息熵作为y轴数值绘制图像.

延伸阅读

  • VMware公司使用定制的决策树进行定价优化

<span style="background-color:#f8f8f8"><span style="color:#333333">VMware(VMW)是一家提供虚拟化技术、终端服务和云处理的公司,它将产品销售给B2B客户。长期以来,VMW公司的产品价格罕有变动。当接收到大订单的时候,销售代表会通过销售人员特别折扣(Sales Person Specific discount,SPF)标识来给出特定折扣。而VMW的定价部门则希望找到一种方法来优化其产品定价。在各个商业领域,市场上都有着对应的解决定价问题的数据挖掘解决方案。解决方案的目标不仅是优化定价,同时还要让客户的利益最大化。

VMW公司的分析和数据科学小组通过分析历史价格和相应的销量变化,来理解折扣百分比与SPF标识的关联性,并以此为依据归纳出所有产品的推荐定价。传统的定价优化会根据数量变化来进行价格变动,但是VMW公司并不会改变价格,而是使用折扣作为替代方法,但是使用折扣需要额外的步骤来确定是否需要给出折扣以及折扣率。
小组使用决策树的方法,基于折扣率和SPF标识的使用情况来对所有订单进行分类。根据业务的需求,以一种特定顺序构建出多分支(非二元)决策树。各种可能订单定价的属性都在决策树构建中被考虑进来。决策树构建过程中,基于均方误差、熵、log-loss、Gini指标等确定了决策树构建过程中分支属性的顺序。相比于使用标准分裂标准,使用的是根据业务需求定制的分裂标准。分裂停止标准是最小化观测对象数目。针对完成的分块,基于分块的属性特性观察其折扣百分比与SPF使用情况的关联性,并完成产品平台级的定价推荐。</span></span>

一、决策树

1. 什么是决策树

决策树依据的思想:相同/相似的输入,产生相同/相似的输出(同因同果)

决策树是一种常见的机器学习方法,其核心思想是相同(或相似)的输入产生相同(或相似)的输出,通过树状结构来进行决策,其目的是通过对样本不同属性的判断决策,将具有相同属性的样本划分到一个叶子节点下,从而实现分类或回归. 以下是几个生活中关于决策树的示例。

【示例1】

男生看女生与女生看男生的决策树模型

【示例2】

挑选西瓜的决策树模型

在上述示例模型中,通过对西瓜一系列特征(色泽、根蒂、敲声等)的判断,最终我们得出结论:这是否为一个好瓜. 决策过程中提出的每个判定问题都是对某个属性的“测试”,例如“色泽=?”,“根蒂=?”. 每个测试的结果可能得到最终结论,也可能需要进行下一步判断,其考虑问题的范围是在上次决策结果限定范围之内. 例如若在“色泽=青绿”之后再判断“根蒂=?”.

2. 决策树的结构

一般来说,一棵决策树包含一个根节点、若干个内部节点和若干个叶子节点. 叶子节点对应最终的决策结果,其它每个节点则对应与一个属性的测试. 最终划分到同一个叶子节点上的样本,具有相同的决策属性,可以对这些样本的值求平均值来实现回归,对这些样本进行投票(选取样本数量最多的类别)实现分类.

3. 如何构建决策树

1)构建决策树算法

决策树的构建,就是不断选取好的特征作为决策节点,构建一颗泛化能力较强的树结构,其基本算法如下所示:

显然,决策树的构建是一个递归的过程,核心是以下两个问题:

  • 如何选取特征. 决策树构建的每一步,应该挑选最优的特征,进行决策对数据集划分效果最好;

  • 决定何时停止分裂子节点.

2)如何选择特征

① 信息熵

信息熵(information entropy)是度量样本集合纯度的常用指标,该值越大,表示该集合纯度越低(或越混乱),该值越小,表示该集合纯度越高(或越有序).

特征最好:根据特征划分,划分前后熵值减小最快(也就是划分后,纯度变高)

信息熵定义如下:

其中,​表示集合中第i类样本所占比例(0-1之间),当​为1时(只有一个类别,比例为100%), ​的值为0,整个系统信息熵为0;当类别越多,则​的值越接近于0(越混乱),​趋近去负无穷大,整个系统信息熵就越大.以下代码,展示了类别数量从1...10的集合信息熵变化:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500"># 信息熵计算演示</span>
<span style="color:#770088">import</span> <span style="color:#000000">math</span>
<span style="color:#770088">import</span> <span style="color:#000000">numpy</span> <span style="color:#770088">as</span> <span style="color:#000000">np</span>
<span style="color:#770088">import</span> <span style="color:#000000">matplotlib</span>.<span style="color:#000000">pyplot</span> <span style="color:#770088">as</span> <span style="color:#000000">mp</span>
​
<span style="color:#000000">class_num</span> = <span style="color:#116644">10</span>  <span style="color:#aa5500"># 类别最大数量</span>
​
​
<span style="color:#770088">def</span> <span style="color:#0000ff">entropy_calc</span>(<span style="color:#000000">n</span>):
    <span style="color:#000000">p</span> = <span style="color:#116644">1.0</span> <span style="color:#981a1a">/</span> <span style="color:#000000">n</span>  <span style="color:#aa5500"># 计算每个类别的概率</span>
    <span style="color:#000000">entropy_value</span> = <span style="color:#116644">0.0</span>  <span style="color:#aa5500"># 信息熵</span>
​
    <span style="color:#770088">for</span> <span style="color:#000000">i</span> <span style="color:#770088">in</span> <span style="color:#3300aa">range</span>(<span style="color:#000000">n</span>):
        <span style="color:#000000">p_i</span> = <span style="color:#000000">p</span> <span style="color:#981a1a">*</span> <span style="color:#000000">math</span>.<span style="color:#000000">log</span>(<span style="color:#000000">p</span>)
        <span style="color:#000000">entropy_value</span> += <span style="color:#000000">p_i</span>
​
    <span style="color:#770088">return</span> <span style="color:#981a1a">-</span><span style="color:#000000">entropy_value</span>  <span style="color:#aa5500"># 返回熵值</span>
​
​
<span style="color:#000000">entropies</span> = []
<span style="color:#770088">for</span> <span style="color:#000000">i</span> <span style="color:#770088">in</span> <span style="color:#3300aa">range</span>(<span style="color:#116644">1</span>, <span style="color:#000000">class_num</span> <span style="color:#981a1a">+</span> <span style="color:#116644">1</span>):
    <span style="color:#000000">entropy</span> = <span style="color:#000000">entropy_calc</span>(<span style="color:#000000">i</span>)  <span style="color:#aa5500"># 计算类别为i的熵值</span>
    <span style="color:#000000">entropies</span>.<span style="color:#000000">append</span>(<span style="color:#000000">entropy</span>)
​
<span style="color:#3300aa">print</span>(<span style="color:#000000">entropies</span>)
​
<span style="color:#aa5500"># 可视化回归曲线</span>
<span style="color:#000000">mp</span>.<span style="color:#000000">figure</span>(<span style="color:#aa1111">'Entropy'</span>, <span style="color:#000000">facecolor</span>=<span style="color:#aa1111">'lightgray'</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">title</span>(<span style="color:#aa1111">'Entropy'</span>, <span style="color:#000000">fontsize</span>=<span style="color:#116644">20</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">xlabel</span>(<span style="color:#aa1111">'Class Num'</span>, <span style="color:#000000">fontsize</span>=<span style="color:#116644">14</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">ylabel</span>(<span style="color:#aa1111">'Entropy'</span>, <span style="color:#000000">fontsize</span>=<span style="color:#116644">14</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">tick_params</span>(<span style="color:#000000">labelsize</span>=<span style="color:#116644">10</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">grid</span>(<span style="color:#000000">linestyle</span>=<span style="color:#aa1111">'-'</span>)
<span style="color:#000000">x</span> = <span style="color:#000000">np</span>.<span style="color:#000000">arange</span>(<span style="color:#116644">0</span>, <span style="color:#116644">10</span>, <span style="color:#116644">1</span>)
<span style="color:#3300aa">print</span>(<span style="color:#000000">x</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">plot</span>(<span style="color:#000000">x</span>, <span style="color:#000000">entropies</span>, <span style="color:#000000">c</span>=<span style="color:#aa1111">'orangered'</span>, <span style="color:#000000">label</span>=<span style="color:#aa1111">'entropy'</span>)
​
<span style="color:#000000">mp</span>.<span style="color:#000000">legend</span>()
<span style="color:#000000">mp</span>.<span style="color:#000000">show</span>()</span></span>

执行结果:

② 信息增益

决策树根据属性进行判断,将具有相同属性的样本划分到相同节点下,此时,样本比划分之前更加有序(混乱程度降低),信息熵的值有所下降。用划分前的信息熵减去划分后的信息熵,就是决策树获得的信息增益。可以用以下表达式表示:

其中,D表示样本集合,a表示属性,v表示属性可能的取值​, ​表示权重,样本越多的分支对分类结果影响更大,赋予更高的权重, ​表示在样本集合D上使用属性a来划分子节点所获得的信息增益. 以下是一个关于信息增益计算的示例.

说明:

  • 香蕉占2/5,所以​;梨占1/5,所以​;黄瓜占1/5,所以​

  • 根节点信息熵:​

  • 根据颜色划分后:黄色分支信息熵​;绿色分支信息熵​;整个第二层信息熵为​

  • 根据颜色划分后的信息增益:​

由以上示例可知,经过对样本按颜色进行类别划分,划分后的信息熵比原来下降了,下降的值就是信息增益。一般来说,信息增益越大,以该属性划分所获得的“纯度提升”越大. 著名的ID3决策树学习算法就是以信息增益为准则来划分属性.

ID3决策树的缺点:

对于具有很多值的属性它是非常敏感的,例如,如果我们数据集中的某个属性值对不同的样本基本上是不相同的,甚至更极端点,对于每个样本都是唯一的,如果我们用这个属性来划分数据集,它会得到很大的信息增益,但是,这样的结果并不是我们想要的。 ID3算法不能处理具有连续值的属性。 ID3算法不能处理属性具有缺失值的样本。 由于按照上面的算法会生成很深的树,所有容易产生过拟合现象。

③ 增益率

增益率不直接采用信息增益,而采用信息增益与熵值的比率来作为衡量特征优劣的标准. C4.5算法就是使用增益率作为标准来划分属性. 增益率定义为:

其中(划分前的信息熵) --->内在价值

C4.5算法:

ID3算法不能处理具有连续值的属性。而C4.5算法很好地解决了这个问题。(通过二分法将区域进行划分)

ID3算法不能处理具有空值,C4.5可以解决。

④ 基尼系数

基尼系数定义为:(基尼系数越大,不确定性越高,样本越混乱)

直观来说,基尼系数反映了从数据集D中随机抽取两个样本,类别标记不一致的概率. 因此,基尼系数越小,数据集的纯度越高. CART决策树(Classification And Regression Tree)使用基尼系数来选择划分属性,选择属性时,选择划分后基尼值最小的属性作为最优属性. 采用和上式相同的符号表示,数据集D下属性a的基尼系数定义为:

CART决策树:

CART (Classification and Regression Trees)与C4.5算法是非常相似的,但是CART支持预测连续的值(回归),不断通过对连续值的划分,循环划分,最终选出最优质值。CART构建二叉树,而C4.5则不一定。

CART用训练集和交叉验证集不断地评估决策树的性能来修剪决策树,从而使训练误差和测试误差达到一个很好地平衡点。 ————————————————

3)如何停止分裂

以下几种情况会停止决策树子节点的构建:

  • 当前节点所有样本属于同一个类别,无需划分

  • 当前属性集为空,或者所有样本取值相同,无法划分

  • 当前节点包含的样本集合为空,不能划分

  • 当前节点样本数量少于指定数量

4. 如何实现决策树

scikit-learn中决策树相关API:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500"># 模型</span>
<span style="color:#000000">model</span> = <span style="color:#000000">st</span>.<span style="color:#000000">DecisionTreeRegressor</span>(<span style="color:#000000">max_depth</span>=<span style="color:#116644">4</span>)  <span style="color:#aa5500"># 决策树回归器      可用于特征值的提取</span>
<span style="color:#aa5500"># 训练</span>
<span style="color:#000000">model</span>.<span style="color:#000000">fit</span>(<span style="color:#000000">train_x</span>, <span style="color:#000000">train_y</span>)
<span style="color:#aa5500"># 预测</span>
<span style="color:#000000">pre_test_y</span> = <span style="color:#000000">model</span>.<span style="color:#000000">predict</span>(<span style="color:#000000">test_x</span>)</span></span>

【案例】波士顿房价预测

  • 数据集介绍

    该数据集为一个开放房价数据集,包含506笔样本,每个样本包含13个特征和1个标签,具体如下所示:

  • 代码实现

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500"># 决策树回归示例</span>
<span style="color:#aa5500"># 使用决策树预测波士顿房价</span>
​
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">datasets</span> <span style="color:#770088">as</span> <span style="color:#000000">sd</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">utils</span> <span style="color:#770088">as</span> <span style="color:#000000">su</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">tree</span> <span style="color:#770088">as</span> <span style="color:#000000">st</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">ensemble</span> <span style="color:#770088">as</span> <span style="color:#000000">se</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">metrics</span> <span style="color:#770088">as</span> <span style="color:#000000">sm</span>
​
​
<span style="color:#000000">boston</span> = <span style="color:#000000">sd</span>.<span style="color:#000000">load_boston</span>()  <span style="color:#aa5500"># 加载boston地区房价数据</span>
<span style="color:#3300aa">print</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">feature_names</span>)
<span style="color:#3300aa">print</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">data</span>.<span style="color:#000000">shape</span>)
<span style="color:#3300aa">print</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">target</span>.<span style="color:#000000">shape</span>)
​
​
<span style="color:#000000">random_seed</span> = <span style="color:#116644">7</span>  <span style="color:#aa5500"># 随机种子,计算随机值,相同的随机种子得到的随机值一样</span>
<span style="color:#000000">x</span>, <span style="color:#000000">y</span> = <span style="color:#000000">su</span>.<span style="color:#000000">shuffle</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">data</span>, <span style="color:#000000">boston</span>.<span style="color:#000000">target</span>, <span style="color:#000000">random_state</span> = <span style="color:#000000">random_seed</span>)
<span style="color:#aa5500"># 计算训练数据的数量</span>
<span style="color:#000000">train_size</span> = <span style="color:#3300aa">int</span>(<span style="color:#3300aa">len</span>(<span style="color:#000000">x</span>) <span style="color:#981a1a">*</span> <span style="color:#116644">0.8</span>) <span style="color:#aa5500"># 以boston.data中80%的数据作为训练数据</span>
<span style="color:#aa5500"># 构建训练数据、测试数据</span>
<span style="color:#000000">train_x</span> = <span style="color:#000000">x</span>[:<span style="color:#000000">train_size</span>]  <span style="color:#aa5500"># 训练输入, x前面80%的数据</span>
<span style="color:#000000">test_x</span> = <span style="color:#000000">x</span>[<span style="color:#000000">train_size</span>:]   <span style="color:#aa5500"># 测试输入, x后面20%的数据</span>
<span style="color:#000000">train_y</span> = <span style="color:#000000">y</span>[:<span style="color:#000000">train_size</span>]  <span style="color:#aa5500"># 训练输出</span>
<span style="color:#000000">test_y</span> = <span style="color:#000000">y</span>[<span style="color:#000000">train_size</span>:]   <span style="color:#aa5500"># 测试输出</span>
​
<span style="color:#aa5500">######## 单棵树进行预测 ########</span>
<span style="color:#aa5500"># 模型</span>
<span style="color:#000000">model</span> = <span style="color:#000000">st</span>.<span style="color:#000000">DecisionTreeRegressor</span>(<span style="color:#000000">max_depth</span>=<span style="color:#116644">4</span>)  <span style="color:#aa5500"># 决策回归器</span>
​
<span style="color:#aa5500"># 训练</span>
<span style="color:#000000">model</span>.<span style="color:#000000">fit</span>(<span style="color:#000000">train_x</span>, <span style="color:#000000">train_y</span>)
<span style="color:#aa5500"># 预测</span>
<span style="color:#000000">pre_test_y</span> = <span style="color:#000000">model</span>.<span style="color:#000000">predict</span>(<span style="color:#000000">test_x</span>)
<span style="color:#aa5500"># 打印预测输出和实际输出的R2值</span>
<span style="color:#3300aa">print</span>(<span style="color:#000000">sm</span>.<span style="color:#000000">r2_score</span>(<span style="color:#000000">test_y</span>, <span style="color:#000000">pre_test_y</span>))</span></span>
  • 执行结果

<span style="background-color:#f8f8f8"><span style="color:#333333">[<span style="color:#aa1111">'CRIM'</span> <span style="color:#aa1111">'ZN'</span> <span style="color:#aa1111">'INDUS'</span> <span style="color:#aa1111">'CHAS'</span> <span style="color:#aa1111">'NOX'</span> <span style="color:#aa1111">'RM'</span> <span style="color:#aa1111">'AGE'</span> <span style="color:#aa1111">'DIS'</span> <span style="color:#aa1111">'RAD'</span> <span style="color:#aa1111">'TAX'</span> <span style="color:#aa1111">'PTRATIO'</span>
 <span style="color:#aa1111">'B'</span> <span style="color:#aa1111">'LSTAT'</span>]
(<span style="color:#116644">506</span>, <span style="color:#116644">13</span>)
(<span style="color:#116644">506</span>,)
<span style="color:#116644">0.8202560889408634</span></span></span>
  • 特征重要性

作为决策树模型训练过程中的副产品,根据每个特征划分子表前后信息熵减少量就标志了该特征的重要程度,此即为该特征重要性的指标。训练后得到的模型对象提供了属性feature_importances_来存储每个特征的重要性。(是一串数值,可以排序获取它的索引后,通过feature_names[sorted_index]获取特征名)在工程应用上,可以对决策树做一些优化,不必让每一个特征都参与子表划分,而只选择其中较重要的(或者说影响因素较大的)的特征作为子表划分依据。特征重要性的评价指标,就是根据该特征划分子表后所带来的信息熵减少量,熵减越大的就越重要,也就越优先参与子表的划分。

在上述示例中加入如下代码:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">import</span> <span style="color:#000000">matplotlib</span>.<span style="color:#000000">pyplot</span> <span style="color:#770088">as</span> <span style="color:#000000">mp</span>
<span style="color:#770088">import</span> <span style="color:#000000">numpy</span> <span style="color:#770088">as</span> <span style="color:#000000">np</span>
<span style="color:#000000">fi</span> = <span style="color:#000000">model</span>.<span style="color:#000000">feature_importances_</span>  <span style="color:#aa5500"># 获取特征重要性  得到的是值</span>
<span style="color:#3300aa">print</span>(<span style="color:#aa1111">"fi:"</span>, <span style="color:#000000">fi</span>)
​
<span style="color:#aa5500"># 特征重要性可视化</span>
<span style="color:#000000">mp</span>.<span style="color:#000000">figure</span>(<span style="color:#aa1111">"Feature importances"</span>, <span style="color:#000000">facecolor</span>=<span style="color:#aa1111">"lightgray"</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">plot</span>()
<span style="color:#000000">mp</span>.<span style="color:#000000">title</span>(<span style="color:#aa1111">"DT Feature"</span>, <span style="color:#000000">fontsize</span>=<span style="color:#116644">16</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">ylabel</span>(<span style="color:#aa1111">"Feature importances"</span>, <span style="color:#000000">fontsize</span>=<span style="color:#116644">14</span>)
<span style="color:#000000">mp</span>.<span style="color:#000000">grid</span>(<span style="color:#000000">linestyle</span>=<span style="color:#aa1111">":"</span>, <span style="color:#000000">axis</span>=<span style="color:#116644">1</span>)
<span style="color:#000000">x</span> = <span style="color:#000000">np</span>.<span style="color:#000000">arange</span>(<span style="color:#000000">fi</span>.<span style="color:#000000">size</span>)
<span style="color:#000000">sorted_idx</span> = <span style="color:#000000">fi</span>.<span style="color:#000000">argsort</span>()[::<span style="color:#981a1a">-</span><span style="color:#116644">1</span>]  <span style="color:#aa5500"># 重要性排序(倒序) 得到的是排序的index</span>
<span style="color:#000000">fi</span> = <span style="color:#000000">fi</span>[<span style="color:#000000">sorted_idx</span>]  <span style="color:#aa5500"># 根据排序索引重新排特征值</span>
<span style="color:#000000">mp</span>.<span style="color:#000000">xticks</span>(<span style="color:#000000">x</span>, <span style="color:#000000">boston</span>.<span style="color:#000000">feature_names</span>[<span style="color:#000000">sorted_idx</span>]) <span style="color:#aa5500">#这里是获取名字</span>
<span style="color:#000000">mp</span>.<span style="color:#000000">bar</span>(<span style="color:#000000">x</span>, <span style="color:#000000">fi</span>, <span style="color:#116644">0.4</span>, <span style="color:#000000">color</span>=<span style="color:#aa1111">"dodgerblue"</span>, <span style="color:#000000">label</span>=<span style="color:#aa1111">"DT Feature importances"</span>)
​
<span style="color:#000000">mp</span>.<span style="color:#000000">legend</span>()
<span style="color:#000000">mp</span>.<span style="color:#000000">tight_layout</span>()
<span style="color:#000000">mp</span>.<span style="color:#000000">show</span>()</span></span>

执行结果:

 

5. 决策树的剪枝

剪枝(pruning)是决策树学习算法对付“过拟合”的主要手段. 在决策树学习中,为了尽可能正确分类训练样本,节点划分过程将不断重复,有时会造成决策树分支过多,这时就可能因训练样本学的“太好了”,以至于把训练集本身的一些特点当做数据所具有的一般性质而导致过拟合. 因此,可通过主动去掉一些分支来降低过拟合风险.

(1)预剪枝. 决策树生成过程中,对每个节点在划分前进行评估,若当前节点不能带来决策树泛化性能的提升,则停止划分并将当前节点标记为叶子节点.

#先预算生成节点的信息增益,来确定要不要剪枝。占用内存较少。

(2)后剪枝. 先训练为一颗完整的决策树,然后自低向上对非叶子节点进行考察,若将该节点对应的子树替换为叶节点能带来决策树泛化能力提升,则将该子树替换为叶节点.

#生成完整的决策树之后,再计算每个节点根据实际的信息增益来确定剪枝。这种方式更加靠谱,但是它的计算量非常大。

二、集成学习与随机森林

1. 集成学习

集成学习(ensemble learning)通过构建并合并多个模型来完成学习任务,从而获得比单一学习模型更显著优越的泛化性能,简言之,集成学习就是利用模型的“集体智慧”,提升预测的准确率. 根据单个模型方式,集成学习可以分为两大类:

  • 个体间存在强依赖关系,必须串行生成的序列化方法,其代表为Boosting算法;

  • 个体之间不存在强依赖关系,可同时生成的并行化方法,代表是Bagging和随机森林算法.

2. Boosting

1)什么是Boosting

Boosting(直译为推进、提升)是一族可以将弱学习器提升为强学习器的算法,其工作原理是:

  • 先训练出一个初始模型;

  • 根据模型的表现进行调整,使得模型预测错误的数据获得更多的关注,再重新训练下一个模型;(通过权重使得错误样本得到更多的关注,使错误样本在下一轮训练中得到更多的关注)

  • 不断重复第二步,直到模型数量达到预先设定的数目T,最终将这T个模型加权结合.

AdaBoosting是Boosting算法族中最著名的算法,它根据每次训练集之中每个样本的分类是否正确,以及上次的总体分类的准确率,来确定每个样本的权值。将修改过权值的新数据集送给下层分类器进行训练,最后将每次训练得到的分类器最后融合起来,作为最后的决策分类器。

2)实现Boosting

sklearn中,AdaBoosting相关API:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">tree</span> <span style="color:#770088">as</span> <span style="color:#000000">st</span>  <span style="color:#aa5500">#决策树</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">ensemble</span> <span style="color:#770088">as</span> <span style="color:#000000">se</span>  <span style="color:#aa5500">#随机森林</span>
​
<span style="color:#aa5500"># model: 决策树模型(单个模型,基学习器)</span>
<span style="color:#000000">model</span> = <span style="color:#000000">st</span>.<span style="color:#000000">DecisionTreeRegressor</span>(<span style="color:#000000">max_depth</span>=<span style="color:#116644">4</span>)
​
<span style="color:#aa5500"># n_estimators:构建400棵不同权重的决策树,训练模型</span>
<span style="color:#000000">model</span> = <span style="color:#000000">se</span>.<span style="color:#000000">AdaBoostRegressor</span>(<span style="color:#000000">model</span>, <span style="color:#aa5500"># 单模型</span>
                             <span style="color:#000000">n_estimators</span>=<span style="color:#116644">400</span>, <span style="color:#aa5500"># 决策树数量</span>
                             <span style="color:#000000">random_state</span>=<span style="color:#116644">7</span>)<span style="color:#aa5500"># 随机种子</span>
​
<span style="color:#aa5500"># 训练模型</span>
<span style="color:#000000">model</span>.<span style="color:#000000">fit</span>(<span style="color:#000000">train_x</span>, <span style="color:#000000">train_y</span>)
​
<span style="color:#aa5500"># 测试模型</span>
<span style="color:#000000">pred_test_y</span> = <span style="color:#000000">model</span>.<span style="color:#000000">predict</span>(<span style="color:#000000">test_x</span>)</span></span>

代码:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500"># AdaBoosting示例</span>
<span style="color:#aa5500"># 使用AdaBoosting预测波士顿房价</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">datasets</span> <span style="color:#770088">as</span> <span style="color:#000000">sd</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">utils</span> <span style="color:#770088">as</span> <span style="color:#000000">su</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">tree</span> <span style="color:#770088">as</span> <span style="color:#000000">st</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">ensemble</span> <span style="color:#770088">as</span> <span style="color:#000000">se</span>
<span style="color:#770088">import</span> <span style="color:#000000">sklearn</span>.<span style="color:#000000">metrics</span> <span style="color:#770088">as</span> <span style="color:#000000">sm</span>
​
<span style="color:#000000">boston</span> = <span style="color:#000000">sd</span>.<span style="color:#000000">load_boston</span>()  <span style="color:#aa5500"># 加载boston地区房价数据</span>
<span style="color:#3300aa">print</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">feature_names</span>)
<span style="color:#3300aa">print</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">data</span>.<span style="color:#000000">shape</span>)
<span style="color:#3300aa">print</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">target</span>.<span style="color:#000000">shape</span>)
​
<span style="color:#000000">random_seed</span> = <span style="color:#116644">7</span>  <span style="color:#aa5500"># 随机种子,计算随机值,相同的随机种子得到的随机值一样</span>
<span style="color:#000000">x</span>, <span style="color:#000000">y</span> = <span style="color:#000000">su</span>.<span style="color:#000000">shuffle</span>(<span style="color:#000000">boston</span>.<span style="color:#000000">data</span>, <span style="color:#000000">boston</span>.<span style="color:#000000">target</span>, <span style="color:#000000">random_state</span> = <span style="color:#000000">random_seed</span>)
<span style="color:#aa5500"># 计算训练数据的数量</span>
<span style="color:#000000">train_size</span> = <span style="color:#3300aa">int</span>(<span style="color:#3300aa">len</span>(<span style="color:#000000">x</span>) <span style="color:#981a1a">*</span> <span style="color:#116644">0.8</span>) <span style="color:#aa5500"># 以boston.data中80%的数据作为训练数据</span>
<span style="color:#aa5500"># 构建训练数据、测试数据</span>
<span style="color:#000000">train_x</span> = <span style="color:#000000">x</span>[:<span style="color:#000000">train_size</span>]  <span style="color:#aa5500"># 训练输入, x前面80%的数据</span>
<span style="color:#000000">test_x</span> = <span style="color:#000000">x</span>[<span style="color:#000000">train_size</span>:]   <span style="color:#aa5500"># 测试输入, x后面20%的数据</span>
<span style="color:#000000">train_y</span> = <span style="color:#000000">y</span>[:<span style="color:#000000">train_size</span>]  <span style="color:#aa5500"># 训练输出</span>
<span style="color:#000000">test_y</span> = <span style="color:#000000">y</span>[<span style="color:#000000">train_size</span>:]   <span style="color:#aa5500"># 测试输出</span>
​
<span style="color:#000000">model2</span> = <span style="color:#000000">se</span>.<span style="color:#000000">AdaBoostRegressor</span>(<span style="color:#000000">st</span>.<span style="color:#000000">DecisionTreeRegressor</span>(<span style="color:#000000">max_depth</span>=<span style="color:#116644">4</span>),
                              <span style="color:#000000">n_estimators</span>=<span style="color:#116644">400</span>,   <span style="color:#aa5500"># 决策树数量</span>
                              <span style="color:#000000">random_state</span>=<span style="color:#000000">random_seed</span>) <span style="color:#aa5500"># 随机种子</span>
<span style="color:#aa5500"># 训练</span>
<span style="color:#000000">model2</span>.<span style="color:#000000">fit</span>(<span style="color:#000000">train_x</span>, <span style="color:#000000">train_y</span>)
<span style="color:#aa5500"># 预测</span>
<span style="color:#000000">pre_test_y2</span> = <span style="color:#000000">model2</span>.<span style="color:#000000">predict</span>(<span style="color:#000000">test_x</span>)
<span style="color:#aa5500"># 打印预测输出和实际输出的R2值</span>
<span style="color:#3300aa">print</span>(<span style="color:#000000">sm</span>.<span style="color:#000000">r2_score</span>(<span style="color:#000000">test_y</span>, <span style="color:#000000">pre_test_y2</span>))</span></span>

执行结果:

<span style="background-color:#f8f8f8"><span style="color:#333333">['CRIM' 'ZN' 'INDUS' 'CHAS' 'NOX' 'RM' 'AGE' 'DIS' 'RAD' 'TAX' 'PTRATIO'
 'B' 'LSTAT']
(506, 13)
(506,)
0.9068598725149652</span></span>

可以看到,通过AdaBoosting算法,回归模型获得了更高的R2值.

3. 随机森林

1)什么是随机森林

随机森林(Random Forest,简称RF)是专门为决策树分类器设计的一种集成方法,是Bagging法的一种拓展,它是指每次构建决策树模型时,不仅随机选择部分样本,而且还随机选择部分特征来构建多棵决策树. 这样不仅规避了强势样本对预测结果的影响,而且也削弱了强势特征的影响,使模型具有更强的泛化能力.

随机森林简单、容易实现、计算开销小,在很多现实任务中展现出强大的性能,被誉为“代表集成学习技术水平的方法”.

2)如何实现随机森林

sklearn中,随机森林相关API:

<span style="background-color:#f8f8f8"><span style="color:#333333">import sklearn.ensemble as se

model = se.RandomForestRegressor(
    max_depth, # 决策树最大深度
    n_estimators, # 决策树数量
    min_samples_split)# 子表中最小样本数 若小于这个数字,则不再继续向下拆分</span></span>

以下是利用随机森林实现波士顿房价预测的代码:

<span style="background-color:#f8f8f8"><span style="color:#333333"># 使用随机森林预测波士顿房价
import sklearn.datasets as sd
import sklearn.utils as su
import sklearn.tree as st
import sklearn.ensemble as se
import sklearn.metrics as sm

boston = sd.load_boston()  # 加载boston地区房价数据
print(boston.feature_names)
print(boston.data.shape)
print(boston.target.shape)

random_seed = 7  # 随机种子,计算随机值,相同的随机种子得到的随机值一样
x, y = su.shuffle(boston.data, boston.target, random_state=random_seed)
# 计算训练数据的数量
train_size = int(len(x) * 0.8)  # 以boston.data中80%的数据作为训练数据
# 构建训练数据、测试数据
train_x = x[:train_size]  # 训练输入, x前面80%的数据
test_x = x[train_size:]  # 测试输入, x后面20%的数据
train_y = y[:train_size]  # 训练输出
test_y = y[train_size:]  # 测试输出

# 创建随机森林回归器,并进行训练
model = se.RandomForestRegressor(max_depth=10,  # 最大深度
                                 n_estimators=1000,  # 树数量
                                 min_samples_split=2)  # 最小样本数量,小于该数就不再划分子节点
model.fit(train_x, train_y)  # 训练

# 基于统计数据的特征重要性
fi_dy = model.feature_importances_
# print(fi_dy)
pre_test_y = model.predict(test_x)
print(sm.r2_score(test_y, pre_test_y))  # 打印r2得分</span></span>

打印输出:

<span style="background-color:#f8f8f8"><span style="color:#333333">['CRIM' 'ZN' 'INDUS' 'CHAS' 'NOX' 'RM' 'AGE' 'DIS' 'RAD' 'TAX' 'PTRATIO'
 'B' 'LSTAT']
(506, 13)
(506,)
0.9271955403309159</span></span>

三、总结

1)什么是决策树:利用样本特征进行决策归类,将具有相同属性的样本划入一个子节点

2)决策树的用途:用作分类器、回归器

3)如何构建决策树:根据信息熵增益构建(不同的决策树的算法不一样,有ID3-->信息商增益 C4.5-->增益率 CART决策树--->基尼系数

4)什么情况下使用决策树:实用性较广,课用于一般回归、分类问题

5)决策树优化:集成学习、随机森林

四、练习

(1)有一批水果(如下图所以),按照形状进行分类,将长条形、椭圆形各划分到不同子节点中,计算划分后的信息增益.

(2)一批样本包含A和B两个类别,计算:当A类别比率依次占0%, 10%, 20%, ..., 100%时,这批样本信息熵值,并以占比作为x轴数值、信息熵作为y轴数值绘制图像.

延伸阅读

  • VMware公司使用定制的决策树进行定价优化

<span style="background-color:#f8f8f8"><span style="color:#333333">VMware(VMW)是一家提供虚拟化技术、终端服务和云处理的公司,它将产品销售给B2B客户。长期以来,VMW公司的产品价格罕有变动。当接收到大订单的时候,销售代表会通过销售人员特别折扣(Sales Person Specific discount,SPF)标识来给出特定折扣。而VMW的定价部门则希望找到一种方法来优化其产品定价。在各个商业领域,市场上都有着对应的解决定价问题的数据挖掘解决方案。解决方案的目标不仅是优化定价,同时还要让客户的利益最大化。

VMW公司的分析和数据科学小组通过分析历史价格和相应的销量变化,来理解折扣百分比与SPF标识的关联性,并以此为依据归纳出所有产品的推荐定价。传统的定价优化会根据数量变化来进行价格变动,但是VMW公司并不会改变价格,而是使用折扣作为替代方法,但是使用折扣需要额外的步骤来确定是否需要给出折扣以及折扣率。
小组使用决策树的方法,基于折扣率和SPF标识的使用情况来对所有订单进行分类。根据业务的需求,以一种特定顺序构建出多分支(非二元)决策树。各种可能订单定价的属性都在决策树构建中被考虑进来。决策树构建过程中,基于均方误差、熵、log-loss、Gini指标等确定了决策树构建过程中分支属性的顺序。相比于使用标准分裂标准,使用的是根据业务需求定制的分裂标准。分裂停止标准是最小化观测对象数目。针对完成的分块,基于分块的属性特性观察其折扣百分比与SPF使用情况的关联性,并完成产品平台级的定价推荐。</span></span>

使用python中的pymsql完成如下:表结构与数据创建 1. 建立 `users` 表和 `orders` 表。 `users` 表有用户ID、用户名、年龄字段,(id,name,age) `orders` 表有订单ID、订单日期、订单金额,用户id字段。(id,order_date,amount,user_id) 2 两表的id作为主键,`orders` 表用户id为users的外键 3 插入数据 `users` (1, '张三', 18), (2, '李四', 20), (3, '王五', 22), (4, '赵六', 25), (5, '钱七', 28); `orders` (1, '2021-09-01', 500, 1), (2, '2021-09-02', 1000, 2), (3, '2021-09-03', 600, 3), (4, '2021-09-04', 800, 4), (5, '2021-09-05', 1500, 5), (6, '2021-09-06', 1200, 3), (7, '2021-09-07', 2000, 1), (8, '2021-09-08', 300, 2), (9, '2021-09-09', 700, 5), (10, '2021-09-10', 900, 4); 查询语句 1. 查询订单总金额 2. 查询所有用户的平均年龄,并将结果四舍五入保留两位小数。 3. 查询订单总数最多的用户的姓名和订单总数。 4. 查询所有不重复的年龄。 5. 查询订单日期在2021年9月1日至9月4日之间的订单总金额。 6. 查询年龄不大于25岁的用户的订单数量,并按照降序排序。 7. 查询订单总金额排名前3的用户的姓名和订单总金额。 8. 查询订单总金额最大的用户的姓名和订单总金额。 9. 查询订单总金额最小的用户的姓名和订单总金额。 10. 查询所有名字中含有“李”的用户,按照名字升序排序。 11. 查询所有年龄大于20岁的用户,按照年龄降序排序,并只显示前5条记录。 12. 查询每个用户的订单数量和订单总金额,并按照总金额降序排序。
06-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值