基于决策树算法完成鸢尾花的分类并使用scikit-learn进行交叉验证

专栏推荐

(此处已添加圈子卡片,请到今日头条客户端查看)

正文

这个demo我们要演示机器学习算法中的决策树实现,我们还是使用鸢尾花数据集,这个数据集有四个特征,而类别有4个,我们根据这四个特征进行决策,然后最后构造出一棵决策树,最终决策的结果就是对这个数据集中的鸢尾花类别进行分类。

首先我们先来读取一下这个鸢尾花的数据,因为鸢尾花的数据是没有列名的,所以第一步我们给这个数据集来添加一下类名,也就是标签名和类别名。

import pandas as pd

iris_data = pd.read_csv('iris.data')

iris_data.columns = ['sepal_length_cm', 'sepal_width_cm', 'petal_length_cm', 'petal_width_cm', 'class']

print iris_data.head()

这个就是鸢尾花中的前五行数据,我们发现每一列都已经添加了特征名,最后一列class为标签名。

我有一张鸢尾花的图片,我们可以发现有一个叫做sepal叫做花萼,有一个叫做petal叫做花瓣,这个花萼和花瓣分别有长度和宽度,所以一共构成了四个特征:花萼的长度,花萼的宽度,花瓣的长度,花瓣的宽度。

我们先来使用python来读取一下这个图片,然后再来显示一下。


import matplotlib.pyplot as plt

from PIL import Image

img=Image.open('test.jpg')

plt.imshow(img)

plt.show()


这个代码很简单就是读取一个图片然后显示。

我们可以使用iris_data.describe()方法,来看我们对鸢尾花这一数据集的数学描述

我们可以看出列为特征,一行为count总数,mean表示均值,std为标准查,min最小值,max最大值,25%为4分位,50%为二分位,75%为4分之3分位。

我们现在先来使用可视化的方式来看一下鸢尾花数据集中特征和特征之间的关系


import pandas as pd

import matplotlib.pyplot as plt

import seaborn as sb

sb.pairplot(iris_data.dropna(), hue='class')

plt.show()


使用seaborn画图会简单许多,pairplot画图会很给力,它会自动讲数据集中的特征进行两两组合进行画图。效果如下所示:

其中对角线位置因为是一个特征,所以它就化成了柱状图

这里来再画一个图,画小提琴图,这样可以更加直观的看出在相同特征之间不同类别之间的差距

我们画出来的小提琴图如图所示,越宽表示越集中,比如在特征sepal_length=5的时候iris-setosa那个地方很宽,这就表示sepal_length为5的地方这张鸢尾花的数据很多。我在小提琴图中画了两条黑色的直线,可以看出最上面的那条黑色直线并没有分开三个类别,而下面的那条直线很好的分开了三个类别(一条线上面为两个类别,下面为一个类别),所以我们可以说下面那个特征决策效果很好


画小提琴的代码为:

