您当前的位置: 首页 > 

孑渡

暂无认证

  • 2浏览

    0关注

    178博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

DecisionTree以及可视化

孑渡 发布时间:2020-12-06 11:48:21 ,浏览量:2

使用决策树方法对泰坦尼克幸存者进行预测。 数据下载链接:https://share.weiyun.com/h93y7TnI 数据集为1912年泰坦尼克号沉船事件中一些船员的个人信息以及存活状况。这些历史数据已经非分为训练集和测试集,你可以根据训练集训练出合适的模型并预测测试集中的存活状况。

1. 数据处理

  • 数据处理
def data_pross(train_data):
    age_pross(train_data)
    fare_pross(train_data)
  • 年龄处理
def age_pross(train_data):
    '''
    离散值处理age
    :param train_data:
    :return:
    '''
    for i in range(len(train_data)):
        # if 15 > train_data[i][2] >= 0:
        #     train_data[i][2] = 0
        # elif 15 = train_data[i][5] > 120:
            train_data[i][5] = 37
        elif 120 >= train_data[i][5] > 100:
            train_data[i][5] = 36
        elif 100 >= train_data[i][5] > 90:
            train_data[i][5] = 35
        elif 90 >= train_data[i][5] > 80:
            train_data[i][5] = 34
        elif 80>= train_data[i][5] > 70:
            train_data[i][5] = 33
        elif 70 >= train_data[i][5] > 65:
            train_data[i][5] = 32
        elif 65 >= train_data[i][5] > 60:
            train_data[i][5] = 31
        elif 60 >= train_data[i][5] >= 0:
            train_data[i][5] = int(int(train_data[i][5]) / 2)
        else:
            train_data[i][5] = 50

2. DecisionTree的实现

由于graphviz的接口调用是通过python实现的,因此没有选用更为适合构建树形状的C或者C++,而是依旧选择了Python。 下面是对程序中的各模块解释。

  • 代码所应用的包
from pandas import read_csv
from sklearn.model_selection import train_test_split
import numpy as np
import collections as cc
import time
import math
from graphviz import Digraph
import xlrd
import xlwt

pandas用于读取沉船数据。 由于机器学习任务目标是手动实现decisionTree,因此sklearn只用于划分数据集。 graphviz用于画图 xlrd和xlwt用于预测test

  • 公共数据区
dot = Digraph(name="DecisionTree", format="pdf")
dict2 = {0: 'Pclass', 1: 'Sex', 2: 'Age', 3: 'SibSp', 4: 'Parch', 5: 'Fare', 6: 'Embarked'}
count = 1
Feature_list = ['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked']

dot用于保存图 dict2对应需要特征的字典 Feature_list为保存特征的列表

  • 读取train的csv文件
def generate_dataset(file_name):
    '''
    读取train文件数据
    :param file_name:
    :return:
    '''
    data_dict = read_csv(file_name, index_col=0)
    # 姓名,船舱号,票号三个无关特征丢弃
    data_dict.drop(['Name', 'Ticket', 'Cabin'], axis=1, inplace=True)

    #Pandas的read_csv返回的结构不是直接的字典,是以series结构发过来的。
    # 将性别转换为数值
    # print(type(data_dict['Sex']))
    # for i in range(len(data_dict)):
    #     if data_dict['Sex'] == 'male':
    #         data_dict['Sex'] = 1
    #     else:
    #         data_dict['Sex'] = 0
    data_dict['Sex'] = (data_dict['Sex'] == 'male').astype('int')

    # 按照不同的港口名称标签赋予不同的值
    lables = data_dict['Embarked'].unique().tolist()
    data_dict['Embarked'] = data_dict['Embarked'].apply(lambda n: lables.index(n))

    # 体热指标,考虑是否去零,是否选择归一化
    # data_dict['Fare'] = data_dict['Fare'].apply(lambda n: n-n % 1)
    data_dict['Fare'] = data_dict['Fare'].apply(lambda n: n)

    # Embarked 2 null less
    # Cabin 687 null  aborted
    # Age 177 null
    # 处理age和embarked的缺失值
    # 缺失值应当用概率分布生成比较好,但是比较麻烦,选择用不改变方差的平均值处理
    data_dict['Age'].fillna(data_dict['Age'].mean(), inplace=True)
    data_dict['Age'].fillna(int(data_dict['Embarked'].mean()), inplace=True)
    # int(data_dict['Embarked'].mean())
    y = data_dict['Survived'].values
    data_dict.drop('Survived', axis=1, inplace=True)
    x = data_dict.values
    return x, y, lables

数据处理,格式处理,标记数据提取,返回Embarked列表用于处理test文件

  • 最大类寻找
def FindMajorClass(label):
    '''
    找到最大的类
    :param label: 
    :return: 
    '''
    # 对label集进行统计
    # .most_common(1),从Counter中提起出现数目最多的一组
    MajorClass = cc.Counter(label).most_common(1)[0][0]

    return MajorClass
  • 信息熵计算
