[Python] Python pandas aprendizaje rápido de la máquina algoritmo ID3 para construir un árbol de decisión para lograr paquete de transferencia con las teclas + sklearn

el blog de referencia: https://blog.csdn.net/c406495762/article/details/76262487

 

directorio

1, principio algoritmo ID3

2, el algoritmo de código (usando PANDAS)

2.1 La construcción del conjunto de entrenamiento

2.2 Algoritmo

2.3 Todos los códigos

3, la transferencia de paquetes usando árboles de decisión

3.1 Código

3.2 ajustes de parámetros relacionados

4, las ventajas y desventajas del árbol de decisión


 

1, principio algoritmo ID3


    El núcleo de ID3 criterio de ganancia de información características correspondientes en el árbol seleccionada cada nodo, un árbol de decisiones de forma recursiva. El método específico es: a partir de nodo raíz (nodo raíz), calcular todas las posibles características de la ganancia de la información del nodo, selecciona la información característica de ganancia máxima como un nodo característica, el nodo hijo para establecer las características de los diferentes valores, y entonces sub-nodo recursivamente llamar al proceso anterior, un árbol de decisiones; ganancia de información hasta que todas las funciones tienen poca o ninguna característica pueden ser seleccionados hasta el momento, para dar un árbol de decisión final. ID3 equivalente al modelo seleccionado de probabilidad método de máxima verosimilitud utilizado.

 

2, el algoritmo de código (usando PANDAS)

2.1 La construcción del conjunto de entrenamiento

def create_dataSet():
    # 函数说明:创建训练数据集
    dataSet = [[0, 0, 0, 0, 'no'],						#数据集
			[0, 0, 0, 1, 'no'],
			[0, 1, 0, 1, 'yes'],
			[0, 1, 1, 0, 'yes'],
			[0, 0, 0, 0, 'no'],
			[1, 0, 0, 0, 'no'],
			[1, 0, 0, 1, 'no'],
			[1, 1, 1, 1, 'yes'],
			[1, 0, 1, 2, 'yes'],
			[1, 0, 1, 2, 'yes'],
			[2, 0, 1, 2, 'yes'],
			[2, 0, 1, 1, 'yes'],
			[2, 1, 0, 1, 'yes'],
			[2, 1, 0, 2, 'yes'],
			[2, 0, 0, 0, 'no']]
    classList = [example[-1] for example in dataSet]  # 取分类标签(是否放贷:yes or no)
    labels = ['年龄', '有工作', '有自己的房子', '信贷情况','类别标签']		# 特征标签
    return pd.DataFrame(data=dataSet,columns=labels)

2.2 Algoritmo

def shannonEnt(dataSet):
    # 函数说明:计算数据集经验熵
    # 取数据集的行数
    data_row = dataSet.shape[0]
    Ent = 0
    for i in dataSet[dataSet.columns[-1]].value_counts():
        # 运用公式
        Ent -= (i/data_row) * log(i/data_row,2)
    return Ent

def max_info_gain_feature(dataSet):
    # 函数说明:计算信息增益最大的特征
    # 计算总行数,即总个数
    row = dataSet.shape[0]
    # 最大值指针初始化
    max_gain = 0
    # 最大值特征
    max_gain_feature = None
    # 遍历每一个特征
    for col in dataSet.columns[:dataSet.shape[1]-1]:
        # 初始化特征的H(D|特征)
        gain = 0
        # 生成交叉表,取出数据,即按某特征情况下来分的子集信息
        crosstab = pd.DataFrame(pd.crosstab(index=dataSet[col],columns=dataSet[dataSet.columns[-1]]).reset_index(),columns=['yes','no'])
        # 遍历每一行,即该特征下各特征值分出来的子集的标签分类情况
        for i in range(crosstab.shape[0]):
            # 此时特征情况下来分的子集条数/总数,即概率
            ai_prob = np.sum(crosstab,axis=1)[i]/row
            # 此时特征情况下来分的子集条数
            row_sum = np.sum(crosstab,axis=1)[i]
            # 遍历每一个子集
            for j in crosstab.iloc[i,:].values:
                # 计算公式,防止除数为0
                gain +=  ai_prob * (-j/row_sum * log(j/row_sum+0.000000000000000000001,2))
        # 信息增益 = H(D) - H(D|A)
        infogain = shannonEnt(create_dataSet()) - gain
        # 如果大于此时最大
        if infogain > max_gain:
            max_gain = infogain
            max_gain_feature = col
    return max_gain_feature

