当前位置:   article > 正文

AI-机器学习-自学笔记(五)决策树算法_embark town 和cabin

embark town 和cabin

        决策树(Decision Tree)是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法,是直观运用概率分析的一种图解法。由于这种决策分支画成图形很像一棵树的枝干,故称决策树。

        简单说就是依据熵值计算,不断地做出选择,直到获得最终结果(熵值为0或者在设定的某个范围内)。根据计算方法不同,有ID3算法、C4.5算法、CART算法等。

        每个对象就是一个节点,开始的地方叫根节点,最后不能分的地方叫叶子节点。

剪枝

        剪枝是决策树停止分支的方法之一,剪枝有分预先剪枝和后剪枝两种。

        预先剪枝是在树的生长过程中设定一个指标,当达到该指标时就停止生长,这样做容易产生“视界局限”,就是一旦停止分支,使得节点N成为叶节点,就断绝了其后继节点进行“好”的分支操作的任何可能性。

        后剪枝中树首先要充分生长,直到叶节点都有最小的不纯度值为止,因而可以克服“视界局限”,而且无需保留部分样本用于交叉验证,所以可以充分利用全部训练集的信息。但后剪枝的计算量代价比预剪枝方法大得多,特别是在大样本集中,不过对于小样本的情况,后剪枝方法还是优于预剪枝方法的。

ID3算法

        以信息增益为准则来选择划分属性,选择划分后信息增益最大的属性进行划分,这种算法对属性可取数目较多时有偏好。

这里举个例子,比如说有个女生要选相亲对象,相亲对象有收入(income)、身高(hight)、长相(look)、体型(shape)等条件可以考察,那么我们用ID3算法来分析以下她的决策。

我们收集了她之前研究过的几十个相亲对象和决策情况,如下表,我们把它保存为文件data01.csv

收入身高长相体型是否见面
一般
普通
一般
匀称
匀称
普通
一般普通匀称
普通匀称
一般
普通
一般
一般普通匀称
一般普通
一般
一般匀称
普通
普通
普通
一般匀称
普通
一般

