当前位置:   article > 正文

机器学习笔记(7)——决策树&随机森林代码_决策树代码

决策树代码

机器学习笔记(7)——决策树&随机森林代码

本文部分图片与文字来源网络或学术论文,仅供学习使用,持续修改完善中。

目录

机器学习笔记(7)——决策树&随机森林代码

1、决策树

python写决策树

sklearn实现决策树分类器

 sklearn实现决策树回归器

2、随机森林

sklearn实现随机森林分类器

 sklearn实现随机森林回归器

 sklearn用随机森林回归填补缺失值


1、决策树

决策树(Decision Tree)是一种非参数的有监督学习方法,它能够从一系列有特征和标签的数据中总结出决策规 则,并用树状图的结构来呈现这些规则,以解决分类和回归问题。

python写决策树

  1. import math
  2. import random
  3. from collections import Counter
  4. import pandas as pd
  5. import numpy as np
  6. import pygraphviz as pyg
  7. def calAccuracy(pred,label):
  8. """
  9. calAccuracy函数:计算准确率
  10. :param pred:预测值
  11. :param label:真实值
  12. :returns acc:正确率
  13. :returns p:查准率
  14. :returns r:查全率
  15. :returns f1:F1度量
  16. """
  17. num = len(pred)#样本个数
  18. TP = 0
  19. FN = 0
  20. FP = 0
  21. TN = 0
  22. '''分别计算TP FP FN TN'''
  23. for i in range(num):
  24. if pred[i] == 1 and label[i]==1:
  25. TP += 1
  26. elif pred[i] == 1 and label[i]==0:
  27. FP += 1
  28. elif pred[i] == 0 and label[i]==1:
  29. FN += 1
  30. elif pred[i] == 0 and label[i]==0:
  31. TN += 1
  32. '''计算准确率 查准率 查全率 F1度量'''
  33. acc = (TN+TP) / num
  34. if TP+FP==0:
  35. p = 0
  36. else:
  37. p = TP/(TP+FP)
  38. if TP+FN == 0:
  39. r = 0
  40. else:
  41. r = TP/(TP+FN)
  42. if p+r==0:
  43. f1 = 0
  44. else:
  45. f1 = 2*p*r/(p+r)
  46. return acc,p,r,f1
  47. def get_dataset(filename ="watermelon.txt"):
  48. """
  49. get_dataset:从文件中读取数据,将其转化为指定格式的dataset和col_name
  50. :returns dataset:数据+标签 col_name:列名,即有哪些属性
  51. """
  52. df = pd.read_csv(filename)
  53. #下面分别提取标签和数据:一行对应一个数据
  54. dataset = df.values.tolist()
  55. col_name = df.columns.values[0:-1].tolist()#剔除最后一列
  56. return dataset,col_name
  57. class Node(object):
  58. #决策树节点类
  59. def __init__(self):
  60. self.attr = None # 决策节点属性
  61. self.value = None # 节点与父节点的连接属性
  62. self.isLeaf = False # 是否为叶节点 T or F
  63. self.label = 0 # 叶节点对应标签
  64. self.parent = None # 父节点
  65. self.children = [] # 子列表
  66. @staticmethod
  67. def set_leaf(self, label):
  68. """
  69. :param self:
  70. :param label: 叶子节点分类值 int
  71. :return:
  72. """
  73. self.isLeaf = True
  74. self.label= label
  75. class DataSet(object):
  76. """
  77. 数据集类
  78. """
  79. def __init__(self, data_set, col_name):
  80. """
  81. :param col_name 列名 list[]
  82. :param data_set 数据集 list[list[]]:
  83. """
  84. self.num = len(data_set) #获得数据集大小
  85. self.data_set = data_set
  86. self.data = [example[:-1] for example in data_set if self.data_set[0]] #提取数据剔除标签
  87. self.labels = [int(example[-1]) for example in data_set if self.data_set[0]] # 类别向量集合
  88. self.col_name = col_name # 特征向量对应的标签
  89. def get_mostLabel(self):
  90. """
  91. 得到最多的类别
  92. """
  93. class_dict = Counter(self.labels)
  94. return max(class_dict)
  95. def is_OneClass(self):
  96. """
  97. 判断当前的data_set是否属于同一类别,如果是返回类别,如果不是,返回-1
  98. :return: class or -1
  99. """
  100. if len(np.unique(self.labels))==1:#只有一个类别
  101. return self.labels[0]
  102. else:
  103. return -1
  104. def group_feature(self, index, feature):
  105. """
  106. group_feature:将 data[index] 等于 feature的值放在一起,同时去除该列,保证不会重复计算
  107. :param index:当前处理特征的索引
  108. :param feature:处理的特征值
  109. :return:聚集后的数据经过打包返回
  110. """
  111. grouped_data_set = [example[:index]+example[index+1:] for example in self.data_set if example[index] == feature]
  112. sub_col = self.col_name.copy() # list 传参可能改变原参数值,故需要复制出新的labels避免影响原参数
  113. del(sub_col[index]) #删除划分属性
  114. return DataSet(grouped_data_set, sub_col)
  115. def is_sameFeature(self):
  116. """
  117. 判断数据集的所有特征是否相同
  118. :return: Ture or False
  119. """
  120. example = self.data[0]
  121. for index in range(self.num):
  122. if self.data[index] != example:
  123. return False
  124. return True
  125. def cal_ent(self):
  126. """
  127. 计算信息熵
  128. :return:float 信息熵
  129. """
  130. class_dict = Counter(self.labels)
  131. # 计算信息熵
  132. ent = 0
  133. for key in class_dict.keys():
  134. p = float(class_dict[key]) / self.num
  135. ent -= p*math.log(p, 2)
  136. return ent
  137. def split_continuous_feature(self, index, mid):
  138. """
  139. 划分连续型数据
  140. :param index:是哪一列特征
  141. :param mid:考察的中位数
  142. :return:经过DataSet类封装的数据集
  143. """
  144. left_feature_list = []
  145. right_feature_list = []
  146. for example in self.data_set:#遍历每一行数据
  147. if example[index] <= mid:
  148. left_feature_list.append(example) # 此处不用del第axis个标签,连续变量的属性可以作为后代节点的划分属性
  149. else:
  150. right_feature_list.append(example)
  151. return DataSet(left_feature_list, self.col_name), DataSet(right_feature_list, self.col_name)
  152. def choose_byGain(self):
  153. """
  154. 根据信息增益选择最佳列属性划分
  155. :return: 最佳划分属性索引,int
  156. """
  157. num_features = len(self.data[0])#特征数量
  158. max_Gain = -999#最大增益率
  159. best_feature_index = -1
  160. best_col = ""
  161. for index in range(num_features):
  162. new_ent = 0
  163. feature_list = [example[index] for example in self.data]#提取每一行特征
  164. if type(feature_list[0]).__name__ == "float": # 如果是连续值
  165. sorted_feature_list = sorted(feature_list)#对连续值排序
  166. split_list = []
  167. for k in range(self.num - 1):#考察选取哪一个中位数点
  168. mid_feature = (sorted_feature_list[k] + sorted_feature_list[k+1])/2#计算中位数
  169. split_list.append(mid_feature)
  170. left_feature_list, right_feature_list = self.split_continuous_feature(index, mid_feature)
  171. p_left = left_feature_list.num / float(self.num)
  172. p_right = right_feature_list.num / float(self.num)
  173. new_ent = p_left*left_feature_list.cal_ent() + p_right*right_feature_list.cal_ent()#划分后只有两个类别
  174. gain = self.cal_ent() - new_ent # 计算增益率
  175. if gain > max_Gain:
  176. max_Gain = gain
  177. best_feature_index = index
  178. best_col = self.col_name[best_feature_index] + "<=" + str(mid_feature)
  179. else:
  180. unique_feature = np.unique(feature_list)#剔除重复出现的特征减少计算量
  181. for feature in unique_feature:
  182. sub_data_set = self.group_feature(index,feature)
  183. p = sub_data_set.num/float(self.num)#同一个个数比例
  184. new_ent += p*sub_data_set.cal_ent()
  185. gain = self.cal_ent()-new_ent#计算增益率
  186. if gain > max_Gain:
  187. max_Gain = gain
  188. best_feature_index = index
  189. best_col = self.col_name[best_feature_index]
  190. return best_feature_index, best_col
  191. def choose_byGain_ratio(self):
  192. """
  193. 根据信息增益率选择最佳列属性划分
  194. :return: 最佳划分属性索引,int
  195. """
  196. gain_list = []#记录各个属性的信息增益
  197. gainRatio_list = []#记录各个属性的增益率
  198. col_list = []
  199. num_features = len(self.data[0])#特征数量
  200. best_col = ""
  201. for index in range(num_features):
  202. new_ent = 0
  203. feature_list = [example[index] for example in self.data]#提取每一行特征
  204. if type(feature_list[0]).__name__ == "float": # 如果是连续值
  205. sorted_feature_list = sorted(feature_list)#对连续值排序
  206. split_list = []
  207. maxGain = -999
  208. for k in range(self.num - 1):#考察选取哪一个中位数点
  209. mid_feature = (sorted_feature_list[k] + sorted_feature_list[k+1])/2#计算中位数
  210. split_list.append(mid_feature)
  211. left_feature_list, right_feature_list = self.split_continuous_feature(index, mid_feature)
  212. p_left = left_feature_list.num / float(self.num)
  213. p_right = right_feature_list.num / float(self.num)
  214. new_ent = p_left*left_feature_list.cal_ent() + p_right*right_feature_list.cal_ent()#划分后只有两个类别
  215. gain = self.cal_ent() - new_ent # 计算
  216. if gain>maxGain:
  217. maxGain = gain
  218. best_feature_index = index
  219. best_col = self.col_name[best_feature_index] + "<=" + str(mid_feature)
  220. IV =p_left*math.log(p_left,2)+math.log(p_right,2)*p_right
  221. IV = 0-IV#取相反数
  222. Gain_ratio = gain/IV#计算信息增益
  223. gain_list.append(maxGain)
  224. gainRatio_list.append(Gain_ratio)
  225. col_list.append(best_col)
  226. else:
  227. unique_feature = np.unique(feature_list)#剔除重复出现的特征减少计算量
  228. IV = 0
  229. for feature in unique_feature:
  230. sub_data_set = self.group_feature(index,feature)
  231. p = sub_data_set.num/float(self.num)#同一个个数比例
  232. new_ent += p*sub_data_set.cal_ent()
  233. IV += p*math.log(p,2)
  234. gain = self.cal_ent()-new_ent#计算信息增益
  235. if IV==0:
  236. IV=0.001
  237. IV = 0 - IV # 取相反数
  238. Gain_ratio = gain / IV#计算增益率
  239. gain_list.append(gain)
  240. gainRatio_list.append(Gain_ratio)
  241. col_list.append(self.col_name[index])
  242. av_gain = np.average(gain_list)#求均值
  243. dic_table = {}#信息增益和增益率的对照字典,key为增益率,值为信息增益和index的元祖
  244. for i in range(num_features):
  245. dic_table[gainRatio_list[i]] = (gain_list[i],i)
  246. gainRatio_list.sort(reverse=True)#对增益率排序
  247. for ratio in gainRatio_list:
  248. if dic_table[ratio][0]>=av_gain:#高于平均值
  249. index = dic_table[ratio][1]
  250. return index, col_list[index]
  251. else:
  252. continue
  253. from pygraphviz import AGraph
  254. class DecisionTree(object):
  255. """
  256. 决策树
  257. """
  258. def __init__(self, data_set:DataSet,strategy):
  259. self.root = self.bulidTree(data_set,strategy)#头结点
  260. def bulidTree(self,data_set:DataSet,strategy):
  261. """
  262. :param data_set: 建立树用到的数据集
  263. :param strategy:选择建立树的策略包含--信息增益:gain --增益率gain-ratio
  264. :return:建立树的头结点
  265. """
  266. node = Node()
  267. if data_set.is_OneClass() != -1: # 如果数据集中样本属于同一类别
  268. node.isLeaf = True # 标记为叶子节点
  269. node.label = data_set.is_OneClass() # 标记叶子节点的类别为此类
  270. return node
  271. if len(data_set.data) == 0 or data_set.is_sameFeature(): # 如果数据集为空或者数据集的特征向量相同
  272. node.isLeaf = True # 标记为叶子节点
  273. node.label = data_set.get_mostLabel() # 标记叶子节点的类别为数据集中样本数最多的类
  274. return node
  275. if strategy=='gain_ratio':
  276. best_feature_index, best_col = data_set.choose_byGain_ratio() # 最佳划分数据集的标签索引,最佳划分数据集的列名
  277. elif strategy=='gain':
  278. best_feature_index, best_col = data_set.choose_byGain()
  279. else:
  280. print("输入策略有误!!!")
  281. return node
  282. node.attr = best_col # 设置非叶节点的属性为最佳划分数据集的列名
  283. if u'<=' in node.attr: #如果当前属性是连续属性
  284. mid_value = float(best_col.split('<=')[1]) # 获得比较值
  285. left_data_set, right_data_set = data_set.split_continuous_feature(best_feature_index, mid_value)
  286. left_node = Node()
  287. right_node = Node()
  288. '''分别求左右子树'''
  289. if left_data_set.num == 0: # 如果子数据集为空
  290. left_node.isLeaf = True # 标记新节点为叶子节点
  291. left_node.label = data_set.get_mostLabel() # 类别为父数据集中样本数最多的类
  292. else:
  293. left_node = self.bulidTree(left_data_set,strategy)#递归生成新的树
  294. if right_data_set.num == 0: # 如果子数据集为空
  295. right_node.isLeaf = True # 标记新节点为叶子节点
  296. right_node.label = data_set.get_mostLabel() # 类别为父数据集中样本数最多的类
  297. else:
  298. right_node = self.bulidTree(right_data_set,strategy)
  299. left_node.value = '小于等于'
  300. right_node.value = '大于'
  301. node.children.append(left_node)#记录孩子
  302. node.children.append(right_node)#记录又孩子
  303. else:
  304. feature_set = np.unique([example[best_feature_index] for example in data_set.data]) #最佳划分标签的可取值集合
  305. for feature in feature_set:
  306. new_node = Node()
  307. sub_data_set = data_set.group_feature(best_feature_index, feature) # 划分数据集并返回子数据集
  308. if sub_data_set.num == 0:# 如果子数据集为空
  309. new_node.isLeaf = True # 标记新节点为叶子节点
  310. new_node.label = data_set.get_mostLabel() # 类别为父数据集中样本数最多的类
  311. else:
  312. new_node = self.bulidTree(sub_data_set,strategy)
  313. new_node.value = feature # 设置节点与父节点间的连接属性
  314. new_node.parent = node # 设置父节点
  315. node.children.append(new_node)
  316. return node
  317. def save(self, filename):
  318. g = pyg.AGraph(strict=False, directed=True)
  319. g.add_node(self.root.attr, fontname="Microsoft YaHei")
  320. self._save(g, self.root)
  321. g.layout(prog='dot')
  322. g.draw(filename)
  323. def _save(self, graph, root):
  324. if len(root.children) > 0:
  325. for node in root.children:
  326. if node.attr != None:
  327. graph.add_node(node.attr, fontname="Microsoft YaHei")
  328. graph.add_edge(root.attr, node.attr, label=node.value, fontname="Microsoft YaHei")
  329. else:
  330. graph.add_node(node.label, shape="box", fontname="Microsoft YaHei")
  331. graph.add_edge(root.attr, node.label, label=node.value, fontname="Microsoft YaHei")
  332. self._save(graph, node)
  333. def predict_one(self, test_x, node, col_name) -> int:
  334. if (len(node.children) == 0):
  335. return node.label
  336. else:
  337. if u'<=' not in node.attr: # 处理离散数据
  338. index = col_name.index(node.attr)
  339. for chil in node.children:
  340. if chil.value == None: # 是一个叶子节点
  341. return chil.label
  342. if chil.value == test_x[index]:
  343. return self.predict_one(test_x, chil, col_name)
  344. else:
  345. col_ = node.attr.split("<=")[0]
  346. value = eval(node.attr.split("<=")[1])
  347. index = col_name.index(col_) # 这个元素的索引是啥
  348. if test_x[index] <= value: # 小于划分节点,在左子树
  349. return self.predict_one(test_x, node.children[0], col_name)
  350. else:
  351. return self.predict_one(test_x, node.children[1], col_name)
  352. def predict(self, test_data, col_name):
  353. pred = []
  354. for data in test_data:
  355. pred_y = self.predict_one(data, self.root, col_name)
  356. pred.append(pred_y)
  357. return pred
  358. dataset,col_name = get_dataset()
  359. # print(dataset)
  360. # print(col_name)
  361. random.shuffle(dataset) #将序列中的元素随机打乱
  362. train_data, test_data = dataset[0:12],dataset[12:17] #前12列为训练数据,13-17的5列为测试数据
  363. test_label = [test_data[i][-1] for i in range(len(test_data))] #5个测试数据的label
  364. Train_Data_set = DataSet(train_data,col_name)
  365. print("*" *10 + "测试集样本情况"+ "*" *10)
  366. for data in test_data:
  367. print(data)

 ID4.5 iterative dichotomiser 迭代二分器,使用的信息增益率划分

  1. print("*"*10+"信息增益率"+"*"*10)
  2. decisionTree = DecisionTree(Train_Data_set,strategy ='gain_ratio')
  3. decisionTree.save('watermelon_gainRatio.jpg')
  4. pred = decisionTree.predict(test_data,col_name)
  5. print("预测值:",pred)
  6. acc, p, r, f1 = calAccuracy(pred,test_label)
  7. print("正确率:{:.2%}\t查准率:{:.4f}\t查全率:{:.4f}\tF1:{:.4f}".format(acc,p,r,f1))