def split_dataSet(dataSet, axis, value):
    # 返回按某特征的某特征值分出的数据子集
    return dataSet.loc[dataSet[axis] == value]

def create_tree(dataSet):
    # 创建用训练集训练的决策树
    # 如果类别完全相同则停止继续划分
    if dataSet[dataSet.columns[-1]].value_counts()[0] == dataSet.shape[0]:
        # 返回该类别标签
        return dataSet[dataSet.columns[-1]].value_counts().index[0]
    # 遍历完所有特征时
    if dataSet.shape[1] == 1:
        # 返回出现次数最多的类标签
        return dataSet[dataSet.columns[-1]].value_counts().sort_values(ascending=True).index[0]
    # 选择信息增益最大特征
    best_feature = max_info_gain_feature(dataSet)
    # 根据最优特征的标签生成树
    decision_tree = {best_feature:{}}
    # #遍历特征,创建决策树
    for featvalue in dataSet[best_feature].value_counts().index:
        decision_tree[best_feature][featvalue] = create_tree(split_dataSet(dataSet,best_feature,featvalue))
    # 删除已使用的特征
    del dataSet[best_feature]
    return decision_tree

def classify(tree,data=None):
    classlabel = None
    # 获取决策树字典的某一层的key
    first_key = next(iter(tree))
    # 获取决策树结点的某一层的key的value
    first_key_dict = tree[first_key]
    for key in first_key_dict.keys():
        if data[first_key].iat[0] == key:
            if type(first_key_dict[key]).__name__ == 'dict':
                classlabel = classify(first_key_dict[key],data)
            else:
                classlabel = first_key_dict[key]
    return classlabel

def store_tree(inputTree, filename):
    # 存储决策树
    with open(filename, 'wb') as fw:
        pickle.dump(inputTree, fw)

def get_tree(filename):
    fr = open(filename,'rb')
    return pickle.load(fr)

2.3 Todos los códigos

import pandas as pd
from math import log
import numpy as np
import pickle

def create_dataSet():
    # 函数说明:创建训练数据集
    dataSet = [[0, 0, 0, 0, 'no'],						#数据集
			[0, 0, 0, 1, 'no'],
			[0, 1, 0, 1, 'yes'],
			[0, 1, 1, 0, 'yes'],
			[0, 0, 0, 0, 'no'],
			[1, 0, 0, 0, 'no'],
			[1, 0, 0, 1, 'no'],
			[1, 1, 1, 1, 'yes'],
			[1, 0, 1, 2, 'yes'],
			[1, 0, 1, 2, 'yes'],
			[2, 0, 1, 2, 'yes'],
			[2, 0, 1, 1, 'yes'],
			[2, 1, 0, 1, 'yes'],
			[2, 1, 0, 2, 'yes'],
			[2, 0, 0, 0, 'no']]
    classList = [example[-1] for example in dataSet]  # 取分类标签(是否放贷:yes or no)
    labels = ['年龄', '有工作', '有自己的房子', '信贷情况','类别标签']		# 特征标签
    return pd.DataFrame(data=dataSet,columns=labels)

def shannonEnt(dataSet):
    # 函数说明:计算数据集经验熵
    # 取数据集的行数
    data_row = dataSet.shape[0]
    Ent = 0
    for i in dataSet[dataSet.columns[-1]].value_counts():
        # 运用公式
        Ent -= (i/data_row) * log(i/data_row,2)
    return Ent

