随机森林(Random Forest):
随机森林是一个最近比较火的算法,它有很多的优点:
- 在数据集上表现良好
- 在当前的很多数据集上,相对其他算法有着很大的优势
- 它能够处理很高维度(feature很多)的数据,并且不用做特征选择
- 在训练完后,它能够给出哪些feature比较重要
- 在创建随机森林的时候,对generlization error使用的是无偏估计
- 训练速度快
- 在训练过程中,能够检测到feature间的互相影响
- 容易做成并行化方法
- 实现比较简单
随机森林最早由Leo Breiman与Adele Cutler提出,
随机森林顾名思义,是用随机的方式建立一个森林,森林里面有很多的决策树组成,随机森林的每一棵决策树之间是没有关联的(跟Adaboost相反,Adaboost的每个基学习器互相相关。)。在得到森林之后,当有一个新的输入样本进入的时候,就让森林中的每一棵决策树分别进行一下判断,看看这个样本应该属于哪一类(对于分类算法),然后看看哪一类被选择最多,就预测这个样本为那一类。
在建立每一棵决策树的过程中,有两点需要注意 - 采样与完全分裂。首先是两个随机采样的过程,random forest对输入的数据要进行行的采样(即样本的采样)和列的采样(特征的采样)。对于行采样,采用有放回的方式,也就是在采样得到的样本集合中,可能有重复的样本。假设输入样本为N个,那么采样的样本也为N个。这样使得在训练的时候,每一棵树的输入样本都不是全部的样本,使得相对不容易出现over-fitting,这种方法也叫作re-sampling,通常情况下,随机抽取得到的N个样本中,只出现输入样本的60~70%的样本,剩下的样本不在re-sampling后的样本中出现。
然后进行列采样(特征采样),从M个feature中,选择m个(一般选择m=log2M)。之后就是对采样之后的数据根据CART进行分类。注意:在基学习器深度大于1的情况,要对每个结点都从该点的特征集合中重新选取k个特征,并且根据GINI系数进行判断,从而将决策树继续展开。这样决策树的某一个叶子节点要么是无法继续分裂的(更倾向于这种,这种方法就是设置基学习器CART的高度),要么里面的所有样本的都是指向的同一个分类(可能每个学习器都需要很多迭代,不推荐)。一般很多的决策树算法都一个重要的步骤 - 剪枝,但是这里不这样干,由于之前的两个随机采样的过程保证了随机性,所以就算不剪枝,也不会出现over-fitting。
按这种算法得到的随机森林中的每一棵都是很弱的,但是大家组合起来就很厉害了。我觉得可以这样比喻随机森林算法:每一棵决策树就是一个精通于某一个窄领域的专家(因为我们从M个feature中选择m让每一棵决策树进行学习),这样在随机森林中就有了很多个精通不同领域的专家,对一个新的问题(新的输入数据),可以用不同的角度去看待它,最终由各个专家,投票得到结果。
下面是随机森林最简单实现的Python代码:
- '''''
- Samuel Gao
- 2017.4.19
- 随机森林
- 离散属性
- 1、基学习器深度取为1 ,因为我这里
- 只随机取1个进行决策树分析,
- 没有用到CART决策树,按gini系数比较。对特征多的可以加上。
- ps:要对每个基学习器的节点随机抽取一个特征进行分叉,除非像我一样
- ,将每棵树的高度设为1.
- 2、基学习器可以并行生成,有兴趣的可以用Threading或multiprocessing模块
- 来实现,还是不太难的。这里没有写出
- '''
- # from sklearn.ensemble import RandomForestClassifier
- import numpy as np
- import pandas as pd
- import random
- from threading import Thread
- from collections import Counter
- def xunlian(data, number):
- featureChoice = int(np.random.randint(0, number-1, 1))
- features = list(data[featureChoice].unique())
- # features为['清脆', '沉闷']的形式
- categorys = list(data[featureChoice])
- dicts = {}
- cc = 0
- for ll in features:
- dicts[ll] = []
- for m in categorys:
- for j in features:
- if m == j:
- dicts[j].append(cc)
- cc += 1
- for i in features:
- lst = dicts.get(i)
- new_lst = []
- if len(lst) > 0:
- for k in lst:
- new_lst.append(int(data[k:k+1][data.shape[1]-1]))
- jieguo = Counter(new_lst).most_common(1)[0][0]
- dicts[i] = jieguo
- return dicts
- # dicts 为 {'清脆':1, '沉闷':0}的形式
- class RandomForest():
- def __init__(self, n_estimators = 3):
- self.estimators = n_estimators
- @staticmethod
- def assemble(inputs, labels):
- n = len(labels)
- for i in range(n):
- inputs[i].append(labels[i])
- data = np.vstack(inputs)
- return data
- def train(self, inputs, labels):
- n = len(inputs[0]) # 特征个数
- data = RandomForest.assemble(inputs, labels)
- data = pd.DataFrame(data)
- sum_dicts = {}
- rows = int(data.shape[0])
- rcounts = rows - 1
- for i in range(self.estimators):
- df = pd.DataFrame()
- for m in range(rows):
- j = random.randint(0, int(rcounts))
- df = df.append(data.loc[j, :])
- sum_dicts[i] = xunlian(df, n)
- return sum_dicts
- # 多线程并行生成基学习器方式:以后有时间完善
- # threads = []
- # for i in range(self.estimators):
- # ti = Thread(target=xunlian, args=(data, n,))
- # threads.append(ti)
- #
- # for t in threads:
- # t.setDeamon(True)
- # t.start()
- def predict(self, input, model):
- n = len(model)
- # n为基学习器的个数
- predicts = list()
- for i in range(n):
- categoryes = model[i]
- for j in input:
- if j in categoryes.keys():
- predicts.append(categoryes[j])
- prediction = Counter(predicts).most_common(1)
- print(prediction)
- if prediction[0][0] == 0:
- print("预测结果为:坏瓜")
- else:
- print("预测结果为:好瓜")
- if __name__ == "__main__":
- ex = RandomForest() # 默认为3个基学习器
- a0 = ['浅绿', '清脆', '中']
- a1 = ['深绿', '沉闷', '大']
- a2 = ['薄白', '清脆', '小']
- a3 = ['浅绿', '清脆', '小']
- a4 = ['深绿', '沉闷', '中']
- lst = [a0, a1, a2, a3, a4]
- y = [0, 1, 0, 1, 1] # 0坏 1好
- model = ex.train(lst, y)
- ex.predict(['浅绿', '清脆', '小'], model)
参考资料:
1、 http://www.cnblogs.com/LeftNotEasy/archive/2011/03/07/random-forest-and-gbdt.html
2 、http://blog.csdn.net/w28971023/article/details/8240756