随机森林——回归预测股票数据的Python实例

在做项目时要用随机森林,查资料发现大多数都是用随机森林做分类,很少见到有回归的。虽然分类随机森林和回归随机森林代码实现相差不大,但是对于新手小白来说,如果有比较完整的代码直接学习可以节省很多时间,这是我写这篇文章的原因。

随机森林我就不介绍了,其他地方介绍一搜一大堆。

这篇文章关注的是如何用python实现回归随机森林。分为随机森林构建随机森林预测两部分

 

 

 

 

随机森林构建——

  • 随机森林主要的参数有树的棵树、特征的个数和树的最大深度,在mydata定义参数
  • #自定义参数
    def mydata():
        trees=10 #CART回归树的个数
        n_features=6 #特征个数
        max_depth=20 #树的最大深度
        return trees,n_features,max_depth
    

     

  • 读入数据,我用的股票数据是csv格式,将文件名和路径名分开写,方便有需要时将整个文件夹的文件逐个读出
#读入数据 这样路径和文件名分开写,方便以后将整个文件夹的数据导入进来。
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

 

 

  • 把数据集划分为训练数据和测试数据。我这里以2018年10月1日为分界线,10月1日以前为训练数据,以后为测试数据。
    
    #把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

实现逻辑:

  1. 调用loadCsvDataSet读入股票数据,通过mydata获取设定的参数(决策树的棵数,特征数和深度)。用split_train_test_data把数据得到训练数据X_train和y_train,测试数据X_test 和y_test。
  2. 使用X_train调用RandomForest创建森林。RandomForest里调用createTree创建每棵树。每棵树的创建都是先调用chooseBestSplit进行最优特征分割,然后在其左右子节点递归调用自身。
  3. 使用X_test调用Predict使用创建的森林进行预测。Predict是遍历所有CART回归树调用createForeCast,在createForecast里将X_test里的所有数据逐行调用treeForecast使用单棵树预测,将所有CART回归树预测到的数取平均数,得到最终的预测值。

 

#明天补充几张图简单讲解一下随机森林实现过程和原理吧

如果这篇文章对您有帮助,麻烦点个赞告诉我,谢谢!不胜感激~

 

参考文章:

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著

 

你可能感兴趣的:(随机森林——回归预测股票数据的Python实例)