65.9K
CodeProject 正在变化。 阅读更多。
Home

随机森林 Python

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (21投票s)

2017年7月18日

CPOL

9分钟阅读

viewsIcon

49919

downloadIcon

1221

本文以一种简单易懂的方式提供了关于随机森林(一种流行的机器学习算法)的 Python 代码。

要求: 机器学习

随机森林简介

随机森林是一种流行的算法,用作分类和回归的集成学习方法。这意味着随机森林包含多个决策树。每棵决策树结果的平均值将是随机森林的最终输出。决策树存在一些缺点,例如在训练集上过拟合导致高方差,尽管随机森林通过 Bagging(Bootstrap Aggregating)解决了这个问题。首先,最好先了解决策树算法,然后再研究随机森林。因为随机森林是由许多决策树组成的。

决策树

决策树使用树状图,通过考虑图中的所有元素来做出可能的决策。例如,回想一下那位网球运动员,他有一个计划在不同天气条件下打球。现在,我们想知道这位运动员在第 15 天是否会打球?

寻找纯分支

有 15 天,其中 9 天他打了球,5 天他没打球;现在我们想知道他在特定情况下是否会打球。您应该仔细查看训练数据,其中有不同的特征和不同的值。我们必须查看每个特征的所有值(所有天数“打球=是”或“打球=否”),或者换句话说,上面表格中的哪个值颜色相同。

(湿度 = 高  所有天数: (打球 = 是) | (打球 = 否))

(湿度 = 正常  所有天数: (打球 = 是) | (打球 = 否))

(风 = 弱  所有天数: (打球 = 是) | (打球 = 否))

(风 = 强  所有天数: (打球 = 是) | (打球 = 否))

(外观 = 雨  所有天数: (打球 = 是) | (打球 = 否))

(外观 = 晴  所有天数: (打球 = 是) | (打球 = 否))

(外观 = 阴  所有天数: (打球 = 是) | (打球 = 否)) 是 √

所以,当“外观 = 阴”(D3、D7、D12、D13)时,我们的运动员总是打球;我们应该从“外观”特征开始建立分支并作为根。因此,下次,我们应该关注“外观 = 晴”,并尝试找出是“湿度”还是“风”是下一个。在 D1、D2、D8、D9、D11;只有 (D1、D2、D8) (湿度 = 高) 颜色相同或值相同,这次 (打球 = 否) 晴天:D1、D2、D8、D9、D11

  1. 晴天:D1、D2、D8 & (湿度 = 高)  (打球 = 否)
  2. 晴天:D9、D11 & (湿度 = 正常)  (打球 = 是)

    所以我们的下一个分支是“湿度”,因为我们找到了“纯粹”的值。现在,看看当

    “外观 = 雨” 雨天:D4、D5、D6、D10、D14 1. 雨天:D4、D5、D10 & (风 = 弱)  (打球 = 是)

  3. 雨天:D6、D14 & (风 = 强)  (打球 = 否)

现在让我们一目了然地比较一下表格和决策树。

因此,为了计算以下情况,我们首先考虑“外观 = 雨”,然后沿右分支,检查“风 = 弱”,所以我们深入到左侧,答案是“是”。提示:过拟合定义;在下面的图中;正如你所见,我们将每个节点拆分,直到达到“纯净”结果。例如,最后一个“叶子(树的末端节点)”中的所有“打球”结果都应该是相同的“是”或“否”。如果一直拆分直到完美纯净的集合,那么准确率将是 100%。这意味着每个叶子最终只有一个特定的值。拆分越多,准确率越高,树越大,因为树的生长越来越多。如果树的大小与数据集相同,那么我们就“过拟合”了。过拟合导致算法过于具体于(训练)数据,但它无法泛化测试数据。如何避免或停止过拟合是修剪树,以某种方式移除不适合未来测试数据的分支,然后查看结果移除是否会损害或改善我们的分析。

[ 如果 (“外观 = 晴” & “湿度 = 正常”  所有“打球 = 是”) ]

[ 如果 (“外观 = 雨” & “风 = 弱”  所有“打球 = 是”) ]

D15:“外观 = 雨” & “湿度 = 高” & “风 = 弱”

随机森林

随机森林是一种集成学习方法,非常适合监督学习,如分类和回归。在随机森林中,我们将训练集分成更小的部分,并将每个小部分作为独立的树,其结果不会影响其他树。随机森林获取训练集并使用“Bagging = Bootstrap Aggregating”算法对其进行划分,该算法通过防止过拟合和降低方差来提高准确性。它开始将数据集分成 60% 作为独立的决策树,30% 作为重叠数据。

它将训练集分成“B”棵不同的决策树(其中 60% 使用独特数据,30% 使用重复数据),然后开始计算每棵决策树的结果并拆分它们,直到达到适当的情况(当它足以泛化到测试数据时)。下面,您可以看到有两个“否”答案和三个“是”答案,因此答案的平均值是“是”。

