一个决策的做出,需要考虑一系列盘根错节的问题。

决策树是一个通过特征学习决策规则,用于预测目标的监督机器学习模型。顾名思义,该模型通过提出一系列的问题将数据进行分解,从而做出决策。

下图示例中用决策树决定某一天的活动:


pyspark特征工程机器学习 python特征分析_子节点


根据训练集的特征,决策树模型学习一系列问题来推断样本的类标签。从图中可以看出,如果可解读性是重要因素,决策树模型是个不错的选择。

尽管上图显示了基于分类目标(分类)的决策树的概念,但如果目标为实数,它也同样使用(回归)。

本教程将讨论如何使用Python的scikit-learn库构建决策树模型。其中将包括:

· 决策树的基本概念

· 决策树学习算法背后的计算

· 信息增益和不纯性度量

· 分类树

· 回归树

让我们开始吧!

本教程是参考Next Tech的Python机器学习系列而编写的。该系列带领学员通过Python了解机器学习和深度学习算法,实现从小白到大师的转变。它包括一个浏览器模式的沙箱环境,里头预装了所有必要的软件和库,还包括使用公共数据集的项目。


pyspark特征工程机器学习 python特征分析_子节点_02


决策树的基本概念

决策树是通过递归拆分构成的——先从根节点开始(也称为父节点),将每个节点分为左右子节点。这些节点可以再进一步分裂成其他子节点。

比如说上图中,根节点为Work to do?,然后根据是否有活动需要完成而分裂为子节点Stay in和Outlook。Outlook节点再继续分裂为三个子节点。

那么,如何确定各个节点的最佳分裂点呢?

从根节点开始,数据在能产生最大信息增益 (IG) 的特征上产生分裂(下文将有更详细的解释)。在迭代过程中,该分裂过程将在每个子节点持续重复,直到所有的叶子达到纯性为止,即每个节点的样本都属于同一类。

在实践中,可能会形成节点过多的树,导致过度拟合。因此,一般情况下会通过限制树的最大深度来进行剪枝。


pyspark特征工程机器学习 python特征分析_子节点_02


信息增益最大化

为了在最具信息的特征分裂节点,首先必须定义一个目标函数,并通过树学习算法对其进行优化。这里,目标函数是在各个分裂点处实现最大化的信息增益,定义如下:


pyspark特征工程机器学习 python特征分析_pyspark特征工程机器学习_04


方程式中,f为执行分裂的特征,Dp,Dleft和Dright分别为为父子节点的数据集。I为不纯性度量,Np为父节点上样本的总数,而Nleft和Nright为子节点的样本数量。

在下面的例子中,本文将更详细地讨论用于分类和回归决策树的不纯性度量。但现在,只需理解信息增益简单来说就是父节点不纯性和子节点不纯性之和之间的差值,子节点的不纯性越低,则信息增益越大。

注意,上面的方程式只适用于二叉决策树,即每个父节点只分裂为两个子节点。若一个决策树包含超过两个节点,那么只需求所有节点的不纯性的总和即可。


pyspark特征工程机器学习 python特征分析_子节点_02


分类树

首先讨论分类决策树(也称为分类树)。下面的例子将使用费雪鸢尾花卉(iris)数据集,机器学习领域的经典数据集。它包含了来自三个不同物种的150朵鸢尾花的属性,分别是Setosa, Versicolor和Virginica。这些将是本里的目标。本例旨在预测某个鸢尾花属于哪一种类。将花瓣长度和宽度(以厘米为单位)储存为列,也称为该数据集的特征。

数据集传送门:https://archive.ics.uci.edu/ml/datasets/iris

首先导入数据集,并将特征设为x,目标为y:

from sklearn import datasets iris = datasets.load_iris() # Load iris dataset X = iris.data[:, [2, 3]] # Assign matrix Xy = iris.target #Assign vector y

使用scikit-learn训练一个最大深度为4的决策树。代码如下:

from sklearn.tree import DecisionTreeClassifier # Import decision tree classifier model tree = DecisionTreeClassifier(criterion='entropy', # Initialize and fitclassifier max_depth=4, random_state=1)tree.fit(X, y)

注意,在这里criterion被设为‘熵’。该标准被称为不纯性度量(上文有提到)。在分类中,熵是最常见的不纯性度量或分裂标准。它的定义如下:


pyspark特征工程机器学习 python特征分析_子节点_06


方程式中,p(i|t) 为一个特定节点t中属于c类样本的部分。因此,如果一个节点上的所有样本都属于同一类,则熵值为0;如果类型均匀分布,则熵值最大。

为了能更直观地了解熵,在此编写类1概率范围 [0,1] 的不纯性指数。代码如下:

import numpy as npimport matplotlib.pyplot as plt def entropy(p): return - p * np.log2(p) - (1- p) * np.log2(1 - p)x = np.arange(0.0, 1.0, 0.01) # Create dummy datae = [entropy(p) if p != 0 else None for p in x] # Calculate entropyplt.plot(x, e, label='entropy', color='r') # Plot impurity indicesfor y in [0.5, 1.0]: plt.axhline(y=y, linewidth=1,color='k',linestyle='--')plt.xlabel('p(i=1)')plt.ylabel('Impurity Index')plt.legend()plt.show()