然后我们用ID3算法来分析:

  1. from math import log
  2. import operator
  3. import numpy as np
  4. import pandas as pd
  5. from pandas import DataFrame, Series
  6. #构建决策和数字的映射
  7. productDict = {'高':1,'一般':2,'低':3,'中':2, '帅':1, '普通':2, '丑':3, '胖':3, '匀称':2,'瘦':1, '是':1, '否':0}
  8. #导入数据
  9. def Importdata(datafile):
  10. dataa = pd.read_excel(datafile) # datafile是excel文件,所以用read_excel,如果是csv文件则用read_csv
  11. #将文本中不可直接使用的文本变量替换成数字
  12. dataa['income'] = dataa['收入'].map(productDict) # 将每一列中的数据按照字典规定的转化成数字
  13. dataa['hight'] = dataa['身高'].map(productDict)
  14. dataa['look'] = dataa['长相'].map(productDict)
  15. dataa['shape'] = dataa['体型'].map(productDict)
  16. dataa['is_meet'] = dataa['是否见面'].map(productDict)
  17. data = dataa.iloc[:,5:].values.tolist() # 取量化后的几列,去掉文本列
  18. b = dataa.iloc[0:0,5:-1]
  19. labels = b.columns.values.tolist() # 将标题中的值存入列表中
  20. return data,labels
  21. #计算数据的熵(entropy)--原始熵
  22. def dataentropy(data, feat):
  23. lendata = len(data) # 数据条数
  24. labelCounts = {} # 数据中不同类别的条数
  25. for featVec in data:
  26. category = featVec[-1] # 每行数据的最后一个字(叶子节点)
  27. if category not in labelCounts.keys():
  28. labelCounts[category] = 0
  29. labelCounts[category] += 1 # 统计有多少个类以及每个类的数量
  30. entropy = 0
  31. for key in labelCounts:
  32. prob = float(labelCounts[key]) / lendata # 计算单个类的熵值
  33. entropy -= prob * log(prob,2) # 累加每个类的熵值
  34. return entropy
  35. #对数据按某个特征value进行分类
  36. def splitData(data,i,value):
  37. splitData = []
  38. for featVec in data:
  39. if featVec[i] == value:
  40. rfv = featVec[:i]
  41. rfv.extend(featVec[i+1:])
  42. splitData.append(rfv)
  43. return splitData
  44. #选择最优的分类特征
  45. def BestSplit(data):
  46. numFea = len(data[0]) - 1 # 计算一共有多少个特征,因为最后一列一般是分类结果,所以需要-1
  47. baseEnt = dataentropy(data,-1) # 定义初始的熵,用于对比分类后信息增益的变化
  48. bestInfo = 0
  49. bestFeat = -1
  50. for i in range(numFea):
  51. featList = [rowdata[i] for rowdata in data]
  52. uniqueVals = set(featList)
  53. newEnt = 0
  54. for value in uniqueVals:
  55. subData = splitData(data,i,value) # 获取按照特征value分类后的数据
  56. prob = len(subData) / float(len(data))
  57. newEnt += prob * dataentropy(subData,i) # 按特征分类后计算得到的熵
  58. info = baseEnt - newEnt # 原始熵与按特征分类后的熵的差值,即信息增益
  59. if (info > bestInfo): # 若按某特征划分后,若infoGain大于bestInf,则infoGain对应的特征分类区分样本的能力更强,更具有代表性。
  60. bestInfo = info # 将infoGain赋值给bestInf,如果出现比infoGain更大的信息增益,说明还有更好地特征分类
  61. bestFeat = i # 将最大的信息增益对应的特征下标赋给bestFea,返回最佳分类特征
  62. return bestFeat
  63. #按分类后类别数量排序,取数量较大的
  64. def majorityCnt(classList):
  65. c_count = {}
  66. for i in classList:
  67. if i not in c_count.keys():
  68. c_count[i] = 0
  69. c_count[i] += 1
  70. ClassCount = sorted(c_count.items(),key=operator.itemgetter(1),reverse=True) # 按照统计量降序排序
  71. return ClassCount[0][0] # reverse=True表示降序,因此取[0][0],即最大值
  72. #构建树
  73. def createTree(data,labels):
  74. classList = [rowdata[-1] for rowdata in data] # 取每一行的最后一列,分类结果(1/0)
  75. #print(classList)
  76. if classList.count(classList[0]) == len(classList):
  77. return classList[0]
  78. if len(data[0]) == 1:
  79. return majorityCnt(classList)
  80. bestFeat = BestSplit(data) # 根据信息增益选择最优特征
  81. bestLab = labels[bestFeat]
  82. myTree = {bestLab:{}} # 分类结果以字典形式保存
  83. del(labels[bestFeat])
  84. featValues = [rowdata[bestFeat] for rowdata in data]
  85. uniqueVals = set(featValues)
  86. for value in uniqueVals:
  87. subLabels = labels[:]
  88. myTree[bestLab][value] = createTree(splitData(data,bestFeat,value),subLabels)
  89. return myTree
  90. #主程序
  91. datafile = 'data/dateperson/date01.xlsx' # 文件所在位置
  92. data, labels = Importdata(datafile) # 导入数据
  93. jc=createTree(data, labels) # 输出决策树模型结果
  94. print(jc)

执行之后得到如下结果:

  1. PS C:\coding\machinelearning>ID3相亲决策实验.py
  2. {'income': {1: 1, 2: {'hight': {1: {'look': {1: 1, 2: 1, 3: {'shape': {0: 0, 1: 1}}}}, 2: 1, 3: 0}}, 3: {'hight': {1: {'look': {2: 1, 3: 0}}, 2: 0, 3: 0}}}}
  3. PS C:\coding\machinelearning>

从结果来看,小姐姐找相亲对象,首先看收入,收入高的一定见,收入中等的再看身高、长相等。收入低的除非又高又帅,否则免谈。

C4.5算法

        选择具有最大增益率的属性作为划分属性,具体做法是先从候选划分属性中找到信息增益高于平均水平的属性,再从中选择增益率最高的作为划分属性。