随机森林中的错误计算:有一些方法可以增强随机森林的优化。交叉验证用于评估预测模型的结果如何泛化到其他独立测试数据。下面有一个训练集,其中输出被划分为“Y”,特征被划分为“X”。

引导

随机创建 T 棵树;T = { T1 , T2 , T3 , T4 , T5 },每次对每个数据进行 n 次抽样。袋外错误:如果我们随机选择特定的 j = (Xi , Yi) 并查找所有树中的 j,并找到一些不包含此值的树,那么它们将构成袋外错误。实际上,当 (Xi , Yi) 不在树中时,它重复 n 次的比例。

代码

我准备了训练集和测试集数据,以便用 Python 练习随机森林。训练集是与一些患者相关的数据,在训练集中,我们知道他们将根据年龄、性别和医院类别得到治愈。测试集是用于测试的数据,我们不知道谁会被治愈,我们应该用随机森林来检查它。我有一个空的 Excel 文件 result.csv 用于在其中写入结果。我选择了所有扩展名为“csv”,因为它们方便与 Python 一起使用。训练 测试 结果 随机森林是监督学习。要了解更多关于它的知识,请阅读本文

下载 Python

如果您想使用舒适的 IDE 和专业的编辑器轻松上手,而无需安装库。您可以使用 Anaconda & Spider

然后从开始菜单打开 Anaconda Navigator,选择“Spyder”。

有一些要点

  1. Python 是面向对象的
  2. 动态类型
  3. 丰富的库
  4. 易于阅读
  5. Python 区分大小写
  6. 缩进对 Python 很重要

Python 实现随机森林

步骤 1:导入重要库,如 numpy、用于 I/O 的 csv、sklearn

import numpy as np
import csv as csv
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.cross_validation import StratifiedKFold # Add important libs

步骤 2:训练和测试准备:读取数据并填充到数组中

请考虑您的路径并根据保存方式进行更改。例如,如果您将 train 和 test 保存在 D 盘根目录,请将其替换为 path1 = r'D:\train.csv'

train=[]
test=[]         #Array Definition
path1 =  r'D:\random forest\data set\train.csv'     #Address Definition
path2 =  r'D:\random forest\data set\test.csv'
with open(path1, 'r') as f1:    #Open File as read by 'r'
    reader = csv.reader(f1)     
    next(reader, None)          #Skip header because file header is not needed
    for row in reader:          #fill array by file info by for loop
        train.append(row)
    train = np.array(train)       	
	
with open(path2, 'r') as f2:
    reader2 = csv.reader(f2)
    next(reader2, None)  
    for row2 in  reader2:
        test.append(row2)
    test = np.array(test)
    
train = np.delete(train,[0],1)  #delete first column of which is patientid
test = np.delete(test,[0],1)

步骤 3:删除与“PatientID”相关的第一个列,我们的算法不需要知道 patientid。

train = np.delete(train,[0],1)  #delete first column of which is patientid
test = np.delete(test,[0],1)

步骤 4:手动优化数据,将性别替换为整数值

train[train[0::,3] == 'male', 3] = 1        #replacement gender with number
train[train[0::,3] == 'female', 3] = 0
test[test[0::,2] == 'male',2] = 1
test[test[0::,2] == 'female',2] = 0

步骤 5:优化数据

因为患者的治愈情况与他们的年龄直接相关,而且年龄列中有一些缺失值,所以通过了解患者的情况,[他的年龄是多少?] 或 [他的头衔是什么?] 或 [他使用了哪种医院类别?]。因此,首先提取他们的头衔,然后根据这些,安排缺失的年龄值。

for row in  train:
	Title = row[2].split(',')[1].split('.')[0].strip() #Extracting Name in order to gain title
	row[2] = Title
	
for row in train:       #Fill empty cell o rage column by the below logic
	if (row[4]==''):
		if (row[1]=='1' and row[2]=='Miss' and row[3]=='0'):
			row[4] =30
		if (row[1]=='1' and row[2]=='Mrs' and row[3]=='0'):
			row[4] =40
		if (row[1]=='2' and row[2]=='Miss' and row[3]=='0'):
			row[4] =24
		if (row[1]=='2' and row[2]=='Mrs' and row[3]=='0'):
			row[4] =31.5
		if (row[1]=='3' and row[2]=='Miss' and row[3]=='0'):
			row[4] =18
		if (row[1]=='3' and row[2]=='Mrs' and row[3]=='0'):
			row[4] =31
		if (row[1]=='1' and row[2]=='Master' and row[3]=='1'):
			row[4] =4
		if (row[1]=='1' and row[2]=='Mr' and row[3]=='1'):
			row[4] =40
		if (row[1]=='2' and row[2]=='Master' and row[3]=='1'):
			row[4] =1
		if (row[1]=='2' and row[2]=='Mr' and row[3]=='1'):
			row[4] =31
		if (row[1]=='3' and row[2]=='Master' and row[3]=='1'):
			row[4] =4
		if (row[1]=='3' and row[2]=='Mr' and row[3]=='1'):
			row[4] =26
			
