
1,初品随机森林
随机森林,森林就是很多决策树放在一起一起叫森林,而随机体现在数据集的随机采样中和特征的随机选取中,具体下面再讲。通俗的说随机森林就是建立多颗决策树(CART),来做分类(回归),以多数表决(平均法)来得出我们的分类(回归)结果。
这种思想就是一种集成思想,集成算法目前有两大类,一类是基学习器(可看做本文讲的决策树)之间存在强依赖性,基分类器的得出依赖于前面的分类器(前面分类器的结果会影响后面分类器的训练),可形象的看做个基学习器是串联的,代表是 Adaboost, Xgboost, GBDT(后面两种我们以后总结)。另一类是个体学习器之间不存在相关关系,相互独立,可形象的看做并联关系,代表是bagging和随机森林。
在建立独立的决策树时,有一些细节问题需要注意。
2, 随机选择样本
随机森林的随机之一就在样本的选择上,我们从样本集中有放回的随机采样,这种采样方法与bagging采样方法一致,具体采样过程如下:
- 有放回的从样本集中(
个)随机采取
个样本,这
个样本中有重复样本。
- 进行
轮采样(
为决策树个数),采样方法如1。
def
3, 随机选择特征
随机森林的另一随机就在特征选择上,随机森林本质就是对决策树的Bagging集成,只是在决策树的建立过程中加入了特征的随机选择。一直说特征选择,到底在哪用到了特征选择?接着说,每一棵决策树的每一个节点的建立不再是遍历每个特征的每一个取值,而是随机的选取预设个数的特征,要比原特征个数小,这样是为了使决策树有差异,这样的森林具有更好的泛化能力。然后在选取的特征上进行最优特征与最优切分点的选取。
def feature_sample(rows,n_feature):import randomfeature_index = [] #用于存放随机选取的特征对应的列号while len(feature_index)<n_feature:index = random.randrange(len(rows[0])-1)if index not in feature_index: #选取的特征不重复feature_index.append(index)return feature_index
4, 集成方式
- 平均法:回归任务,对所有决策树的预测结果进行求平均
- 投票法:分类任务,少数服从多数
5, 随机森林代码实现
我们做一个随机森林的简单实现,使得更加理解随机森林。但如果在实际项目中使用,直接调用sklearn库中的函数即可。有一些辅助函数的实现,在上一篇决策树理论总结与代码实现 - 刘毛毛的文章 - 知乎 https://zhuanlan.zhihu.com/p/106833254文章中有实现,这里将直接使用。
def buildTree(rows,scoref,n_feature,min_size,min_gini,max_depth,depth):if len(rows)<=min_size:return decisionNode(results = uniquecounts(rows))if depth>=max_depth:return decisionNode(results = uniquecount(rows))best_gini = 0best_criteria = Nonebest_sets = None#特征抽样###features_index = feature_sample(rows,n_feature)#与决策树相比每个节点的最优特征候选集小了#根据抽取的特征对数据集进行拆分###for col in features_index:column_values={}for row in rows:column_values[row[col]]=1 #这样较决策树里的代码修改了一下,不重复的记录某特征的值values =[]for key in column_values.keys():#不在遍历某特征的所有值,只不重复的遍历values.append(key)for value in values:(set1,set2)=divideset(rows,col,value)p_set = float(len(set1))/len(rows)gini = p_set*scoref(set1)+(1-p_set)*scoref(set2)if gini>best_gini and len(set1)>0 and len(set2)>0:best_gini = ginibest_criteria=(col,value)best_sets = (set1,set2)if best_gini > min_gini:truebranch = buildTree(best_sets[0],scoref,n_feature,min_size,mini_gini,max_depth,depth+1)falsebranch = buildTree(best_sets[1],scoref,n_feature,min_size,mini_gini,max_depth,depth+1)return decisionnode(col = best_criteria[0],value = best_criteria[1],tb = truebranch,fb = falsebranch)else:return decisionnode(results=classcounts(rows))
添加预测函数,求准确率函数,结果集成函数(分类)
def predict_results(observation,tree):if tree.results != None:return tree.resultselse:v = observation[tree.col]Branch = Noneif isinstance(v,int) or isinstance(v,float):if v >= tree.value:Branch = tree.tbelse:Branch = tree.fbelse:if v == tree.value:Branch = tree.tbelse:Branch = tree.fbreturn predict_results(observation,Branch)def predict(observation,tree):results = predict_results(observation,tree)label = Noneb_count = 0for key in results.keys():if results[key] > b_count:b_count = results[key]label = keyreturn label
def accuracy(actual,predicted):correct =0for i in range(len(actual)):if actual[i]==predicted[i]:correct += 1accuracy = (float(correct)/len(actual))*100return accuracy
def bagging_predict(trees,row):predictions=[predict(row,tree) for tree in trees]return max(set(predictions),key=predictions.count)
随机森林实现
def RandomForest(train,test,ratio,max_depth=4,min_size=3,min_gini=0.3,n_trees=100,n_features=3,scoref=giniimpurity):trees = []for i in range(n_trees):subset = subsample(train,ratio)#subset = traintree=buildTree(subset,scoref,n_features,min_gini,min_size,max_depth,0)trees.append(tree)predictions=[bagging_predict(trees,row) for row in test]actual = [row[-1] for row in test]test_score = accuracy(actual,predictions)return test_score
亲测有效,只是对样本量小,特征又小的数据集效果不好,原因应该是在数据集较小的情况下,采样的数据就更加简单化,训练的模型自然不好。