下面再用C4.5算法把上面小姐姐相亲的例子再算一遍

  1. from math import log
  2. import operator
  3. import numpy as np
  4. import pandas as pd
  5. from pandas import DataFrame, Series
  6. productDict = {'高':1,'一般':2,'低':3,'中':2, '帅':1, '普通':2, '丑':3, '胖':3, '匀称':2,'瘦':1, '是':1, '否':0}
  7. #导入数据
  8. def Importdata(datafile):
  9. dataa = pd.read_excel(datafile) # datafile是excel文件,所以用read_excel,如果是csv文件则用read_csv
  10. #将文本中不可直接使用的文本变量替换成数字
  11. dataa['income'] = dataa['收入'].map(productDict) # 将每一列中的数据按照字典规定的转化成数字
  12. dataa['hight'] = dataa['身高'].map(productDict)
  13. dataa['look'] = dataa['长相'].map(productDict)
  14. dataa['shape'] = dataa['体型'].map(productDict)
  15. dataa['is_meet'] = dataa['是否见面'].map(productDict)
  16. data = dataa.iloc[:,5:].values.tolist() # 取量化后的几列,去掉文本列
  17. b = dataa.iloc[0:0,5:-1]
  18. labels = b.columns.values.tolist() # 将标题中的值存入列表中
  19. return data,labels
  20. #计算数据的熵(entropy)--原始熵
  21. def dataentropy(data, feat):
  22. lendata = len(data) # 数据条数
  23. labelCounts = {} # 数据中不同类别的条数
  24. for featVec in data:
  25. category = featVec[-1] # 每行数据的最后一个字(叶子节点)
  26. if category not in labelCounts.keys():
  27. labelCounts[category] = 0
  28. labelCounts[category] += 1 # 统计有多少个类以及每个类的数量
  29. entropy = 0
  30. for key in labelCounts:
  31. prob = float(labelCounts[key]) / lendata # 计算单个类的熵值
  32. entropy -= prob * log(prob,2) # 累加每个类的熵值
  33. return entropy
  34. #对数据按某个特征value进行分类
  35. def splitData(data,i,value):
  36. splitData = []
  37. for featVec in data:
  38. if featVec[i] == value:
  39. rfv = featVec[:i]
  40. rfv.extend(featVec[i+1:])
  41. splitData.append(rfv)
  42. return splitData
  43. #选择最优的分类特征
  44. def BestSplit(data):
  45. numFea = len(data[0]) - 1 # 计算一共有多少个特征,因为最后一列一般是分类结果,所以需要-1
  46. baseEnt = dataentropy(data, -1) # 定义初始的熵,用于对比分类后信息增益的变化
  47. bestGainRate = 0
  48. bestFeat = -1
  49. for i in range(numFea):
  50. featList = [rowdata[i] for rowdata in data]
  51. uniqueVals = set(featList)
  52. newEnt = 0
  53. for value in uniqueVals:
  54. subData = splitData(data,i,value) # 获取按照特征value分类后的数据
  55. prob = len(subData) / float(len(data))
  56. newEnt += prob * dataentropy(subData, i) # 按特征分类后计算得到的熵
  57. info = baseEnt - newEnt # 原始熵与按特征分类后的熵的差值,即信息增益
  58. splitonfo = dataentropy(subData,i) # 分裂信息
  59. if splitonfo == 0: # 若特征值相同(eg:长相这一特征的值都是帅),即splitonfo和info均为0,则跳过该特征
  60. continue
  61. GainRate = info / splitonfo # 计算信息增益率
  62. if (GainRate > bestGainRate): # 若按某特征划分后,若infoGain大于bestInf,则infoGain对应的特征分类区分样本的能力更强,更具有代表性。
  63. bestGainRate = GainRate # 将infoGain赋值给bestInf,如果出现比infoGain更大的信息增益,说明还有更好地特征分类
  64. bestFeat = i # 将最大的信息增益对应的特征下标赋给bestFea,返回最佳分类特征
  65. return bestFeat
  66. def majorityCnt(classList):
  67. c_count = {}
  68. for i in classList:
  69. if i not in c_count.keys():
  70. c_count[i] = 0
  71. c_count[i] += 1
  72. ClassCount = sorted(c_count.items(),key=operator.itemgetter(1),reverse=True)#按照统计量降序排序
  73. return ClassCount[0][0]#reverse=True表示降序,因此取[0][0],即最大值
  74. #构建树
  75. def createTree(data,labels):
  76. classList = [rowdata[-1] for rowdata in data] # 取每一行的最后一列,分类结果(1/0)
  77. if classList.count(classList[0]) == len(classList):
  78. return classList[0]
  79. if len(data[0]) == 1:
  80. return majorityCnt(classList)
  81. bestFeat = BestSplit(data) # 根据信息增益选择最优特征
  82. bestLab = labels[bestFeat]
  83. myTree = {bestLab:{}} # 分类结果以字典形式保存
  84. del(labels[bestFeat])
  85. featValues = [rowdata[bestFeat] for rowdata in data]
  86. uniqueVals = set(featValues)
  87. for value in uniqueVals:
  88. subLabels = labels[:]
  89. myTree[bestLab][value] = createTree(splitData(data,bestFeat,value),subLabels)
  90. return myTree
  91. #主程序
  92. datafile = 'data/dateperson/date01.xlsx' # 文件所在位置
  93. data, labels = Importdata(datafile) # 导入数据
  94. jc=createTree(data, labels) # 输出决策树模型结果
  95. print(jc)

