Python机器学习(1)——决策树分类算法

摘要:
J、 1975年,罗斯·昆兰提议将信息熵的概念引入决策树的构建中,这被称为ID3算法。在这种情况下,决策树的任务是找到一些身高和体重的临界值,根据大于或小于这些临界值的逻辑对样本进行成对分类,并从上到下构建决策树。使用python机器学习库非常简单和优雅。

1、决策树算法

决策树用树形结构对样本的属性进行分类,是最直观的分类算法,而且也可以用于回归。不过对于一些特殊的逻辑分类会有困难。典型的如异或(XOR)逻辑,决策树并不擅长解决此类问题。

决策树的构建不是唯一的,遗憾的是最优决策树的构建属于NP问题。因此如何构建一棵好的决策树是研究的重点。

J. Ross Quinlan在1975提出将信息熵的概念引入决策树的构建,这就是鼎鼎大名的ID3算法。后续的C4.5, C5.0, CART等都是该方法的改进。

熵就是“无序,混乱”的程度。刚接触这个概念可能会有些迷惑。想快速了解如何用信息熵增益划分属性,可以参考这位兄弟的文章:http://blog.csdn.net/alvine008/article/details/37760639

如果还不理解,请看下面这个例子。

假设要构建这么一个自动选好苹果的决策树,简单起见,我只让他学习下面这4个样本:

样本    红     大      好苹果
0       1      1         1
1       1      0         1
2       0      1         0
3       0      0         0

样本中有2个属性,A0表示是否红苹果。A1表示是否大苹果。

那么这个样本在分类前的信息熵就是S = -(1/2 * log(1/2) +1/2 * log(1/2)) = 1。

信息熵为1表示当前处于最混乱,最无序的状态。

本例仅2个属性。那么很自然一共就只可能有2棵决策树,如下图所示:

Python机器学习(1)——决策树分类算法第1张

显然左边先使用A0(红色)做划分依据的决策树要优于右边用A1(大小)做划分依据的决策树。

当然这是直觉的认知。定量的考察,则需要计算每种划分情况的信息熵增益。

先选A0作划分,各子节点信息熵计算如下:

0,1叶子节点有2个正例,0个负例。信息熵为:e1 = -(2/2 * log(2/2) + 0/2 * log(0/2)) = 0。

2,3叶子节点有0个正例,2个负例。信息熵为:e2 =-(0/2 * log(0/2) + 2/2 * log(2/2)) = 0。

因此选择A0划分后的信息熵为每个子节点的信息熵所占比重的加权和:E = e1*2/4 + e2*2/4 = 0。

选择A0做划分的信息熵增益G(S, A0)=S - E = 1 - 0 = 1.

事实上,决策树叶子节点表示已经都属于相同类别,因此信息熵一定为0。

同样的,如果先选A1作划分,各子节点信息熵计算如下:

0,2子节点有1个正例,1个负例。信息熵为:e1 = -(1/2 * log(1/2) + 1/2 * log(1/2)) = 1。

1,3子节点有1个正例,1个负例。信息熵为:e2 =-(1/2 * log(1/2) + 1/2 * log(1/2)) = 1。

因此选择A1划分后的信息熵为每个子节点的信息熵所占比重的加权和:E = e1*2/4 + e2*2/4 = 1。也就是说分了跟没分一样!

选择A1做划分的信息熵增益G(S, A1)=S - E = 1 - 1 = 0.

因此,每次划分之前,我们只需要计算出信息熵增益最大的那种划分即可。

2、数据集

为方便讲解与理解,我们使用如下一个极其简单的测试数据集:

1.5 50thin
1.5 60fat
1.6 40thin
1.6 60fat
1.7 60thin
1.7 80fat
1.8 60thin
1.8 90fat
1.9 70thin
1.9 80 fat

这个数据一共有10个样本,每个样本有2个属性,分别为身高和体重,第三列为类别标签,表示“胖”或“瘦”。该数据保存在1.txt中。

我们的任务就是训练一个决策树分类器,输入身高和体重,分类器能给出这个人是胖子还是瘦子。

(数据是作者主观臆断,具有一定逻辑性,但请无视其合理性)

决策树对于“是非”的二值逻辑的分枝相当自然。而在本数据集中,身高与体重是连续值怎么办呢?

