《opencv》5.1

本节的例子是利用决策树根据病人的一些生理指标数据决定开什么药品,药品一共四种,分别是A、B、C、D。而病人的生理指标有年龄、性别、血压、胆固醇指标、血液中Na浓度、血液中K浓度。所有的数据如下:
data = [
{‘age’: 33, ‘sex’: ‘F’, ‘BP’: ‘high’, ‘cholesterol’: ‘high’, ‘Na’: 0.66, ‘K’: 0.06, ‘drug’: ‘A’},
{‘age’: 77, ‘sex’: ‘F’, ‘BP’: ‘high’, ‘cholesterol’: ‘normal’, ‘Na’: 0.19, ‘K’: 0.03, ‘drug’: ‘D’},
{‘age’: 88, ‘sex’: ‘M’, ‘BP’: ‘normal’, ‘cholesterol’: ‘normal’, ‘Na’: 0.80, ‘K’: 0.05, ‘drug’: ‘B’},
{‘age’: 39, ‘sex’: ‘F’, ‘BP’: ‘low’, ‘cholesterol’: ‘normal’, ‘Na’: 0.19, ‘K’: 0.02, ‘drug’: ‘C’},
{‘age’: 43, ‘sex’: ‘M’, ‘BP’: ‘normal’, ‘cholesterol’: ‘high’, ‘Na’: 0.36, ‘K’: 0.03, ‘drug’: ‘D’},
{‘age’: 82, ‘sex’: ‘F’, ‘BP’: ‘normal’, ‘cholesterol’: ‘normal’, ‘Na’: 0.09, ‘K’: 0.09, ‘drug’: ‘C’},
{‘age’: 40, ‘sex’: ‘M’, ‘BP’: ‘high’, ‘cholesterol’: ‘normal’, ‘Na’: 0.89, ‘K’: 0.02, ‘drug’: ‘A’},
{‘age’: 88, ‘sex’: ‘M’, ‘BP’: ‘normal’, ‘cholesterol’: ‘normal’, ‘Na’: 0.80, ‘K’: 0.05, ‘drug’: ‘B’},
{‘age’: 29, ‘sex’: ‘F’, ‘BP’: ‘high’, ‘cholesterol’: ‘normal’, ‘Na’: 0.35, ‘K’: 0.04, ‘drug’: ‘D’},
{‘age’: 53, ‘sex’: ‘F’, ‘BP’: ‘normal’, ‘cholesterol’: ‘normal’, ‘Na’: 0.54, ‘K’: 0.06, ‘drug’: ‘C’},
{‘age’: 36, ‘sex’: ‘F’, ‘BP’: ‘high’, ‘cholesterol’: ‘high’, ‘Na’: 0.53, ‘K’: 0.05, ‘drug’: ‘A’},
{‘age’: 63, ‘sex’: ‘M’, ‘BP’: ‘low’, ‘cholesterol’: ‘high’, ‘Na’: 0.86, ‘K’: 0.09, ‘drug’: ‘B’},
{‘age’: 60, ‘sex’: ‘M’, ‘BP’: ‘low’, ‘cholesterol’: ‘normal’, ‘Na’: 0.66, ‘K’: 0.04, ‘drug’: ‘C’},
{‘age’: 55, ‘sex’: ‘M’, ‘BP’: ‘high’, ‘cholesterol’: ‘high’, ‘Na’: 0.82, ‘K’: 0.04, ‘drug’: ‘B’},
{‘age’: 35, ‘sex’: ‘F’, ‘BP’: ‘normal’, ‘cholesterol’: ‘high’, ‘Na’: 0.27, ‘K’: 0.03, ‘drug’: ‘D’},
{‘age’: 23, ‘sex’: ‘F’, ‘BP’: ‘high’, ‘cholesterol’: ‘high’, ‘Na’: 0.55, ‘K’: 0.08, ‘drug’: ‘A’},
{‘age’: 49, ‘sex’: ‘F’, ‘BP’: ‘low’, ‘cholesterol’: ‘normal’, ‘Na’: 0.27, ‘K’: 0.05, ‘drug’: ‘C’},
{‘age’: 27, ‘sex’: ‘M’, ‘BP’: ‘normal’, ‘cholesterol’: ‘normal’, ‘Na’: 0.77, ‘K’: 0.02, ‘drug’: ‘B’},
{‘age’: 51, ‘sex’: ‘F’, ‘BP’: ‘low’, ‘cholesterol’: ‘high’, ‘Na’: 0.20, ‘K’: 0.02, ‘drug’: ‘D’},
{‘age’: 38, ‘sex’: ‘M’, ‘BP’: ‘high’, ‘cholesterol’: ‘normal’, ‘Na’: 0.78, ‘K’: 0.05, ‘drug’: ‘A’}
]