得到结果和上面的算法大致差不多

  1. PS C:\coding\machinelearning>C4.5相亲决策实验.py
  2. {'income': {1: 1, 2: {'look': {1: 1, 2: 1, 3: {'shape': {1: {'hight': {0: 0, 1: 1}}, 3: {'hight': {0: 0, 1: 1}}}}}}, 3: {'shape': {0: 0, 1: 1}}}}
  3. PS C:\coding\machinelearning>

CART算法

选择划分后基尼指数最小的属性最为最优划分属性。

这次我们找了个数据集,Titanic号生还者情况的数据集,来分析下乘客的生还情况

  1. #数据处理的库
  2. from numpy.lib.type_check import real
  3. import pandas as pd
  4. #数据分类
  5. from sklearn.model_selection import train_test_split
  6. #算法库
  7. from sklearn.tree import DecisionTreeClassifier
  8. from sklearn.preprocessing import LabelEncoder
  9. from sklearn.model_selection import GridSearchCV
  10. #评估用到的库
  11. from sklearn.metrics import make_scorer
  12. from sklearn.metrics import accuracy_score
  13. from sklearn.metrics import f1_score
  14. from sklearn.metrics import recall_score
  15. from sklearn.metrics import precision_score
  16. #预测
  17. import numpy as np
  18. #读取数据
  19. data = pd.read_csv('data/titanic/train.csv')
  20. print(data.head())
  21. data.info()
  22. # 计算各特征缺失总数
  23. total = data.isnull().sum().sort_values(ascending=False)
  24. # 计算各特征缺失比例
  25. percent = (data.isnull().sum()/data.isnull().count()).sort_values(ascending = False)
  26. miss_data = pd.concat([total, percent], axis = 1, keys = ['Miss_Total', 'Miss_Percent'])
  27. miss_data.head()
  28. # 缺失值处理。
  29. # 删除‘Cabin’
  30. del data['deck']
  31. # 采用中位数填充缺失值
  32. data['age'] = data['age'].fillna(data['age'].median())
  33. # 众数填充缺失值
  34. data['embark_town'] = data['embark_town'].fillna(data['embark_town'].mode()[0])
  35. # 查看数据情况
  36. data.info()
  37. # 观察Name特征提取其中的Title称呼
  38. #data['Title'] = data['Name'].str.split(",", expand=True)[1].str.split(".", expand=True)[0]
  39. # 将字符型变量做数值化处理
  40. label = LabelEncoder()
  41. data['sex'] = label.fit_transform(data['sex'])
  42. data['class'] = label.fit_transform(data['class'])
  43. data['alone'] = label.fit_transform(data['alone'])
  44. #data['Embarked'] = data['Embarked'].astype(str)
  45. data['embark_town'] = label.fit_transform(data['embark_town'])
  46. # 考虑到PassengerId和Ticker为随机生成的变量,不作为影响目标变量的信息,因此特征选择时,将其去除
  47. features = ['class', 'age', 'n_siblings_spouses', 'parch', 'fare', 'sex', 'alone', 'embark_town','survived']
  48. data = data[features]
  49. data.head()
  50. #划分训练集和测试集
  51. X = data[['class', 'age', 'n_siblings_spouses', 'parch', 'fare', 'sex', 'alone', 'embark_town']]
  52. y = data[['survived']]
  53. X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=2)#random_state为随机种子,确保每次划分的结果是相同的
  54. #训练模型
  55. dtc = DecisionTreeClassifier()
  56. dtc.fit(X_train, y_train)
  57. y_predict = dtc.predict(X_test)
  58. # 模型评分:准确率,查全率,查准率,F1得分
  59. accuracyScore = accuracy_score(y_test, y_predict)
  60. recallScore = recall_score(y_test, y_predict)
  61. precisionScore = precision_score(y_test, y_predict)
  62. f1Score = f1_score(y_test, y_predict)
  63. print("DecisionTreeClassifier Results")
  64. print("Accuracy :", accuracyScore)
  65. print("Recall :", recallScore)
  66. print("Precision :", precisionScore)
  67. print("F1 Score :", f1Score)
  68. param = {'max_depth': [1, 3, 5, 7]}
  69. # 采用网格搜索进行参数调优
  70. gsearch = GridSearchCV(estimator=dtc, param_grid=param, cv=5, scoring='f1')
  71. gsearch.fit(X=X_train, y=y_train)
  72. print("最优参数:{}".format(gsearch.best_params_))
  73. print("最优模型:{}".format((gsearch.best_estimator_)))
  74. print("模型最高分:{:.3f}".format(gsearch.score(X_test, y_test)))
  75. # 选择最优模型进行预测
  76. dtc = DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=3,
  77. max_features=None, max_leaf_nodes=None,
  78. min_samples_leaf=1, min_samples_split=2,
  79. min_weight_fraction_leaf=0.0, random_state=None,
  80. splitter='best')
  81. dtc.fit(X_train, y_train)
  82. y_predict = dtc.predict(X_test[:10])
  83. # 打印预测结果
  84. print('===================预测值=======================')
  85. print(y_predict)
  86. # 打印真实值
  87. print('===================真实值=======================')
  88. #print(np.array(y_test[:10]).tolist())
  89. realz = np.array(y_test[:10]).ravel()
  90. print(realz)
  91. Accuracy = accuracy_score(realz, y_predict)
  92. print('准确率为:{:.2f}%'.format(Accuracy*100))