虽然麻烦一点,不过这也不是问题,只需要找到将这些连续值划分为不同区间的中间点,就转换成了二值逻辑问题。

本例决策树的任务是找到身高、体重中的一些临界值,按照大于或者小于这些临界值的逻辑将其样本两两分类,自顶向下构建决策树。

使用python的机器学习库,实现起来相当简单和优雅。

3、Python实现

Python代码实现如下:

importnumpy as np
importscipy as sp
from sklearn importtree
from sklearn.metrics importprecision_recall_curve
from sklearn.metrics importclassification_report
from sklearn.cross_validation importtrain_test_split
 
 
'''数据读入 '''data   =[]
labels =[]
with open("data\1.txt") as ifile:
        for line inifile:
            tokens = line.strip().split(' ')
            data.append([float(tk) for tk in tokens[:-1]])
            labels.append(tokens[-1])
x =np.array(data)
labels =np.array(labels)
y =np.zeros(labels.shape)
 
 
'''标签转换为0/1 '''y[labels=='fat']=1
 
'''拆分训练数据与测试数据 '''x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2)
 
'''使用信息熵作为划分标准,对决策树进行训练 '''clf = tree.DecisionTreeClassifier(criterion='entropy')
print(clf)
clf.fit(x_train, y_train)
 
'''把决策树结构写入文件 '''with open("tree.dot", 'w') as f:
    f = tree.export_graphviz(clf, out_file=f)
    
'''系数反映每个特征的影响力。越大表示该特征在分类中起到的作用越大 '''
print(clf.feature_importances_)
 
'''测试结果的打印'''answer =clf.predict(x_train)
print(x_train)
print(answer)
print(y_train)
print(np.mean( answer ==y_train))
 
'''准确率与召回率'''precision, recall, thresholds =precision_recall_curve(y_train, clf.predict(x_train))
answer = clf.predict_proba(x)[:,1]
print(classification_report(y, answer, target_names = ['thin', 'fat']))

输出结果类似如下所示:

[ 0.2488562 0.7511438]
array([[ 1.6, 60. ],
[ 1.7, 60. ],
[ 1.9, 80. ],
[ 1.5, 50. ],
[ 1.6, 40. ],
[ 1.7, 80. ],
[ 1.8, 90. ],
[ 1.5, 60. ]])
array([ 1., 0., 1., 0., 0., 1., 1., 1.])
array([ 1., 0., 1., 0., 0., 1., 1., 1.])
1.0

precision recall f1-score support
thin 0.83 1.00 0.91 5
fat 1.00 0.80 0.89 5

avg / total 1.00 1.00 1.00 8

array([ 0., 1., 0., 1., 0., 1., 0., 1., 0., 0.])
array([ 0., 1., 0., 1., 0., 1., 0., 1., 0., 1.])

可以看到,对训练过的数据做测试,准确率是100%。但是最后将所有数据进行测试,会出现1个测试样本分类错误。

说明本例的决策树对训练集的规则吸收的很好,但是预测性稍微差点。

这里有3点需要说明,这在以后的机器学习中都会用到。

1、拆分训练数据与测试数据。

这样做是为了方便做交叉检验。交叉检验是为了充分测试分类器的稳定性。

代码中的0.2表示随机取20%的数据作为测试用。其余80%用于训练决策树。

也就是说10个样本中随机取8个训练。本文数据集小,这里的目的是可以看到由于取的训练数据随机,每次构建的决策树都不一样。

2、特征的不同影响因子。

样本的不同特征对分类的影响权重差异会很大。分类结束后看看每个样本对分类的影响度也是很重要的。

在本例中,身高的权重为0.25,体重为0.75,可以看到重量的重要性远远高于身高。对于胖瘦的判定而言,这也是相当符合逻辑的。

3、准确率与召回率。

这2个值是评判分类准确率的一个重要标准。比如代码的最后将所有10个样本输入分类器进行测试的结果:

测试结果:array([ 0., 1., 0., 1., 0., 1., 0., 1., 0., 0.])
真实结果:array([ 0., 1., 0., 1., 0., 1., 0., 1., 0., 1.])

分为thin的准确率为0.83。是因为分类器分出了6个thin,其中正确的有5个,因此分为thin的准确率为5/6=0.83。

