• 机器学习实战第9章树回归


    CART(classificatiion and regression trees)分类回归树

    • CART既能用于分类,也能用于回归
    • CART是二叉树

    CART算法由决策树的生成和决策树的剪枝两步组成。

    1 CART生成

    1.1回归树

    回归树采用平方误差最小化准则,分类树采用基尼指数最小化准则,进行特征选择,生成二叉树。

         

    1.2 分类树

    分类树采用基尼指数选择最优特征,同时决定该值的最优二值切分点。

      

     

         

    2 CART剪枝

    首先从生成算法产生的决策树T0底端开始不断剪枝,直到T0的根节点,形成一个子树序列{T0,T1,…,Tn};然后通过交叉验证法在独立的验证数据集上对子树序列进行测试,从中选择最优子树

    1.剪枝,形成子树序列

    剪枝过程中,计算子树的损失函数:

        

    其中T为任意子树,|T|为树T的节点个数,参数a权衡训练数据的拟合程度与模型的复杂度。

    可以用递归的方法对树进行剪枝,将a从小增大,a0<a1<...<an<+无穷,产生一系列的区间[ai,ai+1),i =0,1,...,n;剪枝得到的子树序列对应着区间[ai,ai+1),i =0,1,...,n的最优子树序列{T0, T1, ... , Tn},序列中的子树是嵌套的。

    对T0中每一内部结点t,计算

          

    3 CART算法实现
    3.1 CART算法在回归中的应用

    3.1.1构建树

    算法:

    对每个特征:

      对特征的每个取值:

        将数据集切分成两部分

        计算切分的误差

        如果当前误差小于当前最小误差,则更新当前最小误差,并更新最佳切分属性和切分值

    返回最佳切分的特征和切分值

    import numpy as np
    from matplotlib import pyplot as plt
    
    def loadDataSet(fileName):
        dataMat = []
        fr = open(fileName)
        for line in fr.readlines():
            curLine = line.strip().split('\t')
            fltLine = map(float, curLine)   #将数据映射成浮点型,返回的是map的地址
            dataMat.append(list(fltLine))
        return dataMat
    
    
    def plotData(dataMat):
        x = dataMat[:,0].tolist()
        y = dataMat[:,1].tolist()
        plt.scatter(x,y)
        plt.title('DataSet')
        plt.xlabel('x')
        plt.ylabel('y')
        plt.show()
    
    
    def plotData2(dataMat):
        x = dataMat[:, 1].tolist()
        y = dataMat[:, 2].tolist()
        plt.scatter(x, y)
        plt.title('DataSet')
        plt.xlabel('x')
        plt.ylabel('y')
        plt.show()
    
    
    def binSplitDataSet(dataSet, feature, value):
        """
         函数说明:根据某个特征及值对数据集进行切分
        :param dataSet: 数据集
        :param feature: 特征
        :param value: 特征值
        :return: 切分后的数据
        """
        mat0 = dataSet[np.nonzero(dataSet[:,feature] > value),:][0]
        mat1 = dataSet[np.nonzero(dataSet[:,feature] <= value),:][0]
        return mat0, mat1
    
    
    """
        下面构建回归树
    """
    def regLeaf(dataSet):
        """
        函数说明:生成叶节点
        :param dataSet: 数据集
        :return: 使用均值作为叶节点的值
        """
        # print(dataSet)
        return np.mean(dataSet[:,-1])
    
    
    def regErr(dataSet):
        """
        函数说明:误差估计函数
        :param dataSet: 数据集
        :return: 总方差
        """
        return np.var(dataSet[:-1]) * np.shape(dataSet)[0]
    
    
    def chooseBestSplit(dataSet, leafType=regLeaf, errType=regErr, ops=(1,4)):
        """
        函数说明:找到数据的最佳二元切分方式函数
        :param dataSet: 数据将
        :param leafType: 生成叶节点
        :param errType: 误差估计函数
        :param ops:用户自定义参数构成的元组
        :return:
            bestIndex :最佳切分特征的下标
            bestValue: 最优切分值
        """
        """
        伪代码:
             首先判断是否所有值相等:
             否:计算误差值,初始化最佳误差,最优切分特征下标,最优切分值
                遍历每个特征:
                    遍历特征的每个值:
                        将数据切分为两部分
                        判断是否小于最少切分样本值:
                        是:跳出循环
                        否:计算切分后误差
                            如果切分后误差小于当前最佳误差,则更新最优切分特征下标,最优切分值,最优误差
                如果误差下降值小于最小误差值,则返回最佳切分特征值和最优切分值
        """
        tolS = ops[0];  tolN = ops[1]   #tolS是允许的最小误差下降值,tolN是切分的最少样本
        if len(set(dataSet[:,-1].T.tolist()[0])) == 1: #如果所有值相等则退出,根据set特性
            return None, leafType(dataSet)
        m,n = np.shape(dataSet)
        #the choice of the best feature is driven by Reduction in RSS error from mean
        S = errType(dataSet)    #计算误差值
        bestS = np.inf; bestIndex = 0; bestValue = 0
        for featIndex in range(n-1):    #遍历每个特征值
            for splitVal in set((dataSet[:,featIndex].T.tolist())[0]):  #遍历特征的每个值
                # print(featIndex, splitVal)
                mat0, mat1 = binSplitDataSet(dataSet, featIndex, splitVal)  #将数据集切分为两部分
                if (np.shape(mat0)[0] < tolN) or (np.shape(mat1)[0] < tolN): continue   #如果小于切分的最少样本数则直接跳到下一次循环
                newS = errType(mat0) + errType(mat1)    #计算新的误差
                if newS < bestS: #如果小于最佳误差则更新
                    bestIndex = featIndex
                    bestValue = splitVal
                    bestS = newS
        #如果误差下降值小于允许的最小误差下降值,则不需要切分
        if (S - bestS) < tolS:
            return None, leafType(dataSet) #exit cond 2
        #切分数据集
        mat0, mat1 = binSplitDataSet(dataSet, bestIndex, bestValue)
        #如果切分后的数据集个数小于tolN,则不进行切分
        # if (np.shape(mat0)[0] < tolN) or (np.shape(mat1)[0] < tolN):
        #     return None, leafType(dataSet)
        return bestIndex, bestValue#返回最佳切分特征的下标和最优切分值
    
    
    def createTree(dataSet, leafType = regLeaf, errType = regErr, ops=(1,4)):
        """
        函数说明:建树
        :param dataSet: 数据集
        :param leafType: 生成叶子节点函数
        :param errType: 误差函数
        :param ops: 用户自定义参数,对树进行预剪枝
        :return: 树
        """
        feat, val = chooseBestSplit(dataSet, leafType, errType, ops)
        if feat == None: return val
        retTree = {}
        retTree['spInd'] = feat
        retTree['spVal'] = val
        lSet, rSet = binSplitDataSet(dataSet, feat, val)
        retTree['left'] = createTree(lSet, leafType, errType, ops)
        retTree['right'] = createTree(rSet, leafType, errType, ops)
        return retTree

    if __name__ == '__main__':

    ex00Data = loadDataSet('txt/ex00.txt')
    ex00Mat = np.mat(ex00Data)
    plotData(ex00Mat)
    myTree1 = createTree(ex00Mat)
    print(myTree1)

    ex0Data = loadDataSet('txt/ex0.txt')
    ex0Mat = np.mat(ex0Data)
    plotData2(ex0Mat)
    myTree2 = createTree(ex0Mat)
    print(myTree2)
    print(createTree(ex0Mat, ops=(0,1)))  #tolS为0,tolN为1

    生成结果如下:  

         

           

     3.1.2 树剪枝

     为了防止过拟合,需要对树进行剪枝

    (1)预剪枝

    if __name__ == '__main__':
        ex2Data = loadDataSet('txt/ex2.txt')
        ex2Mat = np.mat(ex2Data)
        plotData(ex2Mat)
        ex2Tree = createTree(ex2Mat)
        print(ex2Tree)   #非常多的叶子节点
        print(createTree(ex2Mat,ops=(10000,4))) #只有两个叶子节点,tolS对误差的数据集非常敏感

    在生成树的过程中进行剪枝,如前面设置的最低下降误差值tolS和最小节点数tolN

    使用ex2.txt来构建树,ex2.txt的数量级是ex0.txt的100倍

    可以看出停止条件tolS对误差的数量级十分敏感。

     (2)后剪枝

     使用后剪枝需要将数据集分成测试集和训练集。

    剪枝函数的伪代码:

    代码如下:

    import numpy as np
    from matplotlib import pyplot as plt
    
    def loadDataSet(fileName):
        dataMat = []
        fr = open(fileName)
        for line in fr.readlines():
            curLine = line.strip().split('\t')
            fltLine = map(float, curLine)   #将数据映射成浮点型,返回的是map的地址
            dataMat.append(list(fltLine))
        return dataMat
    
    
    def plotData(dataMat):
        x = dataMat[:,0].tolist()
        y = dataMat[:,1].tolist()
        plt.scatter(x,y)
        plt.title('DataSet')
        plt.xlabel('x')
        plt.ylabel('y')
        plt.show()
    
    
    def plotData2(dataMat):
        x = dataMat[:, 1].tolist()
        y = dataMat[:, 2].tolist()
        plt.scatter(x, y)
        plt.title('DataSet')
        plt.xlabel('x')
        plt.ylabel('y')
        plt.show()
    
    
    def binSplitDataSet(dataSet, feature, value):
        """
         函数说明:根据某个特征及值对数据集进行切分
        :param dataSet: 数据集
        :param feature: 特征
        :param value: 特征值
        :return: 切分后的数据
        """
        mat0 = dataSet[np.nonzero(dataSet[:,feature] > value),:][0]
        mat1 = dataSet[np.nonzero(dataSet[:,feature] <= value),:][0]
        return mat0, mat1
    
    
    """
        下面构建回归树
    """
    def regLeaf(dataSet):
        """
        函数说明:生成叶节点
        :param dataSet: 数据集
        :return: 使用均值作为叶节点的值
        """
        # print(dataSet)
        return np.mean(dataSet[:,-1])
    
    
    def regErr(dataSet):
        """
        函数说明:误差估计函数
        :param dataSet: 数据集
        :return: 总方差
        """
        return np.var(dataSet[:-1]) * np.shape(dataSet)[0]
    
    
    def chooseBestSplit(dataSet, leafType=regLeaf, errType=regErr, ops=(1,4)):
        """
        函数说明:找到数据的最佳二元切分方式函数
        :param dataSet: 数据将
        :param leafType: 生成叶节点
        :param errType: 误差估计函数
        :param ops:用户自定义参数构成的元组
        :return:
            bestIndex :最佳切分特征的下标
            bestValue: 最优切分值
        """
        """
        伪代码:
             首先判断是否所有值相等:
             否:计算误差值,初始化最佳误差,最优切分特征下标,最优切分值
                遍历每个特征:
                    遍历特征的每个值:
                        将数据切分为两部分
                        判断是否小于最少切分样本值:
                        是:跳出循环
                        否:计算切分后误差
                            如果切分后误差小于当前最佳误差,则更新最优切分特征下标,最优切分值,最优误差
                如果误差下降值小于最小误差值,则返回最佳切分特征值和最优切分值
        """
        tolS = ops[0];  tolN = ops[1]   #tolS是允许的最小误差下降值,tolN是切分的最少样本
        if len(set(dataSet[:,-1].T.tolist()[0])) == 1: #如果所有值相等则退出,根据set特性
            return None, leafType(dataSet)
        m,n = np.shape(dataSet)
        #the choice of the best feature is driven by Reduction in RSS error from mean
        S = errType(dataSet)    #计算误差值
        bestS = np.inf; bestIndex = 0; bestValue = 0
        for featIndex in range(n-1):    #遍历每个特征值
            for splitVal in set((dataSet[:,featIndex].T.tolist())[0]):  #遍历特征的每个值
                # print(featIndex, splitVal)
                mat0, mat1 = binSplitDataSet(dataSet, featIndex, splitVal)  #将数据集切分为两部分
                if (np.shape(mat0)[0] < tolN) or (np.shape(mat1)[0] < tolN): continue   #如果小于切分的最少样本数则直接跳到下一次循环
                newS = errType(mat0) + errType(mat1)    #计算新的误差
                if newS < bestS: #如果小于最佳误差则更新
                    bestIndex = featIndex
                    bestValue = splitVal
                    bestS = newS
        #如果误差下降值小于允许的最小误差下降值,则不需要切分
        if (S - bestS) < tolS:
            return None, leafType(dataSet) #exit cond 2
        #切分数据集
        mat0, mat1 = binSplitDataSet(dataSet, bestIndex, bestValue)
        #如果切分后的数据集个数小于tolN,则不进行切分
        # if (np.shape(mat0)[0] < tolN) or (np.shape(mat1)[0] < tolN):
        #     return None, leafType(dataSet)
        return bestIndex, bestValue#返回最佳切分特征的下标和最优切分值
    
    
    def createTree(dataSet, leafType = regLeaf, errType = regErr, ops=(1,4)):
        """
        函数说明:建树
        :param dataSet: 数据集
        :param leafType: 生成叶子节点函数
        :param errType: 误差函数
        :param ops: 用户自定义参数,对树进行预剪枝
        :return: 树
        """
        feat, val = chooseBestSplit(dataSet, leafType, errType, ops)
        if feat == None: return val
        retTree = {}
        retTree['spInd'] = feat
        retTree['spVal'] = val
        lSet, rSet = binSplitDataSet(dataSet, feat, val)
        retTree['left'] = createTree(lSet, leafType, errType, ops)
        retTree['right'] = createTree(rSet, leafType, errType, ops)
        return retTree
    
    
    def isTree(obj):
        """
        函数说明:判断是否是一棵树
        :param obj:
        :return:
        """
        return (type(obj).__name__=='dict')
    
    
    def getMean(tree):
        """
        函数说明:递归函数,对树进行塌陷处理(返回树平均值)
        :param tree: 树
        :return: 树的左右子树的均值
        """
        if isTree(tree['left']): tree['left'] = getMean(tree['left'])
        if isTree(tree['right']): tree['right'] = getMean(tree['right'])
        return (tree['left'] + tree['right']) / 2.0
    
    
    def prnue(tree, testData):
        """
        函数说明:后剪枝函数,使用测试数据对树进行剪枝
        :param tree:  待剪枝的树
        :param testData:   测试数据
        :return: 剪枝后的树
        """
        """
            树的后剪枝:
            伪代码:
                基于已有的树切分测试数据:
                    如果存在任一子集是一棵树,则在该子集递归剪枝过程
                    计算将当前两个叶节点合并后的误差
                    计算没有合并时的误差
                    如果合并可以降低误差则进行合并
        """
        #如果测试数据集为空,进行塌陷处理
        if(np.shape(testData[0]) == 0): return getMean(tree)
        # if isTree(tree['left']) and isTree(tree['right']):
        lSet, rSet = binSplitDataSet(testData, tree['spInd'], tree['spVal'])
        if isTree(tree['left']): tree['left'] = prnue(tree['left'], lSet)  #左子集不是单个节点,则对左子树进行剪枝
        if isTree(tree['right']): tree['right'] = prnue(tree['right'], rSet) #右子集不是单个节点,则对右子树进行剪枝
        if not isTree(tree['left']) and not isTree(tree['right']):  #左右子集都是单个节点
            errNoMerge = sum(np.power((lSet[:,-1] - tree['left']),2)) + sum(np.power((rSet[:,-1] - tree['right']),2)) #未合并的误差
            treeMean = getMean(tree)
            errMerge = sum(np.power(testData[:,-1] - treeMean, 2))   #合并后误差
            print(errNoMerge, errMerge)
            if errMerge < errNoMerge:   #如果合并后误差小于合并前误差则合并
                print("merging")
                return treeMean
            else: return tree
        else: return tree


    if __name__ == '__main__':
    ex2Data = loadDataSet('txt/ex2.txt')
    ex2Mat = np.mat(ex2Data)
    plotData(ex2Mat)
    ex2Tree = createTree(ex2Mat)
    print(ex2Tree)

    ex2TestData = loadDataSet('txt/ex2test.txt')
    prnueTree = prnue(ex2Tree, np.mat(ex2TestData))  #对ex2Tree进行剪枝
    print(prnueTree)

     3.2 模型树

    模型树的节点是线性回归函数

    模型树的代码:

    def loadDataSet(fileName):
        dataMat = []
        fr = open(fileName)
        for line in fr.readlines():
            curLine = line.strip().split('\t')
            fltLine = map(float, curLine)   #将数据映射成浮点型,返回的是map的地址
            dataMat.append(list(fltLine))
        return dataMat
    
    def binSplitDataSet(dataSet, feature, value):
        """
         函数说明:根据某个特征及值对数据集进行切分
        :param dataSet: 数据集
        :param feature: 特征
        :param value: 特征值
        :return: 切分后的数据
        """
        mat0 = dataSet[np.nonzero(dataSet[:,feature] > value),:][0]
        mat1 = dataSet[np.nonzero(dataSet[:,feature] <= value),:][0]
        return mat0, mat1
    
    
    def linearSolve(dataSet):
        """
        函数说明:生成数据集的线性模型
        :param dataSet: 数据集
        :return: 系数,X,Y
        """
        m, n = np.shape(dataSet)
        X = np.mat(np.ones((m, n))); Y = np.mat(np.zeros((m, 1)))
        X[:,1:n] = dataSet[:,0:n-1]
        Y = dataSet[:,-1]
        xTx = X.T * X
        # linalg.det()计算行列式,若为0,则不可逆
        if np.linalg.det(xTx) == 0.0:
            print("This matrix is singular, cannot do inverse")
            return
        # 回归系数ws = (X^TX)^-1X^Ty
        ws = xTx.I * (X.T * Y)
        return ws, X, Y
    
    
    def modelLeaf(dataSet):
        """
        函数说明:线性模型树的叶节点生成函数
        :param dataSet:
        :return:
        """
        ws, X, Y = linearSolve(dataSet)
        return ws
    
    
    def modelErr(dataSet):
        """
        函数说明:线性模型误差计算函数
        :param dataSet: 数据集
        :return: 误差
        """
        ws, X, Y = linearSolve(dataSet)
        yHat = X * ws
        return sum(np.power((Y - yHat), 2))
    
    def chooseBestSplit(dataSet, leafType=regLeaf, errType=regErr, ops=(1,4)):
        """
        函数说明:找到数据的最佳二元切分方式函数
        :param dataSet: 数据将
        :param leafType: 生成叶节点
        :param errType: 误差估计函数
        :param ops:用户自定义参数构成的元组
        :return:
            bestIndex :最佳切分特征的下标
            bestValue: 最优切分值
        """
        """
        伪代码:
             首先判断是否所有值相等:
             否:计算误差值,初始化最佳误差,最优切分特征下标,最优切分值
                遍历每个特征:
                    遍历特征的每个值:
                        将数据切分为两部分
                        判断是否小于最少切分样本值:
                        是:跳出循环
                        否:计算切分后误差
                            如果切分后误差小于当前最佳误差,则更新最优切分特征下标,最优切分值,最优误差
                如果误差下降值小于最小误差值,则返回最佳切分特征值和最优切分值
        """
        tolS = ops[0];  tolN = ops[1]   #tolS是允许的最小误差下降值,tolN是切分的最少样本
        if len(set(dataSet[:,-1].T.tolist()[0])) == 1: #如果所有值相等则退出,根据set特性
            return None, leafType(dataSet)
        m,n = np.shape(dataSet)
        #the choice of the best feature is driven by Reduction in RSS error from mean
        S = errType(dataSet)    #计算误差值
        bestS = np.inf; bestIndex = 0; bestValue = 0
        for featIndex in range(n-1):    #遍历每个特征值
            for splitVal in set((dataSet[:,featIndex].T.tolist())[0]):  #遍历特征的每个值
                # print(featIndex, splitVal)
                mat0, mat1 = binSplitDataSet(dataSet, featIndex, splitVal)  #将数据集切分为两部分
                if (np.shape(mat0)[0] < tolN) or (np.shape(mat1)[0] < tolN): continue   #如果小于切分的最少样本数则直接跳到下一次循环
                newS = errType(mat0) + errType(mat1)    #计算新的误差
                if newS < bestS: #如果小于最佳误差则更新
                    bestIndex = featIndex
                    bestValue = splitVal
                    bestS = newS
        #如果误差下降值小于允许的最小误差下降值,则不需要切分
        if (S - bestS) < tolS:
            return None, leafType(dataSet) #exit cond 2
        #切分数据集
        mat0, mat1 = binSplitDataSet(dataSet, bestIndex, bestValue)
        #如果切分后的数据集个数小于tolN,则不进行切分
        # if (np.shape(mat0)[0] < tolN) or (np.shape(mat1)[0] < tolN):
        #     return None, leafType(dataSet)
        return bestIndex, bestValue#返回最佳切分特征的下标和最优切分值
    
      
     def createTree(dataSet, leafType = regLeaf, errType = regErr, ops=(1,4)):
    """
    函数说明:建树
    :param dataSet: 数据集
    :param leafType: 生成叶子节点函数
    :param errType: 误差函数
    :param ops: 用户自定义参数,对树进行预剪枝
    :return:
    """
    feat, val = chooseBestSplit(dataSet, leafType, errType, ops)
    if feat == None: return val
    retTree = {}
    retTree['spInd'] = feat
    retTree['spVal'] = val
    lSet, rSet = binSplitDataSet(dataSet, feat, val)
    retTree['left'] = createTree(lSet, leafType, errType, ops)
    retTree['right'] = createTree(rSet, leafType, errType, ops)
    return retTree
    if __name__ == '__main__':
    exp2Data = loadDataSet('txt/exp2.txt')
    exp2Mat = np.mat(exp2Data)
    exp2Tree = createTree(exp2Mat, modelLeaf, modelErr, (1,10)) #模型树
     print(exp2Tree)

    3.3 进行预测——简单线性回归 回归树 模型树的对比

    使用决定系数R^2值来判断预测效果,越接近于1越好

    #!/usr/bin/env python
    # encoding: utf-8
    '''
    @author: shuhan Wei 
    @software: pycharm
    @file: treeFore.py
    @time: 18-9-13 下午6:33
    @desc:树回归预测
    '''
    import regTrees
    import numpy as np
    
    
    def regTreeEval(model, inDat):
        """
        函数说明:回归树的单个节点预测值
        :param model: 某一节点的值
        :param inDat: 空值
        :return: 预测的浮点数
        """
        return float(model)
    
    
    def modelTreeEval(model, inDat):
        """
        函数说明:模型树的预测值
        :param model: 预测节点的回归系数
        :param inDat: 某个测试数据
        :return: 预测值
        """
        n = np.shape(inDat)[1]
        X = np.mat(np.ones((1, n + 1)))
        X[:, 1:n + 1] = inDat
        return float(X * model)
    
    
    def treeForeCast(tree, inData, modelEval=regTreeEval):
        if not regTrees.isTree(tree): return modelEval(tree, inData)
        if inData[tree['spInd'],0] > tree['spVal']:
            if regTrees.isTree(tree['left']):
                return treeForeCast(tree['left'], inData, modelEval)
            else:
                return modelEval(tree['left'], inData)
        else:
            if regTrees.isTree(tree['right']):
                return treeForeCast(tree['right'], inData, modelEval)
            else:
                return modelEval(tree['right'], inData)
    
    
    def createForeCast(tree, testData, modelEval=regTreeEval):
        m = len(testData)
        yHat = np.mat(np.zeros((m, 1)))
        for i in range(m):
            yHat[i, 0] = treeForeCast(tree, np.mat(testData[i]), modelEval)
        return yHat
    
    
    if __name__ == '__main__':
        trainMat = np.mat(regTrees.loadDataSet('txt/bikeSpeedVsIq_train.txt'))
        testMat = np.mat(regTrees.loadDataSet('txt/bikeSpeedVsIq_test.txt'))
        regTrees.plotData(trainMat)
        # 使用回归树模型进行预测
        regTree = regTrees.createTree(trainMat, ops=(1,20))
        yHat = createForeCast(regTree, testMat, regTreeEval)
        #计算R^2值,越接近于1越好
        cor1 = np.corrcoef(yHat, testMat[:, 1], rowvar=0)[0,1]
        print(cor1)
    
        #使用模型树进行预测
        modelTree = regTrees.createTree(trainMat, regTrees.modelLeaf, regTrees.modelErr, (1,20))
        yHat = createForeCast(modelTree, testMat[:, 0], modelTreeEval)
        col2 = np.corrcoef(yHat, testMat[:, 1], rowvar=0)[0, 1]
        print(col2)

      #使用简单线性模型
      ws, X, Y = regTrees.linearSolve(trainMat)
      for i in range(np.shape(testMat)[0]):
      yHat[i] = testMat[i, 0] * ws[1, 0] + ws[0, 0]
      col3 = np.corrcoef(yHat, testMat[:, 1], rowvar=0)[0, 1]
      print(col3)

        

          

        可以看到数据集的分布像两段线性函数,从R^2值可以看出模型树的预测效果最好。

  • 相关阅读:
    中文转码问题总结
    Linux命令总结
    Maven实战系列文章目录
    JXL API总结
    docker 中安装mysql8之后无法远程连接的问题caching-sha2-password
    springboot查数据并以csv格式现在到本地
    aop
    java.lang.ClassNotFoundException: org.aspectj.lang.JoinPoint
    shiro框架中获取username、ip等信息
    cron
  • 原文地址:https://www.cnblogs.com/weiququ/p/9643198.html
Copyright © 2020-2023  润新知