plt.figure(figsize=(10, 10)指定绘图区域

for column_index, column in enumerate(iris_data.columns):if column == 'class':continueplt.subplot(2, 2, column_index + 1)指定子图,column_index从0,1,2,3sb.violinplot(x='class', y=column, data=iris_data)在子图上画图

plt.show()


我们输出鸢尾花的数据的时候,发现它都排好序了,也就是说如果我们取前面百分之70作为训练集,而取百分之30作为测试集是不行的,所以我们可以先把数据集打乱,然后随机挑选出百分之七十的数据作为训练集,那么剩下的当作测试集,幸运的是,sklearn已经封装好了类似的功能我们直接调用就好了。

这个地方因为要获取很多列的数据,所以我们使用[列名列表]

train_test_split第一个参数为数据集的样本,第二个为数据集中的标签,第三个为指定训练集的的占比,这里我们指定总样本的百分之75为训练样本,那么剩下的样本就是测试样本了。

现在我们有了训练数据和测试数据,那么我们下面的任务就是构造决策树,使用训练数据来拟合这颗决策树,然后再来验证我们测试集中的数据,看准确度是多少。

我们先创建一棵决策树decision_tree_classifier,然后使用训练数据来拟合这颗决策树,拟合之后我们可以测试我们的测试集数据,输出b,就是测试的准确度,准确度为:0.955555555556

其中DecisionTreeClassifier的参数有很多

1.criterion用什么指标: gini(基尼系数), entropy(信息增益)。一般说使用默认的基尼系数"gini"就可以了,即CART算法。除非你非得使用ID3, C4.5的最优特征选择方法。

2.splitter连续的特征从什么地方切分: best,random 前者是在所有特征中找最好的切分点而random是后者是在部分特征中(数据量大的时候)。

3.max_features最大使用多少个特征 :None(默认none为所有)log2(意味着划分时最多考虑log2N个特征),sqrt或者"auto"意味着划分时最多考虑根号N个特征,还可以max_features=整数,如果是整数,代表考虑的特征绝对数。如果是浮点数max_features=0.5,代表考虑特征百分比,即考虑(百分比xN)取整后的特征数。其中N为样本总特征数。N 特征小于50的时候一般使用所有的。

4.max_depth预剪枝(最大深度): 数据少或者特征少的时候可以不管这个值,如果模型样本量多,特征也多的情况下,可以尝试限制下具体的取值取决于数据的分布。常用的可以取值10-100之间。

5.min_samples_split(节点样本个数):这个值限制了子树继续划分的条件,如果某节点的样本数少于min_samples_split,则不会继续再尝试选择最优特征来进行划分,如果样本量不大,不需要管这个值。如果样本量数量级非常大,则可以增大这个值。如果你有大概10万样本,建立决策树时,大概选择min_samples_split=10是差不多的。

6.min_samples_leaf(叶子节点最少的样本数):这个值限制了叶子节点最少的样本数,如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝,默认是1,如果样本量不大,不需要管这个值,如果要是样本数比较大的话可以使用这个参数,我们可以增大这个值,比如如果项目要是有10万样本的话,min_samples_leaf的值为5比较合适,当然实际情况可以自己来调整。

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

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

9.class_weight 指定样本各类别的的权重,主要是为了防止训练集某些类别的样本过多,导致训练的决策树过于偏向这些类别。这里可以自己指定各个样本的权重,如果使用“balanced”,则算法会自己计算权重,样本量少的类别所对应的样本权重会高。如果你的样本类别分布没有明显的偏倚,则可以不管这个参数,使用默认的"None"就ok了。

10.min_impurity_split(节点划分最小不纯度):这个值限制了决策树的增长,如果某节点的不纯度(基尼系数,信息增益,均方差,绝对差)小于这个阈值,则该节点不再生成子节点,就成为了叶子节点 。

11.presort(数据是否预排序):这个值是布尔值,默认是False不排序。排序就是在建树的过程中让划分点选择的更快,使得决策树建立的更快,但是使用这个排序功能的话,在样本数据很多的情况下,这个功能会耗费很多的时间,所以,一般数据很多的情况下是不用使用这个参数的,要是样本不是很多的情况下,其实也没有必要使用,因为样本本来就不多就直接建树就ok了,如果进行排序的话,这个操作简直就是多此一举,所以这个参数用处不大的。

12.min_impurity_decrease:如果这个分裂导致不纯度的降低大于或等于这个值,那么这个节点将被分割。(也不是很常用)。

13. random_state:值为int, RandomState实例或None(默认)。

以上就是我们使用sklearn库建造决策分类树时的一些参数,有些参数比较重要,有些参数不是很重要,

决策树很容易过拟合的种情况是特征数远远大于样本数,这种情况下,我们可以进行降维,比如主成分分析(PCA),特征选择(Losso)或者独立成分分析(ICA),这样拟合决策树模型效果会好。我们在训练的时候如果我们的样本集并不是很均衡,也就是样本的类别不均衡,我们可以使用class_weight来限制类别多的样本。如果输入的样本矩阵是稀疏的,推荐在拟合前调用csc_matrix稀疏化,在预测前调用csr_matrix稀疏化。建造树的时候,可以主要使用树的高度这个参数进行限制,然后进行建造,等建造完成之后,使用graphviz工具来看当前建造的树是否符合我们的要求,如果不满足的话,可以调整这个参数。还要善用使用min_samples_split和min_samples_leaf参数来控制叶子节点的样本数量来有效防止过拟合。

以上的树是分类树(DecisionTreeClassifier)的一些常用的参数,回归树(DecisionTreeClassifier)的调参和这个分类树有一些不同,这个是需要我们注意一下的。

criterion: 可以使用"mse"或者"mae",前者是均方差,后者是和均值之差的绝对值之和。推荐使用默认的"mse"。一般来说"mse"比"mae"更加精确。

其它的参数和上面的分类树是一样的,只不过参数class_weight在回归树种是没有的。

调参代码:

import pandas as pd

from sklearn.datasets import load_iris

from sklearn import tree

import pydotplus

from sklearn.model_selection import GridSearchCV

from sklearn.model_selection import train_test_split

from sklearn.model_selection import cross_val_score

from sklearn import metrics

iris_data = pd.read_csv('iris.data')

iris_data.columns = ['sepal_length_cm', 'sepal_width_cm', 'petal_length_cm', 'petal_width_cm', 'class']

all_inputs = iris_data[['sepal_length_cm', 'sepal_width_cm','petal_length_cm', 'petal_width_cm']].values

all_classes = iris_data['class'].values

decision_tree_classifier= tree.DecisionTreeClassifier()#构造分类树

parameters = {'max_depth': [1, 2, 3, 4, 5,6,7,8,9,10],

'max_features': [1, 2, 3, 4],

'min_samples_split':[2,3,4,5],

'min_samples_leaf':[2,3,4,5]

}

training_inputs,testing_inputs,training_classes,testing_classes = train_test_split(all_inputs, all_classes, train_size=0.7, random_state=1)

if __name__ == "__main__":

decision_tree_classifier = tree.DecisionTreeClassifier()

clf = GridSearchCV(decision_tree_classifier, parameters, n_jobs=-1)

clf.fit(training_inputs,training_classes)

print (clf.best_params_)

print (clf.best_score_)

ypred = clf.predict(testing_inputs)

print(metrics.classification_report(testing_classes,ypred))

结果为:

可以看出当参数min_samples_leaf=5,max_depth=3,max_features=2,min_samples_split=5时训练准确率为最高的。

因为在实际的训练中,训练的结果对于训练集的拟合程度通常还是挺好的(初试条件敏感),但是对于训练集之外的数据的拟合程度通常就不那么令人满意了。因此我们通常并不会把所有的数据集都拿来训练,而是分出一部分来(这一部分不参加训练)对训练集生成的参数进行测试,相对客观的判断这些参数对训练集之外的数据的符合程度。这种思想就称为交叉验证(Cross Validation)

K折交叉验证(k-fold)

在机器学习中,将数据集A分为训练集(training set)B和测试集(test set)C,在样本量不充足的情况下,为了充分利用数据集对算法效果进行测试,将数据集A随机分为k个包,每次将其中一个包作为测试集,剩下k-1个包作为训练集进行训练。这样一共可以对分类器做k次训练,并且得到k个训练结果。

代码为:

from sklearn.model_selection import train_test_split

from sklearn.model_selection import cross_val_score

decision_tree_classifier = DecisionTreeClassifier()

cv_scores = cross_val_score(decision_tree_classifier, all_inputs, all_classes, cv=10)

cross_val_score的 参数为all_inputs:features all_classes:targets cv:k

这样我们输出cv_scores 的结果为:

我们这个程序分成了10份,所以我们现在会有10个测试结果,我们将其可视化,效果为:

sb.distplot(cv_scores)

plt.title('Average score: {}'.format(np.mean(cv_scores)))

plt.show()


我们前面学习了很多DecisionTreeClassifier()的参数可以用他们来限制决策树的建立,我们现在建立一棵其它的决策树,然后使用k这交叉验证方法来测试这颗决策树。

decision_tree_classifier = DecisionTreeClassifier(max_depth=1)cv_scores = cross_val_score(decision_tree_classifier, all_inputs, all_classes, cv=10)print (cv_scores)sb.distplot(cv_scores, kde=False)plt.title('Average score: {}'.format(np.mean(cv_scores)))plt.show()


StratifiedKFold用法类似Kfold,但是他是分层采样,确保训练集,测试集中各类别样本的比例与原始数据集中相同。

举报
评论 0