def Entropy(label):
    '''
    计算信息熵
    :param label: 
    :return: 
    '''
    # 所有的类
    Class = np.unique(label)

    # 对每个类统计出现次数
    ClassNum = cc.Counter(label)

    # 得到标记的总数
    Classlen = len(label)

    # 初始化熵
    H = 0

    # 遍历每一个类
    for c in Class:

        # 计算每个类出现的概率
        P = ClassNum[c] / Classlen

        # 计算经验熵
        # 这里的对数以e为底
        H += -1 * P * math.log(P,2)

    return H
  • 信息熵获取
def get_Entropy(data,label):
    '''
    获取信息熵
    :param data: 
    :param label: 
    :return: 
    '''
    FeatureNum = len(data[0])
    dataNum = len(data)
    C_H_Arr = []#放置条件熵
    for f in range(FeatureNum):

    # 所有样本点的特征f的值
        f_data = list(np.array(data).T[f])

    # 特征f的可取值
        f_value = np.unique(f_data)

    # 初始化特征f的条件熵
        C_H = 0

    # 遍历特征f的每一个可取值
        for f_v in f_value:

        # 得到f_data中值为f_v的所有index
            index = np.argwhere(f_data == f_v)
            # print(index)
            # 准备一个空列表存储满足值为f_v的所有标记
            f_label = []

            for i in index:

                # 得到该特征下满足值为f_v的对应的所有标记
                f_label.append(label[i[0]])

            # 计算f_label的熵
            f_H = Entropy(f_label)

            # 得到在该特征下,值为f_v的概率
            f_P = len(f_label) / dataNum

            # 计算条件熵
            C_H += f_P * f_H

    # 记录每个特征的条件熵
        C_H_Arr.append(C_H)
    # print(C_H_Arr)
    return C_H_Arr
  • 信息增益获取
def InforGain(data, label):
    '''
    获取信息增益
    :param data: 
    :param label: 
    :return: 
    '''
    # 计算当前结点的经验熵
    H = Entropy(label)

    # 计算当前结点的经验条件熵
    C_H_Arr = get_Entropy(data, label)

    # 得到最大的信息增益
    IG = [H - num for num in C_H_Arr]
    IGMax = max(IG)

    # 得到最大信息增益对应的特征
    BestFeature = IG.index(IGMax)
    #print(BestFeature)
    return BestFeature, IGMax
  • 数据集划分
def SplitDataSet(data, label, feature):
    '''
    数据集划分
    :param data: 
    :param label: 
    :param feature: 
    :return: 
    '''
    # 样本数
    SampleNum = len(label)

    # 转置data
    data_T = np.transpose(data)

    # 获得最佳特征的可取值
    feature_value = np.unique(data_T[feature])

    # 准备两个列表,用来存放分割后的子集
    datasets = []
    labelsets = []

    # 遍历最佳特征的每个取值
    for f in feature_value:

        datasets_sub = []
        labelsets_sub = []

        # enumerate不仅遍历元素,同时遍历元素的下标
        # 此处遍历每个样本在最佳特征的取值和下标
        for Index, num in enumerate(data_T[feature]):

            # 当data中的某个样本的该特征=f时,获得它的index
            if num == f:

                # 将用于划分该样本点的最佳特征从数据集中去除
                # 去除后在下一次的迭代中将不再考虑这个特征
                data_temp = data[Index]
                del data_temp[feature]

                # 存储划分后的子集
                # 此时得到的仅为最佳特征的一个取值下的子集
                datasets_sub.append(data_temp)
                labelsets_sub.append(label[Index])

        # 存储根据最佳特征的不同取值划分的子集
        datasets.append(datasets_sub)
        labelsets.append(labelsets_sub)

    return datasets, labelsets
  • 决策树构建
def CreateTree(pre_train_data, pre_train_label, epsilon, parent_dot="DecisionTree"):
    '''
    构建决策树
    '''   
    # 类别去重
    Class = np.unique(pre_train_label)

    # 如果对于当前的标签集合而言,类别只有一个
    # 说明这个结点是叶结点,返回这个类
    if len(Class) == 1:
        return Class[0]

    # 如果已经没有特征可以进行分类了,返回当前label集中数目最多的类
    if len(pre_train_data[0]) == 0:
        return FindMajorClass(pre_train_label)

    # 其它情况下,需要继续对结点进行分类,计算信息增益
    # 得到信息增益最大的特征,及其信息增益
    BestFeature, IGMax = InforGain(pre_train_data, pre_train_label)
    # feature_name = get_best_feature_name(BestFeature)
    # print('Best is {}, type is {}, feature name is '.format(BestFeature, type(BestFeature)))
    # 如果最佳特征的信息增益小于一个我们自己设定的阈值
    # 则采用当前标记中数目最多的类
    if IGMax             
关注
打赏
1663211900
查看更多评论
0.0417s