使用决策树方法对泰坦尼克幸存者进行预测。 数据下载链接: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
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?