ID3 使用的信息增益划分

  1. print("*"*10+"信息增益"+"*"*10)
  2. decisionTree = DecisionTree(Train_Data_set,strategy ='gain')
  3. decisionTree.save('watermelon_gain.jpg')
  4. pred = decisionTree.predict(test_data,col_name)
  5. print("预测值:",pred)
  6. acc, p, r, f1 = calAccuracy(pred,test_label)
  7. print("正确率:{:.2%}\t查准率:{:.4f}\t查全率:{:.4f}\tF1:{:.4f}".format(acc,p,r,f1))

sklearn实现决策树分类器

  1. from sklearn import tree
  2. from sklearn.datasets import load_wine
  3. from sklearn.model_selection import train_test_split
  4. wine = load_wine()
  5. wine.data.shape
  6. wine.target
  7. import pandas as pd
  8. pd.concat([pd.DataFrame(wine.data),pd.DataFrame(wine.target)],axis=1)

  1. Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3)
  2. clf = tree.DecisionTreeClassifier(criterion="entropy")
  3. clf = clf.fit(Xtrain, Ytrain)
  4. score = clf.score(Xtest, Ytest) #返回预测的准确度accuracy
  5. feature_name = ['酒精','苹果酸','灰','灰的碱性','镁','总酚','类黄酮','非黄烷类酚类','花青素','颜色强度','色调','od280/od315稀释葡萄酒','脯氨酸']
  6. import graphviz
  7. dot_data = tree.export_graphviz(clf, out_file="Tree.dot"
  8. ,feature_names = feature_name
  9. ,class_names=["琴酒","雪莉","贝尔摩德"]
  10. ,filled=True
  11. ,rounded=True
  12. )
  13. clf.feature_importances_
  14. [*zip(feature_name,clf.feature_importances_)]
  15. clf = tree.DecisionTreeClassifier(criterion="entropy",random_state=30)
  16. clf = clf.fit(Xtrain, Ytrain)
  17. score = clf.score(Xtest, Ytest) #返回预测的准确度
  18. score

 

 参数:

