在做项目时要用随机森林,查资料发现大多数都是用随机森林做分类,很少见到有回归的。虽然分类随机森林和回归随机森林代码实现相差不大,但是对于新手小白来说,如果有比较完整的代码直接学习可以节省很多时间,这是我写这篇文章的原因。
随机森林我就不介绍了,其他地方介绍一搜一大堆。
这篇文章关注的是如何用python实现回归随机森林。分为随机森林构建和随机森林预测两部分
随机森林构建——
#自定义参数
def mydata():
trees=10 #CART回归树的个数
n_features=6 #特征个数
max_depth=20 #树的最大深度
return trees,n_features,max_depth
#读入数据 这样路径和文件名分开写,方便以后将整个文件夹的数据导入进来。
def loadCsvDataSet(fileName='E:\\Anaconda3\\mydata\\data'):
csv_path=os.path.join(fileName,"AMCX.csv")
df=pd.read_csv(csv_path)
#print(df.values)
return df.values
#把dataset划分成训练数据和测试数据
def split_train_test_data(dataSet):
#第五列是adj close
#即DataSet中取出feature列的值大于value的行,赋值给mat0,
X_train=dataSet[np.nonzero(dataSet[:,0]<'2018-10-01')[0],:]
X_test=dataSet[np.nonzero(dataSet[:,0]>'2018-10-01')[0],:]
y_train=X_train[:,5]
y_test=X_test[:,5]
return X_train,X_test,y_train,y_test
#把dataset划分成训练数据和测试数据
def split_train_test_data(dataSet):
#第五列是adj close
#即DataSet中取出feature列的值大于value的行,赋值给mat0,
X_train=dataSet[np.nonzero(dataSet[:,0]<'2018-10-01')[0],:]
X_test=dataSet[np.nonzero(dataSet[:,0]>'2018-10-01')[0],:]
y_train=X_train[:,5]
y_test=X_test[:,5]
return X_train,X_test,y_train,y_test
#计算方差
def regErr(dataSet):
#第五列是adj close
return np.var(dataSet[:,5])*shape(dataSet)[0]
#计算平均值
def regLeaf(dataSet):
#第五列是adj close
return np.mean(dataSet[:,5])
#选取任意的n个特征,在这n个特征中,选取分割时的最优特征
#对每个特征值:
# 将数据集切分成两份
# 计算切分的误差
# 如果当前误差小于当前最小误差,那么将当前切分设定为最佳切分并更新最小误差,返回最佳切分的特征和阈值
#用shape[1]求出dataSet的列数,初始化index bestS和best_feature,bestValue
#S中存储着计算方差
def chooseBestSplit(dataSet,n_features):
#随机森林不需要进行剪枝
f=dataSet.shape[1]#shape[0]是指dataset的行数,估计1是指dataset的列数
index=[]
bestS=inf
best_feature,bestValue=0,0
S=regErr(dataSet)#回归用于计算方差
for i in range(n_features):
#从dataset的列数f的范围内有放回地取n_features个数,放到index集合里
index.append(np.random.randint(f)) #index里存储着所有取出来的行数集合
#尝试index次分割,每次分割的特征是feature列
for feature in index:
for splitVal in set(dataSet[:,feature]):#set是无序无重复的集合,即把dataSet里的数据去除重复值,遍历dataSet里feature列中不重复的数值,逐个数尝试,有没有哪个数用于分割是最优的(最优的意思是:划分后得到的两部分内部区别最小,即类内方差最小)
#这个binSplitDataSet是上面定义的用于把数据集分为两份的函数
mat0,mat1=binSplitDataSet(dataSet,feature,splitVal)
newS=regErr(mat0)+regErr(mat1)#regErr是求方差
if bestS>newS:#如果新的news比最优的s小,就把数据更新
bestfeature=feature
#splitVal是在feature列下不同的值的数字之一,是切分数据的value
bestValue=splitVal
bestS=newS
#print(bestValue)
#printf(bestfeature)
#if(S-bestS)<0.0000001:#如果误差不大就退出 #设置一个可以接受的误差精度,有这个没这么准确,因此我选择去除,大家可以在自己的项目对比要不要这几句话
#print(regLeaf(dataSet))
#return None,regLeaf(dataSet) #regLeaf计算dataSet的平均值
#mat0,mat1=binSplitDataSet(dataSet,bestfeature,bestValue)
if(shape(mat0)[0]<10)or(shape(mat1)[0]<10):11
#print(regLeaf(dataSet))
return None,regLeaf(dataSet)
return bestfeature,bestValue
#实现树 这里使用递归
#首先调用chooseBestSplit得到返回值bestfeature和bestValue
#然后建立左右子树
#如果深度到指定深度,就返回剩余dataSet的平均值。
#retTree是一个字典,有'bestFeature' 'bestVal' 'right'和'left'
#返回retree
def createTree(dataSet,n_features,max_depth):#min_size是啥啊
bestfeature,bestValue=chooseBestSplit(dataSet,n_features)
if bestfeature==None:
#print(bestValue)
return bestValue
retTree={} #retTree中存储着一泼CART回归树
max_depth-=1
if max_depth<0: #控制树的深度
return regLeaf(dataSet) #regLeaf是算平均值的函数
retTree['bestFeature']=bestfeature
retTree['bestVal']=bestValue
lSet,rSet=binSplitDataSet(dataSet,bestfeature,bestValue)
retTree['right']=createTree(rSet,n_features,max_depth)
retTree['left']=createTree(lSet,n_features,max_depth)
return retTree
#创建n棵树
#最后将X_train调用createTree存储到Trees中。
#返回Trees.Tress里存储的就是n课树
def RandomForest(dataSet,ops):#这个n应该就是树的个数
#dataSet=get_Datasets()
Trees=[]
for i in range(ops[0]):
Trees.append((createTree(X_train,ops[1],ops[2]))) #构件训练数据的树
return Trees
随机森林预测——
#预测单个数据样本 #这里也用递归
#先判断树是不是一个字典,如果不是就到达结束递归的条件,返回tree转化成float的值
#如果是一个字典:继续
#如果data中,tree的bestFeature为下标的数值大于tree的bestVal
#判断左树是否是float类型,是就返回tree的左树
#否则就从左树继续递归
#否则
#判断右树是否是float类型,是就返回tree的右树
#不是float类型就从树的右树进行递归
def TreeForecast(tree,data):
if not isinstance(tree,dict):#isinstance是判断tree是否是一个字典类型,
#print(type(tree))
#print(float(tree))
return float(tree)
if data[tree['bestFeature']]>tree['bestVal']:
if type(tree['left'])=='float':
return tree['left']
else:
return TreeForecast(tree['left'],data)
else:
if type(tree['right'])=='float':
return tree['right']
else:
return TreeForecast(tree['right'],data)
#单棵树预测测试集 调用TreeForecast 单个数据集预测样本
#创建一个n行1列的浮点型的数组
#数组里的每一行都用TreeForecast单个数据集预测,赋值给yhat相应列
def createForeCast(tree,dataSet):
n=len(dataSet)
#np.mat将数据转换成浮点型
yhat=np.mat(zeros((n,1)))#创建一个m行1列的浮点型数组
for i in range(n):
yhat[i,0]=TreeForecast(tree,dataSet[i,:])
#print(yhat[i,0])
return yhat
#随机森林预测
#遍历每棵树进行预测,取所有树预测出的数据的平均值为预测值
def Predict(Trees,dataSet):
n=len(dataSet)
yhat=np.mat(zeros((n,1))) #创造一个n行1列的初始化为0的浮点型数组
for tree in Trees: #trees里面有n棵树,用每棵树都预测一次 yhat中存储着每棵树的预测数值
yhat+=createForeCast(tree,dataSet)#createForecast返回的是一个数组
yhat/=len(Trees)#求出每个数除以树棵树的平均值
return yhat
实现逻辑:
#明天补充几张图简单讲解一下随机森林实现过程和原理吧
如果这篇文章对您有帮助,麻烦点个赞告诉我,谢谢!不胜感激~
参考文章:
https://blog.csdn.net/jiede1/article/details/78245597
https://cloud.tencent.com/developer/article/1043093
https://blog.csdn.net/zwzen1/article/details/79176038
https://book.douban.com/subject/24703171/《机器学习实战》Peter Harrington著