for row in  test:
	Title = row[1].split(',')[1].split('.')[0].strip()
	row[1] = Title
	
for row in test:
	if (row[3]==''):
		if (row[0]=='1' and row[1]=='Miss' and row[2]=='0'):
			row[3] =32
		if (row[0]=='1' and row[1]=='Mrs' and row[2]=='0'):
			row[3] =48
		if (row[0]=='2' and row[1]=='Miss' and row[2]=='0'):
			row[3] =19.5
		if (row[0]=='2' and row[1]=='Mrs' and row[2]=='0'):
			row[3] =29
		if (row[0]=='3' and row[1]=='Miss' and row[2]=='0'):
			row[3] =22
		if (row[0]=='3' and row[1]=='Mrs' and row[2]=='0'):
			row[3] =28
		if (row[0]=='3' and row[1]=='Ms' and row[2]=='0'):
			row[3] =22
		if (row[0]=='1' and row[1]=='Master' and row[2]=='1'):
			row[3] =9.5
		if (row[0]=='1' and row[1]=='Mr' and row[2]=='1'):
			row[3] =42
		if (row[0]=='2' and row[1]=='Master' and row[2]=='1'):
			row[3] =5
		if (row[0]=='2' and row[1]=='Mr' and row[2]=='1'):
			row[3] =28
		if (row[0]=='3' and row[1]=='Master' and row[2]=='1'):
			row[3] =7
		if (row[0]=='3' and row[1]=='Mr' and row[2]=='1'):
			row[3] =25

步骤 6:删除不必要的列

train = np.delete(train,[2],1) #Delete name column because it is not needed
test = np.delete(test,[1],1)    

步骤 7:通过网格搜索优化算法

  • max_depth:它告诉 RF 每棵决策树应该有多深,它接受不同值的数组,由于不确定最佳数量,我添加了两个值 [3,4]。
  • n_estimators:它告诉 RF 应该创建多少棵决策树以获得更好的精度。
  • max_features:在这个训练集示例中,有四个特征
    1. 医院类别
    2. 名称
    3. 性别
    4. 年龄

    当我们想拆分节点时,我们会选择这些特征中的一些或全部,这会影响准确的答案。如果等于 auto,则表示选择了所有特征。

  • min_samples_split:它告诉 RF 对于每个创建的新节点应该有多少个拆分。 min_samples_leaf:叶子是末端节点,没有子节点,在每棵决策树的底部。
  • bootstrap:
parameter_gridsearch = {
                 'max_depth' : [3, 4],  #depth of each decision tree
                 'n_estimators': [50, 20],  #count of decision tree
                 'max_features': ['sqrt', 'auto', 'log2'],      
                 'min_samples_split': [2],      
                 'min_samples_leaf': [1, 3, 4],
                 'bootstrap': [True, False],
                 }

步骤 8:随机森林分类器

randomforest = RandomForestClassifier()
crossvalidation = StratifiedKFold(train[0::,0] , n_folds=5)

gridsearch = GridSearchCV(randomforest,             #grid search for algorithm optimization
                               scoring='accuracy',
                               param_grid=parameter_gridsearch,
                               cv=crossvalidation)


gridsearch.fit(train[0::,1::], train[0::,0])    #train[0::,0] is as target
model = gridsearch
parameters = gridsearch.best_params_

步骤 9:得分计算

print('Best Score: {}'.format(gridsearch.best_score_))
Best Score: 0.8571428571428571

步骤 10:将答案写入 result.csv 文件

path3 =  r'D:\random forest\data set\result.csv'

output = gridsearch.predict(test)

print(output)
with open(path3, 'w',  newline='') as f3, 
    open(path2, 'r') as f4: # write output and other column from test
    forest_Csv = csv.writer(f3)
    forest_Csv.writerow(["PatientId", "healed", "Hospitalclass", "Name", "Sex", "Age"])    
    test_file_object = csv.reader(f4)
    next(test_file_object, None)
    i = 0
    for row in  test_file_object:
        row.insert(1,output[i].astype(np.uint8))
        forest_Csv.writerow(row)
        i += 1

结论

如今,随机森林因其精度和优化功能而成为数据科学家非常受欢迎的选择。它包含多个决策树,我们可以决定需要多少棵树来进行数据导航。RF 解决了决策树的过拟合问题。过拟合是尽可能完整地训练训练数据集,达到 100% 拟合或全部训练集,但难以泛化到所有测试数据。随机森林使用 bagging 或 bootstrap aggregating 将训练集分成不同的独立决策树,并在不干扰其他树的情况下计算它们的结果,最后对所有结果取平均值。最后,它作为元估计器的能力,可以处理不同训练集子集中的决策树数量,以提高准确预测并良好地控制过拟合。

反馈

请随时对本文发表任何反馈;很高兴看到您的意见和对该代码的**投票**。如果您有任何问题,请随时在此处提问。

历史

  • 2019 年 4 月 3 日:初始版本
© . All rights reserved.