drug这一列是我们的target,即分类目标,把它提取出来,并且量化为数值。
target = [d[‘drug’] for d in data]
target = [ord(t) - 65 for t in target]
量化后,target的结果为:
[0, 3, 1, 2, 3, 2, 0, 1, 3, 2, 0, 1, 2, 1, 3, 0, 2, 1, 3, 0]

除了target外,我们需要讲所有的文本特征转换为数值特征,使用sciket-learn中的DictVectorizer完成:
vec = DictVectorizer(sparse=False)
data_pre = vec.fit_transform(data)

之后将数据分成训练和测试两部分:
x_train, x_test, y_train, y_test = ms.train_test_split(data_pre, target, test_size = 5, random_state = 42)

此时就可以使用决策树的训练模型对数据进行训练和预测了。书中使用的是opencv提供的决策树模型实际是3.1版本之前的方法了,当前版本需要使用DTrees_create()创建。实际上sciket-learn也提供了决策树模型,而且更加优秀,用书中的话就是:可以让我们对算法进行定制化,并且可以更简单的对决策树的内部工作了流程进行探索。
权衡后,决定以后所有的机器学习模型都是用sciket-learn中提供的。
dtc = tree.DecisionTreeClassifier(criterion=‘entropy’, max_leaf_nodes=6)
dtc.fit(x_train, y_train)

使用模型对测试数据和训练数据进行预测,得到结果分别是1.0和0.4。很明显,模型出现了过拟合现象,泛化能力不足。
dtc.score(x_train, y_train)
dtc.score(x_test, y_test)

我们对决策树进行可视化,如下图:
《opencv》5.1可以看到每一个决策条件都是data中的一个特征,每一次决策的结果都是将输入数据分成两份,而树的叶节点都是最终的分类结果。

那么问题来了,决策树是如何决定树中节点选择哪个 特征做为判断条件的呢?
scikit-learn提供了方法判断特征的重要性,它会对每个特征返回一个0到1之间的数字,0表示所有决策都不使用这个特征,而1表示这个特征可以完美的预测这个目标。这些特征的结果会归一化。本例中的结果:
[0. 0. 0. 0. 0.5105994 0.18687375 0. 0.30252685 0. 0. ]
[‘BP=high’, ‘BP=low’, ‘BP=normal’, ‘K’, ‘Na’, ‘age’, ‘cholesterol=high’, ‘cholesterol=normal’, ‘sex=F’, ‘sex=M’]
《opencv》5.1
可以看到重要性值最大的是Na这个特征,而决策树中可以看到该指标是作为根节点的判断依据。不过需要说明的是,决策树节点判断条件的选择并不完全是依照重要性来的。

那么特征的重要性是如何得来的呢?
评判的标准主要是特性的信息性的大小,一个特征的信息性越多,则该特征就越重要。
那么信息性又是如何评判的呢?
scikit-learn提供了两种标准,也是最常用的标准,分别是基尼不纯度和信息熵。前者是一个错误分类的的测量,即最小化错误分类的概率。而后者中熵在信息论中是一个信号或者分布的不确定度的测量,一个完美的数据分割的熵为0。
上述的运行结果采用的标准都是信息熵。如果改成基尼不纯度,特征重要性结果是不一样的。
《opencv》5.1
但是预测的结果依然是0.4,模型过拟合的问题依然存在。但是数据量太少,无法做进一步的解析。