random_state:用来设置分枝中的随机模式的参数,默认None,在高维度时随机性会表现更明显,低维度的数据 (比如鸢尾花数据集),随机性几乎不会显现。输入任意整数,会一直长出同一棵树,让模型稳定下来。

splitter:也是用来控制决策树中的随机选项的,有两种输入值,输入”best",决策树在分枝时虽然随机,但是还是会 优先选择更重要的特征进行分枝(重要性可以通过属性feature_importances_查看),输入“random",决策树在 分枝时会更加随机,树会因为含有更多的不必要信息而更深更大,并因这些不必要信息而降低对训练集的拟合。这 也是防止过拟合的一种方式。

剪枝操作:

max_depth: 限制树的最大深度,超过设定深度的树枝全部剪掉 这是用得最广泛的剪枝参数,在高维度低样本量时非常有效。决策树多生长一层,对样本量的需求会增加一倍,所 以限制树深度能够有效地限制过拟合。在集成算法中也非常实用。实际使用时,建议从=3开始尝试,看看拟合的效 果再决定是否增加设定深度。

min_samples_leaf限定:一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样本,否则分 枝就不会发生,或者,分枝会朝着满足每个子节点都包含min_samples_leaf个样本的方向去发生。

  1. clf = tree.DecisionTreeClassifier(criterion="entropy"
  2. ,random_state=30
  3. ,splitter="random"
  4. ,max_depth=3
  5. # ,min_samples_leaf=10
  6. # ,min_samples_split=25
  7. )
  8. clf = clf.fit(Xtrain, Ytrain)
  9. dot_data = tree.export_graphviz(clf
  10. ,feature_names= feature_name
  11. ,class_names=["琴酒","雪莉","贝尔摩德"]
  12. ,filled=True
  13. ,rounded=True
  14. )
  15. graph = graphviz.Source(dot_data)
  16. graph
  17. score = clf.score(Xtest, Ytest)
  18. score
  19. import matplotlib.pyplot as plt
  20. test = []
  21. for i in range(10):
  22. clf = tree.DecisionTreeClassifier(max_depth=i+1
  23. ,criterion="entropy"
  24. ,random_state=30
  25. ,splitter="random"
  26. )
  27. clf = clf.fit(Xtrain, Ytrain)
  28. score = clf.score(Xtest, Ytest)
  29. test.append(score)
  30. plt.plot(range(1,11),test,color="red",label="max_depth")
  31. plt.legend()
  32. plt.show()

  1. #apply返回每个测试样本所在的叶子节点的索引
  2. clf.apply(Xtest)
  3. #predict返回每个测试样本的分类/回归结果
  4. clf.predict(Xtest)

 sklearn实现决策树回归器

  1. from sklearn.datasets import load_boston
  2. from sklearn.model_selection import cross_val_score
  3. from sklearn.tree import DecisionTreeRegressor
  4. boston = load_boston()
  5. #regressor = DecisionTreeRegressor(random_state=0) #实例化
  6. #cross_val_score(regressor, boston.data, boston.target, cv=10).mean()
  7. regressor = DecisionTreeRegressor(random_state=0)
  8. cross_val_score(regressor, boston.data, boston.target, cv=10,
  9. scoring = "neg_mean_squared_error"
  10. )

