机器学习算法:决策树

决策树

适用问题:多类分类,回归
模型类型:判别模型
模型特点:分类树、回归树
学习策略:正则化的极大似然估计
学习的损失函数:对数似然损失
学习算法:特征选择 树的生成 树的剪枝

总结:
1.分类决策树模型是表示基于特征对实例进行分类的树形结构。决策树可以转换成一个if-then规则的集合,也可以看作是定义在特征空间划分上的类的条件概率分布。
2.决策树学习旨在构建一个与训练数据策树是NP报合用好并且复杂度小的决复NP完全问题.现实中采用自
发式方法学习次优的决策树。
决策树学习算法包括三部分:特征选择、树的生成和树的剪枝,常用的算法有ID3、C4.5 和CART.
3.特征选择的目的在于选取对训练数据能够分类的特征.二战选择的关键是其准则。常用的准则如下:
(1)样本集合D对特征A的信息增益(ID3)

其中,H(D) 是数据集D的熵,H(D)是数据集D的熵,H(D|A)是数据集D对特征A的条件熵。D是D中特征A取第i个值的样本子集,C是D中属于第k类的样本子集。n是特征A取值的个数,K是类的个数.
(2)样本集合D对特征A的信息增益比(C4.5)

其中,g(D.A)是信息增益,H,(D)是 D.关于特征的值的熵。
(3)样本集合D的基尼指数(CART)

4.决策树的生成。通常使用信息增益最大、信息增益比最大或基尼指数最小作为特征选择的准则.决策树的生成往往通过计算信息增益或其他指标,从根结点开始,递归地产生决策树.这相当于用信息增益或其他准则不断地选取局部最优的特征,或将训练集分割为能够基本正确分类的子集,
5.决策树的剪枝,由于生成的决策树存在过拟合问题,需要对它进行剪枝,以简化学到的决策树,决策树的剪枝,往往从已生成的树上剪掉些叶结点或叶结点以上的子树,并将其父结点或根结点作为新的叶结点,从而简化生成的决策树.

一、决策树(例5.2)
1.定义:对实例进行分类的树形结构,由决策树和有向边组成。分类时,从根节点开始,对实例的某一节点进行测试,根据测试结果将实例分配到子节点如此递归的将实例来进行测试并分配,直至达到叶节点。
2.步骤:
特征选择 ——判断标准
决策树的生成 ——自然景观
决策树的修剪 ——人工花园
3.优缺点 :
优点:
模型具有可读性、分类速度快、可以处理连续和种类字段
缺点:
对连续性的字段比较难预测。
对有时间顺序的数据,需要很多预处理的工作。
当类别太多时,错误可能就会增加的比较快。
一般的算法分类的时候,只是根据一个字段来分类
import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from math import log
def create_data():
datasets = [[‘青年’, ‘否’, ‘否’, ‘一般’, ‘否’],
[‘青年’, ‘否’, ‘否’, ‘好’, ‘否’],
[‘青年’, ‘是’, ‘否’, ‘好’, ‘是’],
[‘青年’, ‘是’, ‘是’, ‘一般’, ‘是’],
[‘青年’, ‘否’, ‘否’, ‘一般’, ‘否’],
[‘中年’, ‘否’, ‘否’, ‘一般’, ‘否’],
[‘中年’, ‘否’, ‘否’, ‘好’, ‘否’],
[‘中年’, ‘是’, ‘是’, ‘好’, ‘是’],
[‘中年’, ‘否’, ‘是’, ‘非常好’, ‘是’],
[‘中年’, ‘否’, ‘是’, ‘非常好’, ‘是’],
[‘老年’, ‘否’, ‘是’, ‘非常好’, ‘是’],
[‘老年’, ‘否’, ‘是’, ‘好’, ‘是’],
[‘老年’, ‘是’, ‘否’, ‘好’, ‘是’],
[‘老年’, ‘是’, ‘否’, ‘非常好’, ‘是’],
[‘老年’, ‘否’, ‘否’, ‘一般’, ‘否’],
]
labels = [u’年龄’, u’有工作’, u’有自己的房子’, u’信贷情况’, u’类别’]
return datasets, labels

datasets, labels = create_data()
train_data = pd.DataFrame(datasets, columns=labels)
class Node:

初始化决策树

    def __init__(self,root=True,label=None,feature_name = None, feature = None):
        self.root = root
        self.label = label
        self.feature_name = feature_name
        self.feature = feature
        self.tree = {}
        self.result = {'label:':self.label,'feature':self.feature,'tree':self.tree}
#定义输出的格式
    def __repr__(self):
        return '{}'.format(self.result)