分为thin的召回率为1.00。是因为数据集中共有5个thin,而分类器把他们都分对了(虽然把一个fat分成了thin!),召回率5/5=1。

分为fat的准确率为1.00。不再赘述。

分为fat的召回率为0.80。是因为数据集中共有5个fat,而分类器只分出了4个(把一个fat分成了thin!),召回率4/5=0.80。

很多时候,尤其是数据分类难度较大的情况,准确率与召回率往往是矛盾的。你可能需要根据你的需要找到最佳的一个平衡点。

比如本例中,你的目标是尽可能保证找出来的胖子是真胖子(准确率),还是保证尽可能找到更多的胖子(召回率)。

代码还把决策树的结构写入了tree.dot中。打开该文件,很容易画出决策树,还可以看到决策树的更多分类信息。

本文的tree.dot如下所示:

digraph Tree {
0 [label="X[1] <= 55.0000
entropy = 0.954434002925
samples = 8", shape="box"] ;
1 [label="entropy = 0.0000
samples = 2
value = [ 2.  0.]", shape="box"] ;
0 -> 1;
2 [label="X[1] <= 70.0000
entropy = 0.650022421648
samples = 6", shape="box"] ;
0 -> 2;
3 [label="X[0] <= 1.6500
entropy = 0.918295834054
samples = 3", shape="box"] ;
2 -> 3;
4 [label="entropy = 0.0000
samples = 2
value = [ 0.  2.]", shape="box"] ;
3 -> 4;
5 [label="entropy = 0.0000
samples = 1
value = [ 1.  0.]", shape="box"] ;
3 -> 5;
6 [label="entropy = 0.0000
samples = 3
value = [ 0.  3.]", shape="box"] ;
2 -> 6;
}

根据这个信息,决策树应该长的如下这个样子:

Python机器学习(1)——决策树分类算法第2张

免责声明:文章转载自《Python机器学习(1)——决策树分类算法》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇ubuntu添加中文输入法Golang之sqlite数据库下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Python log() 函数

描述 log() 方法返回x的自然对数,x > 0。 语法 以下是 log() 方法的语法: import math math.log( x ) 注意:log()是不能直接访问的,需要导入 math 模块,通过静态对象调用该方法。 参数 x -- 数值表达式。 返回值 返回x的自然对数,x>0。 实例 以下展示了使用 log()...

MySQL查询截取分析

一、查询优化 1,mysql的调优大纲 慢查询的开启并捕获 explain+慢SQL分析 show profile查询SQL在Mysql服务器里面的执行细节和生命周期情况 SQL数据库服务器的参数调优 2,小表驱动大表 mysql的join实现原理是,以驱动表的数据为基础,“嵌套循环”去被驱动表匹配记录。驱动表的索引会失效,而被驱动表的索引有效。 #假...

Mysql:windows上mysql服务管理

自5.1.21及以后的变化: The following table shows the available servers for Windows in MySQL 5.1.20 and earlier. Binary Description mysqld-nt Optimized binary with named-pipe sup...

03-openldap服务端安装配置

openldap服务端安装配置 阅读目录 基础环境准备 安装openldap服务端 初始化openldap配置 启动OpenLDAP 重新生成配置文件信息 规划OpenLDAP目录树组织架构 使用GUI客户端登录查看 openldap配置日志 通过migrationtools实现用户及用户组的添加 OpenLDAP控制策略 1. 基础环境准备 1.1...

三种Js深度学习框架介绍

谈到机器学习,我们脑海首先蹦出的编程语言是什么?一定是python。其实除了python,JavaScript也是不错的选择。都说现在是大前端时代,从移动开发、服务器端,甚至桌面软件开发(比如大名鼎鼎的VS Code),都有JavaScript的身影。   用Javascript写机器学习应用,当然不会从头开始手写机器学习算法和模型,通常会借助现有框架。我...

深度学习—1*1卷积核

主要作用: 1、跨通道的特征整合 2、特征通道的升维和降维 3、减少卷积核参数(简化模型),对于单通道feature map 用单核卷积即为乘以一个参数,而一般情况都是多核卷积多通道,实现多个feature map的线性组合 4、可以实现与全连接层等价的效果。如在faster-rcnn中用1*1*m的卷积核卷积n(如512)个特征图的每一个位置(像素点)...