一维回归的图像绘制:

  1. import numpy as np
  2. from sklearn.tree import DecisionTreeRegressor
  3. import matplotlib.pyplot as plt
  4. rng = np.random.RandomState(1) #随机数种子
  5. X = np.sort(5 * rng.rand(80,1), axis=0) #生成0~5之间随机的x的取值
  6. y = np.sin(X).ravel() #生成正弦曲线
  7. y[::5] += 3 * (0.5 - rng.rand(16)) #在正弦曲线上加噪声
  8. plt.figure()
  9. plt.scatter(X, y, s=20, edgecolor="black",c="darkorange", label="data")

  1. regr_1 = DecisionTreeRegressor(max_depth=2)
  2. regr_2 = DecisionTreeRegressor(max_depth=5)
  3. regr_1.fit(X, y)
  4. regr_2.fit(X, y)
  5. X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis]
  6. y_1 = regr_1.predict(X_test)
  7. y_2 = regr_2.predict(X_test)
  8. plt.figure()
  9. plt.scatter(X, y, s=20, edgecolor="black",c="darkorange", label="data")
  10. plt.plot(X_test, y_1, color="cornflowerblue",label="max_depth=2", linewidth=2)
  11. plt.plot(X_test, y_2, color="yellowgreen", label="max_depth=5", linewidth=2)
  12. plt.xlabel("data")
  13. plt.ylabel("target")
  14. plt.title("Decision Tree Regression")
  15. plt.legend()
  16. plt.show()