def max_info_gain_feature(dataSet):
    # 函数说明:计算信息增益最大的特征
    # 计算总行数,即总个数
    row = dataSet.shape[0]
    # 最大值指针初始化
    max_gain = 0
    # 最大值特征
    max_gain_feature = None
    # 遍历每一个特征
    for col in dataSet.columns[:dataSet.shape[1]-1]:
        # 初始化特征的H(D|特征)
        gain = 0
        # 生成交叉表,取出数据,即按某特征情况下来分的子集信息
        crosstab = pd.DataFrame(pd.crosstab(index=dataSet[col],columns=dataSet[dataSet.columns[-1]]).reset_index(),columns=['yes','no'])
        # 遍历每一行,即该特征下各特征值分出来的子集的标签分类情况
        for i in range(crosstab.shape[0]):
            # 此时特征情况下来分的子集条数/总数,即概率
            ai_prob = np.sum(crosstab,axis=1)[i]/row
            # 此时特征情况下来分的子集条数
            row_sum = np.sum(crosstab,axis=1)[i]
            # 遍历每一个子集
            for j in crosstab.iloc[i,:].values:
                # 计算公式,防止除数为0
                gain +=  ai_prob * (-j/row_sum * log(j/row_sum+0.000000000000000000001,2))
        # 信息增益 = H(D) - H(D|A)
        infogain = shannonEnt(create_dataSet()) - gain
        # 如果大于此时最大
        if infogain > max_gain:
            max_gain = infogain
            max_gain_feature = col
    return max_gain_feature

def split_dataSet(dataSet, axis, value):
    # 返回按某特征的某特征值分出的数据子集
    return dataSet.loc[dataSet[axis] == value]

def create_tree(dataSet):
    # 创建用训练集训练的决策树
    # 如果类别完全相同则停止继续划分
    if dataSet[dataSet.columns[-1]].value_counts()[0] == dataSet.shape[0]:
        # 返回该类别标签
        return dataSet[dataSet.columns[-1]].value_counts().index[0]
    # 遍历完所有特征时
    if dataSet.shape[1] == 1:
        # 返回出现次数最多的类标签
        return dataSet[dataSet.columns[-1]].value_counts().sort_values(ascending=True).index[0]
    # 选择信息增益最大特征
    best_feature = max_info_gain_feature(dataSet)
    # 根据最优特征的标签生成树
    decision_tree = {best_feature:{}}
    # #遍历特征,创建决策树
    for featvalue in dataSet[best_feature].value_counts().index:
        decision_tree[best_feature][featvalue] = create_tree(split_dataSet(dataSet,best_feature,featvalue))
    # 删除已使用的特征
    del dataSet[best_feature]
    return decision_tree

def classify(tree,data=None):
    classlabel = None
    # 获取决策树字典的某一层的key
    first_key = next(iter(tree))
    # 获取决策树结点的某一层的key的value
    first_key_dict = tree[first_key]
    for key in first_key_dict.keys():
        if data[first_key].iat[0] == key:
            if type(first_key_dict[key]).__name__ == 'dict':
                classlabel = classify(first_key_dict[key],data)
            else:
                classlabel = first_key_dict[key]
    return classlabel

def store_tree(inputTree, filename):
    # 存储决策树
    with open(filename, 'wb') as fw:
        pickle.dump(inputTree, fw)

def get_tree(filename):
    fr = open(filename,'rb')
    return pickle.load(fr)

if __name__ == '__main__':
    # 获取训练集
    # dataSet = create_dataSet()
    # 利用训练集创建决策树
    # decision_tree = create_tree(dataSet=dataSet)
    # 存储决策树
    # store_tree(decision_tree,'tree.txt')
    # 读取决策树
    decision_tree = get_tree('tree.txt')
    test_vec = pd.DataFrame(data=[[0,1,0,1]],columns=['年龄', '有工作', '有自己的房子', '信贷情况'])
    print(classify(decision_tree,test_vec))