pyspark特征工程机器学习 python特征分析_pyspark特征工程机器学习_07


正如所见,当p(i=1|t)= 1时,熵值为0。而当所有类型均匀分布,而p(i=1|t)= 0.5时,熵值为1.

现在回到iris的例子,本文将把训练好的分类树可视化,然后观察熵值如何决定每次的分裂。

scikit-learn有一个很好的功能,它允许用户在训练之后将决策树导出为.dot文件,然后可以使用GraphViz之类的软件将其可视化。除了GraphViz之外,还将使用一个名为pydotplus的Python库。它具有类似于GraphViz的功能,可将.dot数据文件转换为决策树图像文件。

若要安装pydotplus和graphviz,可在终端执行下列指令:

pip3 install pydotplusapt install graphviz

下列代码可以PNG格式创建本例的决策树图像:

from pydotplus.graphviz import graph_from_dot_datafrom sklearn.tree import export_graphviz dot_data = export_graphviz( # Create dot data tree, filled=True, rounded=True, class_names=['Setosa','Versicolor','Virginica'], feature_names=['petallength', 'petal width'], out_file=None) graph = graph_from_dot_data(dot_data) # Create graph from dot datagraph.write_png('tree.png') # Write graphto PNG image


pyspark特征工程机器学习 python特征分析_pyspark特征工程机器学习_08

tree.png


从存在图像文件tree.png的决策树图中,可观察到决策树根据训练数据中所进行的分裂点。在根节点处先从150个样本开始,然后根据花瓣宽度是否≤1.75厘米为分裂点,分成两个子节点,各有50和100个样本。在第一次分裂后,可看出左子节点已达纯性,只包含setosa类的样本(熵值 = 0)。而右边进一步分裂,将样本分为versicolor和virginica类。

从最终熵值可看出深度为4的决策树在对花进行分类方面表现得很好。


pyspark特征工程机器学习 python特征分析_子节点_02


回归树

回归树的例子本文将使用波士顿房价(Boston Housing)数据集。这是另一个非常流行的数据集,包含了波士顿教区房屋的信息,共有506个样本和14个属性。出于简化和可视化的考量,这里将只使用两个属性,即MEDV(屋主自住房屋价值的中位数,单元为1000美元)为目标,LSTAT(地位较低的人口比率)为特征。

数据集传送门:

https://www.cs.toronto.edu/~delve/data/boston/bostonDetail.html

首先,将必需的属性从scikit-learn导入到pandas 数据帧DataFrame中。

import pandas as pdfrom sklearn import datasets boston = datasets.load_boston() # Load Boston Datasetdf = pd.DataFrame(boston.data[:, 12]) # Create DataFrame using only the LSATfeaturedf.columns = ['LSTAT']df['MEDV'] = boston.target # Create new column with the targetMEDVdf.head()


pyspark特征工程机器学习 python特征分析_pyspark特征工程机器学习_10


使用scikit-learn中的工具DecisionTreeRegressor来训练回归树:

from sklearn.tree import DecisionTreeRegressor # Import decision tree regression model X = df[['LSTAT']].values # Assign matrix Xy = df['MEDV'].values # Assign vector y sort_idx = X.flatten().argsort() # Sort X and y by ascendingvalues of XX = X[sort_idx]y = y[sort_idx] tree = DecisionTreeRegressor(criterion='mse', # Initialize and fit regressor max_depth=3) tree.fit(X, y)

注意,这里的criterion与分类树中所用的不同。在分类时,熵作为不纯性度量是一个很有用的标准。然而,若将决策树用于回归,则需要一个适合连续变量的不纯性度量,因此这里使用子节点的加权均方误差 (MSE) 来定义不纯性度量:


pyspark特征工程机器学习 python特征分析_决策树_11


方程式中,Nt为节点t的训练样本数量,Dt为节点t的训练子集,y(i)为真实目标值,而ŷt为预测目标值(样本均值):


pyspark特征工程机器学习 python特征分析_子节点_12


现在,将MEDV和LSTAT之间的关系进行建模,看看回归树的直线拟合是什么样的:

plt.figure(figsize=(16, 8))plt.scatter(X, y, c='steelblue', # Plot actual target againstfeatures edgecolor='white',s=70)plt.plot(X, tree.predict(X), # Plot predicted targetagainst features color='black', lw=2)plt.xlabel('% lower status of the population [LSTAT]')plt.ylabel('Price in $1000s [MEDV]')plt.show()


pyspark特征工程机器学习 python特征分析_子节点_13


从上图可看出,深度为3的决策树就能反映数据的总体趋势。

本文讨论了决策树的基本概念,最小化不纯性的算法,以及如何创建用于分类和回归的决策树。

在实践中,为树选择合适的深度是很重要的,以避免数据过度拟合或拟合不足。了解如何将决策树结合成整体的随机森林也是有益的,基于其随机性,通常比单个决策树具有更好的泛化性能。这有助于降低模型的方差。此外,它对数据集中的异常值不太敏感,不需要太多的参数调优。


pyspark特征工程机器学习 python特征分析_pyspark特征工程机器学习_14