一、函数说明
sklearn.tree模块提供了决策树模型,用于解决分类问题和回归问题。
使用的是DecisionTreeClassifier和export_graphviz,前者用于决策树构建,后者用于决策树可视化。DecisionTreeClassifier一共有12个参数:
class sklearn.tree.DecisionTreeClassifier(criterion='gini', splitter='best', max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=None, random_state=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, class_weight=None, presort=False)
参数说明如下:
- criterion:特征选择标准,可选参数,默认是
gini
,可以设置为entropy
。gini
是基尼不纯度。entropy
是香农熵。ID3算法使用的是entropy
,CART算法使用的则是gini
。 - splitter:特征划分点选择标准,可选参数,默认是
best
,可以设置为random
。默认的”best”适合样本量不大的时候,而如果样本数据量非常大,此时决策树构建推荐”random”。主要考虑计算量。 - max_features:划分时考虑的最大特征数,可选参数,默认是None。寻找最佳切分时考虑的最大特征数(n_features为总共的特征数),有如下6种情况:
- 如果max_features是整型的数,则考虑max_features个特征;
- 如果max_features是浮点型的数,则考虑int(max_features * n_features)个特征;
- 如果max_features设为
auto
,那么max_features = sqrt(n_features); - 如果max_features设为
sqrt
,那么max_featrues = sqrt(n_features),跟auto
一样; - 如果max_features设为
log2
,那么max_features = log2(n_features); - 如果max_features设为
None
,那么max_features = n_features,也就是所有特征都用。 - 一般来说,如果样本特征数不多,比如小于50,我们用默认的”None”就可以了,如果特征数非常多,我们可以灵活使用刚才描述的其他取值来控制划分时考虑的最大特征数,以控制决策树的生成时间。
- max_depth:决策树最大深度,即层数,可选参数,默认是
None
(即不会限制子树的深度)。一般来说,数据少或者特征少的时候可以不管这个值。或者如果设置了min_samples_slipt
参数,那么直到少于min_smaples_split
个样本为止。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,常用的可以取值10-100之间。建议先限制决策树的深度,这样可以先观察下生成的决策树里数据的初步拟合情况,然后再决定是否要增加深度。 - min_samples_split:内部节点再划分所需最小样本数,可选参数,默认是2。这个值限制了子树继续划分的条件。如果
min_samples_split
为整数,那么在切分内部结点的时候,min_samples_split
作为最小的样本数,也就是说,如果样本已经少于min_samples_split
个样本,则停止继续切分。如果min_samples_split
为浮点数,那么min_samples_split
就是一个百分比,ceil(min_samples_split * n_samples),数是向上取整的。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。 - min_weight_fraction_leaf:叶子节点最小的样本权重和,可选参数,默认是0。这个值限制了叶子节点所有样本权重和的最小值,如果小于这个值,则会和兄弟节点一起被剪枝。一般来说,如果我们有较多样本有缺失值,或者分类树样本的分布类别偏差很大,就会引入样本权重,这时我们就要注意这个值了。
- max_leaf_nodes:最大叶子节点数,可选参数,默认是
None
。通过限制最大叶子节点数,可以防止过拟合。如果加了限制,算法会建立在最大叶子节点数内最优的决策树。如果特征不多,可以不考虑这个值,但是如果特征分成多的话,可以加以限制,具体的值可以通过交叉验证得到。 - class_weight:类别权重,可选参数,默认是
None
,也可以字典、字典列表、balanced
。指定样本各类别的的权重,主要是为了防止训练集某些类别的样本过多,导致训练的决策树过于偏向这些类别。类别的权重可以通过{class_label:weight}
这样的格式给出,这里可以自己指定各个样本的权重,或者用balanced
,如果使用balanced
,则算法会自己计算权重,样本量少的类别所对应的样本权重会高。当然,如果你的样本类别分布没有明显的偏倚,则可以不管这个参数,选择默认的None
。 - random_state:可选参数,默认是
None
。随机数种子。如果是证书,那么random_state
会作为随机数生成器的随机数种子。随机数种子,如果没有设置随机数,随机出来的数与当前系统时间有关,每个时刻都是不同的。如果设置了随机数种子,那么相同随机数种子,不同时刻产生的随机数也是相同的。如果是RandomState instance
,那么random_state
是随机数生成器。如果为None
,则随机数生成器使用np.random。 - min_impurity_split:节点划分最小不纯度,可选参数,默认是1e-7。这是个阈值,这个值限制了决策树的增长,如果某节点的不纯度(基尼系数,信息增益,均方差,绝对差)小于这个阈值,则该节点不再生成子节点。即为叶子节点 。
- presort:数据是否预排序,可选参数,默认为
False
不排序。一般来说,不用理它就可以了。
此外还提供了一些函数:
详见官网
二、使用
预测隐形眼镜
大致流程:
2.1 数据预处理
因为在fit()函数不能接收string
类型的数据,在使用fit()函数之前,我们需要对数据集进行编码,这里可以使用sklearn.preprocessing中的两种方法:
- LabelEncoder:将字符串转换为增量值
- OneHotEncoder:使用One-of-K算法将字符串转换为整数
为了对string
类型的数据序列化,需要先生成pandas数据,这样方便我们的序列化工作。这里我使用的方法是,原始数据->字典->pandas数据->序列化,编写代码如下:
#coding:utf-8
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn import tree
import pandas as pd
def createData():
#加载文件
with open('lenses.txt', 'r') as fr:
#处理文件
lenses = [inst.strip().split('\t') for inst in fr.readlines()]
#提取每组数据的类别,保存在列表里
lenses_target = []
for each in lenses:
lenses_target.append(each[-1])
#原始数据->字典
lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate']#特征标签
lenses_list = []#保存lenses数据的临时列表
lenses_dict = {}#保存lenses数据的字典,用于生成pandas
for each_label in lensesLabels:#提取信息,生成字典
for each in lenses:
lenses_list.append(each[lensesLabels.index(each_label)])
lenses_dict[each_label] = lenses_list
lenses_list = []
#字典->pandas数据
lenses_pd = pd.DataFrame(lenses_dict)
print(lenses_pd)
#创建LabelEncoder()对象,用于序列化
le = LabelEncoder()
#序列化
for col in lenses_pd.columns:
lenses_pd[col] = le.fit_transform(lenses_pd[col])
print(lenses_pd)
return lenses_pd, lenses_target
2.2 分类
#coding:utf-8
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn import tree
import pandas as pd
def createData():
#加载文件
with open('lenses.txt', 'r') as fr:
#处理文件
lenses = [inst.strip().split('\t') for inst in fr.readlines()]
#提取每组数据的类别,保存在列表里
lenses_target = []
for each in lenses:
lenses_target.append(each[-1])
#原始数据->字典
lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate']#特征标签
lenses_list = []#保存lenses数据的临时列表
lenses_dict = {}#保存lenses数据的字典,用于生成pandas
for each_label in lensesLabels:#提取信息,生成字典
for each in lenses:
lenses_list.append(each[lensesLabels.index(each_label)])
lenses_dict[each_label] = lenses_list
lenses_list = []
#字典->pandas数据
lenses_pd = pd.DataFrame(lenses_dict)
print(lenses_pd)
#创建LabelEncoder()对象,用于序列化
le = LabelEncoder()
#序列化
for col in lenses_pd.columns:
lenses_pd[col] = le.fit_transform(lenses_pd[col])
print(lenses_pd)
return lenses_pd, lenses_target
def classifier0(data, labels):
#创建DecisionTreeClassifier()类
clf = tree.DecisionTreeClassifier(criterion='entropy', min_samples_split=3)
#使用数据,构建决策树
clf = clf.fit(data.values.tolist(), labels)
print(clf)
#预测
print(clf.predict([[1,1,1,0]]))
#绘制决策树
tree.export_graphviz(clf,
#out_file = None,
feature_names = data.keys(),
class_names = clf.classes_,)
if __name__ == '__main__':
data, labels = createData()
classifier0(data, labels)
此时的在当前目录下生成了tree.dot文件,保存了各节点的信息。
注意:该算法只能做到二叉树,树的左枝为True,右枝为False。