3, la transferencia de paquetes usando árboles de decisión

3.1 Código

import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.tree import DecisionTreeClassifier

def get_data():
    names = ['age', 'prescript', 'astigmatic', 'tearRate', 'class']
    data = pd.read_table(filepath_or_buffer='lenses.txt',sep='\t',names=names)
    label = LabelEncoder()
    for col in data[data.columns[:-1]]:
        data[col] = label.fit_transform(data[col])
    return data

def model_predict(data):
    dtc = DecisionTreeClassifier(max_depth=4)
    dtc.fit(data.iloc[:,:-1].values.tolist(),data.iloc[:,-1].values)
    result = dtc.predict([[2,0,0,0]])
    return result
model_predict(get_data())

3.2 ajustes de parámetros relacionados

el blog de referencia: https://blog.csdn.net/c406495762/article/details/76262487

※ 参数说明如下:
1、criterion:特征选择标准,可选参数,默认是gini,可以设置为entropy。gini是基尼不纯度,是将来自集合的某种结果随机应用于某一数据项的预期误差率,是一种基于统计的思想。entropy是香农熵,也就是上篇文章讲过的内容,是一种基于信息论的思想。Sklearn把gini设为默认参数,应该也是做了相应的斟酌的,精度也许更高些?ID3算法使用的是entropy,CART算法使用的则是gini。
2、splitter:特征划分点选择标准,可选参数,默认是best,可以设置为random。每个结点的选择策略。best参数是根据算法选择最佳的切分特征,例如gini、entropy。random随机的在部分划分点中找局部最优的划分点。默认的”best”适合样本量不大的时候,而如果样本数据量非常大,此时决策树构建推荐”random”。
3、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”就可以了,如果特征数非常多,我们可以灵活使用刚才描述的其他取值来控制划分时考虑的最大特征数,以控制决策树的生成时间。
4、max_depth:决策树最大深,可选参数,默认是None。这个参数是这是树的层数的。层数的概念就是,比如在贷款的例子中,决策树的层数是2层。如果这个参数设置为None,那么决策树在建立子树的时候不会限制子树的深度。一般来说,数据少或者特征少的时候可以不管这个值。或者如果设置了min_samples_slipt参数,那么直到少于min_smaples_split个样本为止。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值10-100之间。
5、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),数是向上取整的。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。
6、min_weight_fraction_leaf:叶子节点最小的样本权重和,可选参数,默认是0。这个值限制了叶子节点所有样本权重和的最小值,如果小于这个值,则会和兄弟节点一起被剪枝。一般来说,如果我们有较多样本有缺失值,或者分类树样本的分布类别偏差很大,就会引入样本权重,这时我们就要注意这个值了。
7、max_leaf_nodes:最大叶子节点数,可选参数,默认是None。通过限制最大叶子节点数,可以防止过拟合。如果加了限制,算法会建立在最大叶子节点数内最优的决策树。如果特征不多,可以不考虑这个值,但是如果特征分成多的话,可以加以限制,具体的值可以通过交叉验证得到。
8、class_weight:类别权重,可选参数,默认是None,也可以字典、字典列表、balanced。指定样本各类别的的权重,主要是为了防止训练集某些类别的样本过多,导致训练的决策树过于偏向这些类别。类别的权重可以通过{class_label:weight}这样的格式给出,这里可以自己指定各个样本的权重,或者用balanced,如果使用balanced,则算法会自己计算权重,样本量少的类别所对应的样本权重会高。当然,如果你的样本类别分布没有明显的偏倚,则可以不管这个参数,选择默认的None。
9、random_state:可选参数,默认是None。随机数种子。如果是证书,那么random_state会作为随机数生成器的随机数种子。随机数种子,如果没有设置随机数,随机出来的数与当前系统时间有关,每个时刻都是不同的。如果设置了随机数种子,那么相同随机数种子,不同时刻产生的随机数也是相同的。如果是RandomState instance,那么random_state是随机数生成器。如果为None,则随机数生成器使用np.random。
10、min_impurity_split:节点划分最小不纯度,可选参数,默认是1e-7。这是个阈值,这个值限制了决策树的增长,如果某节点的不纯度(基尼系数,信息增益,均方差,绝对差)小于这个阈值,则该节点不再生成子节点。即为叶子节点 。
11、presort:数据是否预排序,可选参数,默认为False,这个值是布尔值,默认是False不排序。一般来说,如果样本量少或者限制了一个深度很小的决策树,设置为true可以让划分点选择更加快,决策树建立的更加快。如果样本量太大的话,反而没有什么好处。问题是样本量少的时候,我速度本来就不慢。所以这个值一般懒得理它就可以了。