打印预测结果如下:

  1. PS C:\coding\machinelearning>CART实验(titanic).py
  2. survived sex age n_siblings_spouses parch fare class deck embark_town alone
  3. 0 0 male 22.0 1 0 7.2500 Third unknown Southampton n
  4. 1 1 female 38.0 1 0 71.2833 First C Cherbourg n
  5. 2 1 female 26.0 0 0 7.9250 Third unknown Southampton y
  6. 3 1 female 35.0 1 0 53.1000 First C Southampton n
  7. 4 0 male 28.0 0 0 8.4583 Third unknown Queenstown y
  8. <class 'pandas.core.frame.DataFrame'>
  9. RangeIndex: 627 entries, 0 to 626
  10. Data columns (total 10 columns):
  11. # Column Non-Null Count Dtype
  12. --- ------ -------------- -----
  13. 0 survived 627 non-null int64
  14. 1 sex 627 non-null object
  15. 2 age 627 non-null float64
  16. 3 n_siblings_spouses 627 non-null int64
  17. 4 parch 627 non-null int64
  18. 5 fare 627 non-null float64
  19. 6 class 627 non-null object
  20. 7 deck 627 non-null object
  21. 8 embark_town 627 non-null object
  22. 9 alone 627 non-null object
  23. dtypes: float64(2), int64(3), object(5)
  24. memory usage: 49.1+ KB
  25. <class 'pandas.core.frame.DataFrame'>
  26. RangeIndex: 627 entries, 0 to 626
  27. Data columns (total 9 columns):
  28. # Column Non-Null Count Dtype
  29. --- ------ -------------- -----
  30. 0 survived 627 non-null int64
  31. 1 sex 627 non-null object
  32. 2 age 627 non-null float64
  33. 3 n_siblings_spouses 627 non-null int64
  34. 4 parch 627 non-null int64
  35. 5 fare 627 non-null float64
  36. 6 class 627 non-null object
  37. 7 embark_town 627 non-null object
  38. 8 alone 627 non-null object
  39. dtypes: float64(2), int64(3), object(4)
  40. memory usage: 44.2+ KB
  41. DecisionTreeClassifier Results
  42. Accuracy : 0.7698412698412699
  43. Recall : 0.7142857142857143
  44. Precision : 0.7
  45. F1 Score : 0.7070707070707072
  46. 最优参数:{'max_depth': 5}
  47. 最优模型:DecisionTreeClassifier(max_depth=5)
  48. 模型最高分:0.731
  49. ===================预测值=======================
  50. [1 1 0 1 0 0 0 1 0 0]
  51. ===================真实值=======================
  52. [1 0 0 1 0 0 0 1 0 0]
  53. 准确率为:90.00%
  54. PS C:\coding\machinelearning>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/330796
推荐阅读
相关标签
  

闽ICP备14008679号