构造树

添加结点

    def add_node(self,val,node):
        self.tree[val] = node

预测根结点(最优特征)

    def predict(self,features):
        if self.root is True:
            return self.label
        return self.tree[features[self.feature]].predict(features)

class DTree:
    def __init__(self,epsilon=0.1):
        self.epsilon = epsilon
        self._tree = {}

    # 经验熵H(D)
    @staticmethod
    def entropy(datasets):
        data_length = len(datasets)
        label_count = {}
        for i in range(data_length):
            label = datasets[i][-1]
            if label not in label_count:
                label_count[label] = 0
            label_count[label] += 1
        ent = -sum([(p / data_length) * log(p / data_length, 2)
                    for p in label_count.values()])
        return ent

    # 经验条件熵H(D|A)
    def condition_entropy(self,datasets,axis = 0):
        data_length = len(datasets)
        feature_sets = {}
        for i in range(data_length):
            feature = datasets[i][axis]
            if feature not in feature_sets:
                feature_sets[feature] = []
            f feature_sets[feature].append(datasets[i]) 

condi_ent = sum([ (len§ / data_length)*entropy§
for p in feature_sets.values()])
return condi_ent

    # 信息增益
    @staticmethod
    def info_gain(ent,condi_entropy):
        return ent - condi_entropy


    def info_gain_train(self, datasets):
        count = len(datasets[0]) - 1
        ent = self.entropy(datasets)
        best_feature = []

求最大的信息增益(最优特征)

        for c in range(count):
            c_info_gain = self.info_gain(ent,self.condition_entropy(datasets,axis=c))
            best_feature.append((c,c_info_gain))
            print("特征({})的信息增益为: {:.3f}".format(labels[c],c_info_gain))
        best = max(best_feature, key=lambda x:x[-1])
        return best

    def train(self,train_data):
        _,y_train,features = train_data.iloc[:,:-1],train_data.iloc[:,-1],train_data.columns[:-1]
        # 1,若D中实例属于同一类Ck,则T为单节点树,并将类Ck作为结点的类标记,返回T
        if  len(y_train.value_counts()) == 1:
            return Node(root=True, label = y_train.iloc[0])

        # 2, 若A为空,则T为单节点树,将D中实例树最大的类Ck作为该节点的类标记,返回T
        if len(features) == 0:
            return Node(root= True, label=y_train.value_counts().sort_values(ascending=False).index[0])

        # 3,计算最大信息增益 同5.1,Ag为信息增益最大的特征
        max_feature, max_info_gain = self.info_gain_train(np.array(train_data))
        max_feature_name = labels[max_feature]

        # 4,Ag的信息增益小于阈值eta,则置T为单节点树,并将D中是实例数最大的类Ck作为该节点的类标记,返回T
        if max_info_gain < self.epsilon:
            return Node(root=True,label= y_train.value_counts().sort_values(ascending=False).index[0])

        # 5,构建Ag子集
        node_tree = Node(root = False,feature_name= max_feature_name, feature= max_feature)

        feature_list = train_data[max_feature_name].value_counts().index
        for f in feature_list:
            sub_train_df = train_data.loc[train_data[max_feature_name] == f].drop([max_feature_name],axis=1)
            # 6, 递归生成树
            sub_tree = self.train(sub_train_df)
            node_tree.add_node(f, sub_tree)
        return node_tree
# 调整 (剪枝)
    def fit(self,train_data):
        self._tree = self.train(train_data)
        return self._tree

    def predict(self,X_test):
        return self._tree.predict(X_test)

datasets, labels = create_data()
data_df = pd.DataFrame(datasets, columns=labels)
dt = DTree()
tree = dt.fit(data_df)
print(tree)

print(dt.predict(['老年', '否', '否', '一般']))	
# scikit-learn(学习) 实现
def create_data():
    iris = load_iris()
    df = pd.DataFrame(iris.data, columns=iris.feature_names)
    df['label'] = iris.target
    df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']
    data = np.array(df.iloc[:100, [0, 1, -1]])
    print(data)
    return data[:,:2], data[:,-1]

X, y = create_data()

train_test_split函数用于划分数据集为训练集和测试集,其中参数test_size默认为0.3,表示将30%的数据划分为测试集

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
from sklearn.tree import DecisionTreeClassifier

创建决策树分类器

clf = DecisionTreeClassifier()

训练分类器模型

clf.fit(X_train, y_train,)
print(clf.fit(X_train, y_train,))
print(clf.score(X_test, y_test))

你可能感兴趣的:(机器学习算法:决策树)