* 除了这些参数要注意以外,其他在调参时的注意点有:
1、当样本数量少但是样本特征非常多的时候,决策树很容易过拟合,一般来说,样本数比特征数多一些会比较容易建立健壮的模型
2、如果样本数量少但是样本特征非常多,在拟合决策树模型前,推荐先做维度规约,比如主成分分析(PCA),特征选择(Losso)或者独立成分分析(ICA)。这样特征的维度会大大减小。再来拟合决策树模型效果会好。
3、推荐多用决策树的可视化,同时先限制决策树的深度,这样可以先观察下生成的决策树里数据的初步拟合情况,然后再决定是否要增加深度。
4、在训练模型时,注意观察样本的类别情况(主要指分类树),如果类别分布非常不均匀,就要考虑用class_weight来限制模型过于偏向样本多的类别。
决策树的数组使用的是numpy的float32类型,如果训练数据不是这样的格式,算法会先做copy再运行。
5、如果输入的样本矩阵是稀疏的,推荐在拟合前调用csc_matrix稀疏化,在预测前调用csr_matrix稀疏化。

4, las ventajas y desventajas del árbol de decisión

el blog de referencia: https://blog.csdn.net/c406495762/article/details/76262487

# 决策树的一些优点:
1、易于理解和解释,决策树可以可视化。
2、几乎不需要数据预处理。其他方法经常需要数据标准化,创建虚拟变量和删除缺失值。决策树还不支持缺失值。
3、使用树的花费(例如预测数据)是训练数据点(data points)数量的对数。
4、可以同时处理数值变量和分类变量。其他方法大都适用于分析一种变量的集合。
5、可以处理多值输出变量问题。
6、使用白盒模型。如果一个情况被观察到,使用逻辑判断容易表示这种规则。相反,如果是黑盒模型(例如人工神经网络),结果会非常难解释。
7、即使对真实模型来说,假设无效的情况下,也可以较好的适用。

# 决策树的一些缺点:
1、决策树学习可能创建一个过于复杂的树,并不能很好的预测数据。也就是过拟合。修剪机制(现在不支持),设置一个叶子节点需要的最小样本数量,或者数的最大深度,可以避免过拟合。
2、决策树可能是不稳定的,因为即使非常小的变异,可能会产生一颗完全不同的树。这个问题通过decision trees with an ensemble来缓解。
3、学习一颗最优的决策树是一个NP-完全问题under several aspects of optimality and even for simple concepts。因此,传统决策树算法基于启发式算法,例如贪婪算法,即每个节点创建最优决策。这些
4、算法不能产生一个全家最优的决策树。对样本和特征随机抽样可以降低整体效果偏差。
5、概念难以学习,因为决策树没有很好的解释他们,例如,XOR, parity or multiplexer problems.
6、如果某些分类占优势,决策树将会创建一棵有偏差的树。因此,建议在训练之前,先抽样使样本均衡。

 

Publicado 44 artículos originales · elogios ganado 16 · Vistas a 10000 +

Supongo que te gusta

Origin blog.csdn.net/YYIverson/article/details/101768848
Recomendado
Clasificación