2、随机森林

随机森林是非常具有代表性的Bagging集成算法,它的所有基评估器都是决策树,分类树组成的森林就叫做随机森 林分类器,回归树所集成的森林就叫做随机森林回归器。

控制基评估器的参数

criterion 不纯度的衡量指标,有基尼系数和信息熵两种选择。

max_depth 树的最大深度,超过最大深度的树枝都会被剪掉。

min_samples_leaf 一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样 本,否则分枝就不会发生。

min_samples_split 一个节点必须要包含至少min_samples_split个训练样本,这个节点才允许被分 枝,否则分枝就不会发生。

max_features max_features限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃, 默认值为总特征个数开平方取整。

min_impurity_decrease 限制信息增益的大小,信息增益小于设定数值的分枝不会发生。

n_estimators参数:森林中树木的数量,即基评估器的数量。这个参数对随机森林模型的精确性影响是单调的,n_estimators越 大,模型的效果往往越好。但是相应的,任何模型都有决策边界,n_estimators达到一定的程度之后,随机森林的 精确性往往不在上升或开始波动,并且,n_estimators越大,需要的计算量和内存也越大,训练的时间也会越来越 长。对于这个参数,我们是渴望在训练难度和模型效果之间取得平衡。

sklearn实现随机森林分类器

  1. %matplotlib inline
  2. from sklearn.tree import DecisionTreeClassifier
  3. from sklearn.ensemble import RandomForestClassifier
  4. from sklearn.datasets import load_wine
  5. wine = load_wine()
  6. #实例化
  7. #训练集带入实例化的模型去进行训练,使用的接口是fit
  8. #使用其他接口将测试集导入我们训练好的模型,去获取我们希望过去的结果(score.Y_test)
  9. from sklearn.model_selection import train_test_split
  10. Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3)
  11. clf = DecisionTreeClassifier(random_state=0)
  12. rfc = RandomForestClassifier(random_state=0)
  13. clf = clf.fit(Xtrain,Ytrain)
  14. rfc = rfc.fit(Xtrain,Ytrain)
  15. score_c = clf.score(Xtest,Ytest)
  16. score_r = rfc.score(Xtest,Ytest)
  17. print("Single Tree:{}".format(score_c)
  18. ,"Random Forest:{}".format(score_r))
  19. #交叉验证:是数据集划分为n分,依次取每一份做测试集,每n-1份做训练集,多次训练模型以观测模型稳定性的方法
  20. from sklearn.model_selection import cross_val_score
  21. import matplotlib.pyplot as plt
  22. rfc = RandomForestClassifier(n_estimators=25)
  23. rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10)
  24. clf = DecisionTreeClassifier()
  25. clf_s = cross_val_score(clf,wine.data,wine.target,cv=10)
  26. plt.plot(range(1,11),rfc_s,label = "RandomForest")
  27. plt.plot(range(1,11),clf_s,label = "Decision Tree")
  28. plt.legend()
  29. plt.show()
  30. #====================一种更加有趣也更简单的写法===================#
  31. """
  32. label = "RandomForest"
  33. for model in [RandomForestClassifier(n_estimators=25),DecisionTreeClassifier()]:
  34. score = cross_val_score(model,wine.data,wine.target,cv=10)
  35. print("{}:".format(label)),print(score.mean())
  36. plt.plot(range(1,11),score,label = label)
  37. plt.legend()
  38. label = "DecisionTree"
  39. """

 画出随机森林和决策树在十组交叉验证下的效果对比:

  1. rfc_l = []
  2. clf_l = []
  3. for i in range(10):
  4. rfc = RandomForestClassifier(n_estimators=25)
  5. rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10).mean()
  6. rfc_l.append(rfc_s)
  7. clf = DecisionTreeClassifier()
  8. clf_s = cross_val_score(clf,wine.data,wine.target,cv=10).mean()
  9. clf_l.append(clf_s)
  10. plt.plot(range(1,11),rfc_l,label = "Random Forest")
  11. plt.plot(range(1,11),clf_l,label = "Decision Tree")
  12. plt.legend()
  13. plt.show()
  14. #是否有注意到,单个决策树的波动轨迹和随机森林一致?
  15. #再次验证了我们之前提到的,单个决策树的准确率越高,随机森林的准确率也会越高

 

 n_estimators的学习曲线:

  1. superpa = []
  2. for i in range(200):
  3. rfc = RandomForestClassifier(n_estimators=i+1,n_jobs=-1)
  4. rfc_s = cross_val_score(rfc,wine.data,wine.target,cv=10).mean()
  5. superpa.append(rfc_s)
  6. print(max(superpa),superpa.index(max(superpa))+1)#打印出:最高精确度取值,max(superpa))+1指的是森林数目的数量n_estimators
  7. plt.figure(figsize=[20,5])
  8. plt.plot(range(1,201),superpa)
  9. plt.show()

 

 sklearn实现随机森林回归器

  1. from sklearn.datasets import load_boston#一个标签是连续西变量的数据集
  2. from sklearn.model_selection import cross_val_score#导入交叉验证模块
  3. from sklearn.ensemble import RandomForestRegressor#导入随机森林回归系
  4. boston = load_boston()
  5. regressor = RandomForestRegressor(n_estimators=100,random_state=0)#实例化
  6. cross_val_score(regressor, boston.data, boston.target, cv=10
  7. ,scoring = "neg_mean_squared_error"#如果不写scoring,回归评估默认是R平方
  8. )

 sklearn用随机森林回归填补缺失值

  1. import numpy as np
  2. import pandas as pd
  3. import matplotlib.pyplot as plt
  4. from sklearn.datasets import load_boston
  5. from sklearn.impute import SimpleImputer#填补缺失值的类
  6. from sklearn.ensemble import RandomForestRegressor
  7. from sklearn.model_selection import cross_val_score
  8. dataset = load_boston()
  9. dataset#是一个字典
  10. dataset.target#查看数据标签
  11. dataset.data#数据的特征矩阵
  12. dataset.data.shape#数据的结构
  13. #总共506*13=6578个数据
  14. X_full, y_full = dataset.data, dataset.target
  15. n_samples = X_full.shape[0]#506
  16. n_features = X_full.shape[1]#13
  17. #首先确定我们希望放入的缺失数据的比例,在这里我们假设是50%,那总共就要有3289个数据缺失
  18. rng = np.random.RandomState(0)#设置一个随机种子,方便观察
  19. missing_rate = 0.5
  20. n_missing_samples = int(np.floor(n_samples * n_features * missing_rate))#3289
  21. #np.floor向下取整,返回.0格式的浮点数
  22. #所有数据要随机遍布在数据集的各行各列当中,而一个缺失的数据会需要一个行索引和一个列索引
  23. #如果能够创造一个数组,包含3289个分布在0~506中间的行索引,和3289个分布在0~13之间的列索引,那我们就可以利用索引来为数据中的任意3289个位置赋空值
  24. #然后我们用0,均值和随机森林来填写这些缺失值,然后查看回归的结果如何
  25. missing_features = rng.randint(0,n_features,n_missing_samples)#randint(下限,上限,n)指在下限和上限之间取出n个整数
  26. len(missing_features)#3289
  27. missing_samples = rng.randint(0,n_samples,n_missing_samples)
  28. len(missing_samples)#3289
  29. #missing_samples = rng.choice(n_samples,n_missing_samples,replace=False)
  30. #我们现在采样了3289个数据,远远超过我们的样本量506,所以我们使用随机抽取的函数randint。
  31. # 但如果我们需要的数据量小于我们的样本量506,那我们可以采用np.random.choice来抽样,choice会随机抽取不重复的随机数,
  32. # 因此可以帮助我们让数据更加分散,确保数据不会集中在一些行中!
  33. #这里我们不采用np.random.choice,因为我们现在采样了3289个数据,远远超过我们的样本量506,使用np.random.choice会报错
  34. X_missing = X_full.copy()
  35. y_missing = y_full.copy()
  36. X_missing[missing_samples,missing_features] = np.nan
  37. X_missing = pd.DataFrame(X_missing)
  38. #转换成DataFrame是为了后续方便各种操作,numpy对矩阵的运算速度快到拯救人生,但是在索引等功能上却不如pandas来得好用
  39. X_missing.head()
  40. #并没有对y_missing进行缺失值填补,原因是有监督学习,不能缺标签啊

 

  1. #使用均值进行填补
  2. from sklearn.impute import SimpleImputer
  3. imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')#实例化
  4. X_missing_mean = imp_mean.fit_transform(X_missing)#特殊的接口fit_transform = 训练fit + 导出predict
  5. #pd.DataFrame(X_missing_mean).isnull()#但是数据量大的时候还是看不全
  6. #布尔值False = 0, True = 1
  7. # pd.DataFrame(X_missing_mean).isnull().sum()#如果求和为0可以彻底确认是否有NaN
  8. #使用0进行填补
  9. imp_0 = SimpleImputer(missing_values=np.nan, strategy="constant",fill_value=0)#constant指的是常数
  10. X_missing_0 = imp_0.fit_transform(X_missing)
  11. X_missing_reg = X_missing.copy()
  12. #找出数据集中,缺失值从小到大排列的特征们的顺序,并且有了这些的索引
  13. sortindex = np.argsort(X_missing_reg.isnull().sum(axis=0)).values#np.argsort()返回的是从小到大排序的顺序所对应的索引
  14. for i in sortindex:
  15. #构建我们的新特征矩阵(没有被选中去填充的特征 + 原始的标签)和新标签(被选中去填充的特征)
  16. df = X_missing_reg
  17. fillc = df.iloc[:,i]#新标签
  18. df = pd.concat([df.iloc[:,df.columns != i],pd.DataFrame(y_full)],axis=1)#新特征矩阵
  19. #在新特征矩阵中,对含有缺失值的列,进行0的填补
  20. df_0 =SimpleImputer(missing_values=np.nan,strategy='constant',fill_value=0).fit_transform(df)
  21. #找出我们的训练集和测试集
  22. Ytrain = fillc[fillc.notnull()]# Ytrain是被选中要填充的特征中(现在是我们的标签),存在的那些值:非空值
  23. Ytest = fillc[fillc.isnull()]#Ytest 是被选中要填充的特征中(现在是我们的标签),不存在的那些值:空值。注意我们需要的不是Ytest的值,需要的是Ytest所带的索引
  24. Xtrain = df_0[Ytrain.index,:]#在新特征矩阵上,被选出来的要填充的特征的非空值所对应的记录
  25. Xtest = df_0[Ytest.index,:]#在新特征矩阵上,被选出来的要填充的特征的空值所对应的记录
  26. #用随机森林回归来填补缺失值
  27. rfc = RandomForestRegressor(n_estimators=100)#实例化
  28. rfc = rfc.fit(Xtrain, Ytrain)#导入训练集进行训练
  29. Ypredict = rfc.predict(Xtest)#用predict接口将Xtest导入,得到我们的预测结果(回归结果),就是我们要用来填补空值的这些值
  30. #将填补好的特征返回到我们的原始的特征矩阵中
  31. X_missing_reg.loc[X_missing_reg.iloc[:,i].isnull(),i] = Ypredict
  32. #检验是否有空值
  33. X_missing_reg.isnull().sum()
  34. #对所有数据进行建模,取得MSE结果
  35. X = [X_full,X_missing_mean,X_missing_0,X_missing_reg]
  36. mse = []
  37. std = []
  38. for x in X:
  39. estimator = RandomForestRegressor(random_state=0, n_estimators=100)#实例化
  40. scores = cross_val_score(estimator,x,y_full,scoring='neg_mean_squared_error', cv=5).mean()
  41. mse.append(scores * -1)
  42. [*zip(['Full data','Zero Imputation','Mean Imputation','Regressor Imputation'],mse)]
  43. x_labels = ['Full data',
  44. 'Zero Imputation',
  45. 'Mean Imputation',
  46. 'Regressor Imputation']
  47. colors = ['r', 'g', 'b', 'orange']
  48. plt.figure(figsize=(12, 6))#画出画布
  49. ax = plt.subplot(111)#添加子图
  50. for i in np.arange(len(mse)):
  51. ax.barh(i, mse[i],color=colors[i], alpha=0.6, align='center')#bar为条形图,barh为横向条形图,alpha表示条的粗度
  52. ax.set_title('Imputation Techniques with Boston Data')
  53. ax.set_xlim(left=np.min(mse) * 0.9,
  54. right=np.max(mse) * 1.1)#设置x轴取值范围
  55. ax.set_yticks(np.arange(len(mse)))
  56. ax.set_xlabel('MSE')
  57. ax.set_yticklabels(x_labels)
  58. plt.show()

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

闽ICP备14008679号