《机器学习实战》9.树回归

news2024/9/23 13:29:12

目录

树回归

1 复杂数据的局部性建模

2 连续和离散型特征的树的构建

3 将CART算法用于回归

3.1 构建树

3.2 运行代码

4 树剪枝

4.1 预剪枝

4.2 后剪枝

5 模型树

6 示例:树回归与标准回归的比较

7 使用python的Tkinter库创建GUI

7.1 用Tkinter创建GUI

7.2 集成Matplotlib和tkinter

8 本章小结


本章涉及相关代码和数据

树回归

本章内容:

①CART算法

②回归与模型树

③树剪枝算法

④Python中GUI的使用

之前学习的线性回归很强大,但是这些方法创建的模型需要拟合所有的样本点。当数据众多特征并且特征之间的关系十分复杂时,构建全局模型的想法就比较困难,也略显笨拙。

一种可行的方法是将数据集切分成很多份易建模的数据,然后再进行线性回归,如果首次切分后仍然难以拟合线性模型就继续切分。在这种切分方式下,树结构和回归法就相当有用。

这里介绍一个新的叫做CART的树构建算法。该算法既可以分类又可以用于回归。

1 复杂数据的局部性建模

决策树是一种贪心算法,他要在给定书简被做出最佳选择,但并不关心是否能够达到全局最优

优点:可以对复杂和非线性的数据建模

缺点:结果不易理解

使用数据类型:数值型和标称型数据

之前学的树构建算法时ID3,他每次选取当前最佳的特征来分割数据,并按照该特征的所有特征值取值来切分。一旦按照某特征切分之后,该特征在之后的算法执行过程中将不再起作用,所以有观点认为这种切分方式过于迅速。

另一种方法时二元切分法,即每次把数据集切分为两份,如果数据的某特征值等于切分所要求的值,那么这些数据就进入树的左子树,反之则进入树的右子树,除了切分过于迅速之外,ID3算法还存在另一个问题,他不能直接处理连续性特征,只有事先将连续性数据转化为离散型,才可以使用,但这种转换会破坏连续型变量的内在性质。

使用二元切分法则易于对树构建过程进行调整已处理连续性数据。具体的处理方法时:1如果特征值大于给定值就走左子树,反之就走右子树。

树回归的一般方法:

①收集数据:采用任意方法收集数据

②准备数据:需要数值型数据,标称数据应该映射成二值型数据

③分析数据:会出数据的二维可视化显示结果,以字典的方法生成树

④训练算法:大部分书简都花费在u而节点树模型的构建上

⑤测试算法:使用测试数据上的R2值来分析模型的效果

⑥使用算法:使用训练出的树做预测,预测结果还可以用来做很多事情。

2 连续和离散型特征的树的构建

使用一个字典来存储树的数据结构特征,该字典将包含一下4个元素:

①待切分的特征,

②待切分的特征值,

③右子树:当不再需要切分的时候,也可以是单个值,

④左子树:与右子树类似

creatTree()的伪代码大致如下:

找到最佳的切分特征:

    如果该节点不能再分,将该节点存为叶节点

    执行二元切分

    在右子树调用createTree()方法

    在左子树调用createTree()方法

from numpy import *
# 回归树的切分函数
def regLeaf(dataSet):# 生成叶节点,因为在cart中就是求目标均值
    # print(dataSet)
    # print(dataSet[:,-1])
    # return mean(list(dataSet[:,-1]))
    return mean(dataSet[:,-1])

# 在给定数据上计算目标变量的平均误差
def regErr(dataSet): # 
    return var(dataSet[:,-1]) * shape(dataSet)[0]

# 加载数据
def loadDataSet(fileName):
    # print(fileName)
    dataMat=[]
    fr=open(fileName)
    for line in fr.readlines():
        curLine=line.strip().split('\t')
        # print(curLine)
        # 将每行映射为浮点数
        fltLine=list(map(float,curLine))
        # print(fltLine)
        dataMat.append(fltLine)
    return dataMat


# 该函数将数据切分为两个子集并返回(二元切分法)
         #   数据集合、待切分的特征、特征的某个值
def binSplitDataSet(dataSet,feature,value):

    # nonzero函数用于得到数组array中非零元素的位置的函数
    # 原书的代码,但运行出来有一点错误
    # mat0=dataSet[nonzero(dataSet[:,feature]>value)[0],:][0]
    # mat1=dataSet[nonzero(dataSet[:,feature]<=value)[0],:][0]

    mat0=dataSet[nonzero(dataSet[:,feature]>value)[0],:]
    mat1=dataSet[nonzero(dataSet[:,feature]<=value)[0],:]
    # print(mat1)
    # print(mat0)
    return mat0,mat1

# 用最佳的方式切分数据集
def chooseBestSplit(dataSet, leafType=regLeaf, errType=regErr, ops=(1, 4)):
    """chooseBestSplit(用最佳方式切分数据集 和 生成相应的叶节点)

    Args:
        dataSet   加载的原始数据集
        leafType  建立叶子点的函数
        errType   误差计算函数(求总方差)
        ops       [容许误差下降值,切分的最少样本数]。
    Returns:
        bestIndex feature的index坐标
        bestValue 切分的最优值
    Raises:
    """
    # ops=(1,4),非常重要,因为它决定了决策树划分停止的threshold值,被称为预剪枝(prepruning),其实也就是用于控制函数的停止时机。
    # 之所以这样说,是因为它防止决策树的过拟合,所以当误差的下降值小于tolS,或划分后的集合size小于tolN时,选择停止继续划分。
    # 最小误差下降值,划分后的误差减小小于这个差值,就不用继续划分
    tolS = ops[0]
    # 划分最小 size 小于,就不继续划分了
    tolN = ops[1]
    # 如果结果集(最后一列为1个变量),就返回退出
    # .T 对数据集进行转置
    # .tolist()[0] 转化为数组并取第0列
    if len(set(dataSet[:, -1].T.tolist()[0])) == 1: # 如果集合size为1,不用继续划分。
        #  exit cond 1
        return None, leafType(dataSet)
    # 计算行列值
    m, n = shape(dataSet)
    # 无分类误差的总方差和
    # the choice of the best feature is driven by Reduction in RSS error from mean
    S = errType(dataSet)
    # inf 正无穷大
    bestS, bestIndex, bestValue = inf, 0, 0
    # 循环处理每一列对应的feature值
    for featIndex in range(n-1): # 对于每个特征
        # [0]表示这一列的[所有行],不要[0]就是一个array[[所有行]]
        for splitVal in set(dataSet[:, featIndex].T.tolist()[0]):
            # 对该列进行分组,然后组内的成员的val值进行 二元切分
            mat0, mat1 = binSplitDataSet(dataSet, featIndex, splitVal)
            # 判断二元切分的方式的元素数量是否符合预期
            if (shape(mat0)[0] < tolN) or (shape(mat1)[0] < tolN):
                continue
            newS = errType(mat0) + errType(mat1)
            # 如果二元切分,算出来的误差在可接受范围内,那么就记录切分点,并记录最小误差
            # 如果划分后误差小于 bestS,则说明找到了新的bestS
            if newS < bestS:
                bestIndex = featIndex
                bestValue = splitVal
                bestS = newS
    # 判断二元切分的方式的元素误差是否符合预期
    # if the decrease (S-bestS) is less than a threshold don't do the split
    if (S - bestS) < tolS:
        return None, leafType(dataSet)
    mat0, mat1 = binSplitDataSet(dataSet, bestIndex, bestValue)
    # 对整体的成员进行判断,是否符合预期
    # 如果集合的 size 小于 tolN 
    if (shape(mat0)[0] < tolN) or (shape(mat1)[0] < tolN): # 当最佳划分后,集合过小,也不划分,产生叶节点
        return None, leafType(dataSet)
    return bestIndex, bestValue

        #    数据集
def createTree(dataSet,leafType=regLeaf,errType=regErr,ops=(1,4)):
    # 切分数据集
    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

检查一下相关函数的运行结果

# 创建一个简单的矩阵
testMat=mat(eye(4))
testMat
# 测试函数
mat0,mat1=binSplitDataSet(testMat,1,0.5)
# print(mat0,mat1)
mat1

运行结果为:

3 将CART算法用于回归

为了成功构建以分段常数为叶节点的树,需要度量出数据的一致性。

误差计算准则:

首先计算所有数据的均值,然后计算每条数据的值到均值的差值。为了对正负差同等看待,一般使用绝对值或者平方值来代替上述差值,这里需要计算平方误差的总值(总方差),总方差可以通过均方差乘以数据集中样本点的个数来得到。

3.1 构建树

上述代码还缺少一个ChooseBestSplit()函数:用最佳切分方式切分数据集和生成相应的叶节点

伪代码:

对每个特征:

    对每个特征值

        将数据切分成两份

        计算切分的误差

        如果当前误差小于当前最小误差,那么当前切分设定为最佳切分并更新最小误差

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

上一节的函数调用了这里的代码,为了便于运行,该处的相关代码在上面代码段中体现。

3.2 运行代码

查看数据集中的数据分布

def plotDatalwlr(myMat):
    import matplotlib.pyplot as plt
    myMat=array(myMat)
    fig=plt.figure()
    ax=fig.add_subplot(111)
    # ax.plot(xSort[:,1],yHat[srtInd])
    ax.scatter(myMat[:,-2],myMat[:,-1],s=2,c='red')
    plt.show()

myDat=loadDataSet('ex00.txt')
# print(myDat)

myMat=mat(myDat)
plotDatalwlr(myMat)
# myMat
createTree(myMat)

 得到的数据中点的分布以及建成的树如下:

 换另一种数据进行结果测试:

myDat1=loadDataSet('ex0.txt')
# myDat
myMat1=mat(myDat1)
plotDatalwlr(myMat1)
# myMat
createTree(myMat1)

得到的结果为:

到现在为止,已经完成回归树的构建,但是需要某种措施来检查构建过程是否得当。

下面将介绍树剪枝技术,它通过对决策树剪枝来达到更好的预测效果

4 树剪枝

一些树如果节点过多,表明该模型可能对数据进行了“过拟合”。

通过降低决策树的复杂度来避免过拟合的过程称为剪枝。

在函数ChooseBestSplit()中的提前终止条件,实际上是在进行一种所谓的预剪枝操作。

另一种形式的剪枝需要使用测试集和训练集,称为后剪枝

4.1 预剪枝

上面两个简单实验的结果还是令人满意的,但背后存在一些问题。树构建算法其实对输入的参数tolS和tolN非常敏感,如果使用其他值将不太容易达到这么好的效果。

createTree(myMat,ops=(0,1))

得到的输出结果为:

与上面只包含两个节点的树相比,这里构建的树过于臃肿,她甚至为数据集中的每个样本都分配了一个叶节点

下面数据集是上面数据集的100倍,用该数据来构建一颗新的树

myDat2=loadDataSet('ex2.txt')
myMat2=mat(myDat2)
plotDatalwlr(myMat2)
createTree(myMat2)

得到的输出结果为:

 第一个数据ex00.txt构建出来的树只有两个节点,但是这里构建的树则有很多叶节点,产生这个现象的原因在于,通停止条件tols对误差的数量级十分敏感。如果在选项中花费时间对上述误差容忍度取平均值,或许能够的都更好的结果。

createTree(myMat2,ops=(10000,4))

得到的输出结果为:

通过不断修改停止条件来得到合理结果并不是很好的办法,因为我们常常不确定到底要什么样的结果。

因此因为不需要用户指定参数,后剪枝是一种更加理想的剪枝方法。

4.2 后剪枝

使用后剪枝方法需要将数据集分成测试集和训练集。首先指定参数,是的构建的树足够大、足够复杂,便于剪枝。接下来从上而下找到叶节点,用测试集来判断将这些叶节点合并是否能够降低测试误差。如果是的话就合并。

伪代码如下:

基于已有的树切分测试数据:

    如果存在任一子集是一棵树,则在该子集递归剪枝过程

    计算将当前两个叶节点合并后的误差

    计算不合并的误差

    如果合并会降低误差的话,就将叶节点合并

 

# 回归树剪枝函数
# 测试输入变量是否为一棵树
def isTree(obj):
    # 判断该字段是否存在,返回bool类型的结果
    return (type(obj).__name__=='dict')


def getMean(tree):
    if isTree(tree['right']):
        tree['right']=getMean(tree['right'])
    if isTree(tree['left']):
        tree['left']=getMean(tree['left'])
    # 如果找到叶子节点就计算他们的平均值
    return (tree['left']+tree['right'])/2.0

# 待剪枝的树 剪枝所需要的测试数据的平均值
def prune(tree,testData):
    # 确认测试集是否为空
    if shape(testData)[0]==0:
        return getMean(tree)
    if(isTree(tree['right'])or isTree(tree['left'])):
        lSet,rSet=binSplitDataSet(testData,tree['spInd'],tree['spVal'])
    if isTree(tree['left']):
        tree['left']=prune(tree['left'],lSet)
    if isTree(tree['right']):
        tree['right']=prune(tree['right'],rSet)
    if not isTree(tree['left']) and not isTree(tree['right']):
        lSet,rSet=binSplitDataSet(testData,tree['spInd'],tree['spVal'])
        errorNoMerge=sum(power(lSet[:,-1]-tree['left'],2))+sum(power(rSet[:,-1]-tree['right'],2))
        treeMean=(tree['left']+tree['right'])/2.0
        errorMerge=sum(power(testData[:,-1]-treeMean,2))
        if errorMerge<errorNoMerge:
            print("merging")
            return treeMean
        else:
            return tree
    else:
        return tree

测试后剪枝的效果:

myTree=createTree(myMat2,ops=(0,1))
myDatTest=loadDataSet('ex2test.txt')
myMat2Test=mat(myDatTest)
prune(myTree,myMat2Test)

得到的输出结果为:

可以看到,大量的节点已经被剪枝掉了,但没有向预期那样简直成两部分,这说明后剪枝可能不如预剪枝有效。一般的,为了寻求最佳模型可以同时采用两追踪剪枝技术。

下面将重用部分已有的树构建代码来创建一种新的树。概述仍采用二元切分,但叶节点不再是简单的数值,取而代之的是一些线性模型。

5 模型树

用树来对数据建模,除了把叶节点简单的设定为常数值之瓦埃,还有一种方法是把叶节点设定为分段线性函数,这里所谓的分段线性是指模型由多个线性片段组成。

# 利用树的叶节点生成函数

# 将数据格式化成目标变量Y和自变量X,X和Y用于执行简单的线性回归
def linearSolve(dataSet):
    m,n=shape(dataSet)
    X=mat(ones((m,n)))
    Y=mat(ones((m,1)))
    X[:,1:n]=dataSet[:,0:n-1]
    Y=dataSet[:,-1]
    xTx=X.T*X
    if linalg.det(xTx)==0.0:
        raise NameError('This matrix is singular,cannot do inverse,\n try increasing the seccong value of ops')
    ws=xTx.I*(X.T*Y)
    return ws,X,Y

# 当数据不再需要切分的时候她负责生成叶节点的模型
def modelLeaf(dataSet):
    ws,X,Y=linearSolve(dataSet)
    return ws

# 在给定数据集上计算误差
def modelErr(dataSet):
    ws,X,Y=linearSolve(dataSet)
    yHat=X*ws
    return sum(power(Y-yHat,2))

查看数据分布

myMat2=mat(loadDataSet('exp2.txt'))
# print(myMat2)
plotDatalwlr(myMat2)

得到的数据分布为:

创建树:

createTree(myMat2,modelLeaf,modelErr,(1,10))

得到的模型树的结果为:

可以看到该代码以0.285477为界创建了两个模型。与实际数据非常数据接近。

模型树、回归树等比较哪个模型更好,一个比较客观的方法是计算相关系数R方,该系数可以通过调用命令corrcoef(yHat,y,rowvar=0)来求解

6 示例:树回归与标准回归的比较

 

# 用树回归进行预测的代码

# 对回归树叶节点进行预测
def regTreeEval(model,inDat):
    return float(model)

# 对回归树树节点进行预测
def modelTreeEval(model,inDat):
    n=shape(inDat)[1]
    X=mat(ones((1,n+1)))
    X[:,1:n+1]=inDat
    return float(X*model)

# 返回一个浮点数,自顶向下遍历整棵树,直到命中叶节点为止
# 在给定树结构的情况下,对于单个数据点,该函数会给出一个预测值
def treeForeCast(tree,inData,modelEval=regTreeEval):
    # 如果不是树,返回浮点值
    if not isTree(tree):
        return modelEval(tree,inData)
    if inData[tree['spInd']]>tree['spVal']:
        if isTree(tree['left']):
            return treeForeCast(tree['left'],inData,modelEval)
        else:
            return modelEval(tree['left'],inData)
    else:
        if 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=mat(zeros((m,1)))
    for i in range(m):
        # 对每个节点进行预测
        yHat[i,0]=treeForeCast(tree,mat(testData[i]),modelEval)
    return yHat

先查看数据的分布:

# 导入训练集与测试集,查看数据的分布
trainMat=mat(loadDataSet('bikeSpeedVsIq_train.txt'))
testMat=mat(loadDataSet('bikeSpeedVsIq_test.txt'))
plotDatalwlr(trainMat)
plotDatalwlr(testMat)

得到的输出图像为:

 

# 标准回归
myTree=createTree(trainMat,ops=(1,20))
yHat=createForeCast(myTree,testMat[:,0])
corrcoef(yHat,testMat[:,1],rowvar=0)[0,1]

# 同样的在创建一棵树回归
myTree=createTree(trainMat,modelLeaf,modelErr,(1,20))
yHat=createForeCast(myTree,testMat[:,0],modelTreeEval)
corrcoef(yHat,testMat[:,1],rowvar=0)[0,1]

得到的输出结果为:

我们知道R方越接近1越好,所以从上面的结果可以看出,这里模型树的结果比回归树好

为了得到测试集上的所有yHat预测值,在测试数据上循环执行

我们尝试一下单纯的线性回归

# 进行单纯的线性回归
ws,X,Y=linearSolve(trainMat)
for i in range(shape(testMat)[0]):
    yHat[i]=testMat[i,0]*ws[1,0]+ws[0,0]

corrcoef(yHat,testMat[:,1],rowvar=0)[0,1]

 得到的输出结果为:

可以看到,该方法在R方值的表现上不如上面那两种树回归的方法。因此,树回归方法在预测复杂数据上时回避简单的线性模型更有效。

下面使用python提供的框架来构建图像用户界面(GUI)

7 使用python的Tkinter库创建GUI

机器学习给我们提供了一些强大的工具,能从未知数据中抽取出有用的信息。因此,能否将这些信息以易于人们理解的方式呈现十分重要。再者,加入人们可以直接与算法和数据进行交互,将可以比较轻松的进行解译。如果仅仅知识绘制出一幅静态图像,或者知识在python命令行中输出一些数字,那么对结果做分析和交流非常困难。能过能够让用户不需要任何指令就可以按照他们自己的方式来分析数据,就不需要对数据做过多的解释。其中一个能同时支持数据呈现和用户交互的方式就是构建一个图形用户界面GUI

示例:利用GUI对回归树进行调优

①收集数据:所提供的文本文件

②准备数据:用python解析上述文件,得到数值型数据

③分析数据:利用Tkinter构建一个GUI来展示模型和数据

④训练算法:训练一棵回归树和一颗模型树,并与数据一起展示出来

⑤测试算法:这里不需要测试过程

⑥使用算法:GUI使得人们可以在预剪枝时测试不同参数的影响,还可以帮助我们选择模型的类型

7.1 用Tkinter创建GUI

python有很多GUI框架,其中一个易于使用的Tkinter,是随python的标准编译版本发布的。Tkinter可以在多平台上运行,下面从一个简单的例子开始

from tkinter import *
root=Tk()
myLabel=Label(root,text="helo world")
myLabel.grid()
# 启动事件循环,使得该窗口可以响应鼠标点击、按键和重绘等操作
root.mainloop()

 运行得到:

 

# 用于构建树管理器界面的tkinter小部件
def reDraw(tolS,tolN):
    pass

def drawNewTree():
    pass

root=Tk()

# grid()函数设定行和列的位置
Label(root,text='plot place holder').grid(row=0,columnspan=3)

Label(root,text='tolN').grid(row=1,column=0)
tolNentry=Entry(root)
tolNentry.grid(row=1,column=1)
tolNentry.insert(0,'10')
Label(root,text='tolS').grid(row=2,column=0)
tolNentry=Entry(root)
tolNentry.grid(row=2,column=1)
tolNentry.insert(0,'1.0')
Button(root,text='ReDraw',command=drawNewTree).grid(row=1,column=2,rowspan=3)
chkBtnVar=IntVar()
chkBtn=Checkbutton(root,text="model Tree",variable=chkBtnVar)
chkBtn.grid(row=3,column=0,columnspan=2)

# 退出按钮
Button(root,text='Quit',fg='black',command=root.quit).grid(row=1,column=2)
reDraw.rawDat=mat(loadDataSet('sine.txt'))
reDraw.testDat=arange(min(reDraw.rawDat[:,0]),max(reDraw.rawDat[:,0]),0.01)

reDraw(1.0,10)
root.mainloop()

运行得到:

7.2 集成Matplotlib和tkinter

 

import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure

def reDraw(tolS,tolN):
    # 清空?
    reDraw.f.clf()
    reDraw.a = reDraw.f.add_subplot(111)
    # 检查复选框是否被选中
    if chkBtnVar.get():
        if tolN < 2:
            tolN = 2
        # 创建模型树
        myTree = createTree(reDraw.rawDat, modelLeaf, modelErr, (tolS, tolN))
        yHat = createForeCast(myTree, reDraw.testDat, modelTreeEval)
    else:
        # 否则创建回归树
        myTree = createTree(reDraw.rawDat, ops = (tolS, tolN))
        yHat = createForeCast(myTree, reDraw.testDat)
    reDraw.a.scatter(array(reDraw.rawDat[:, 0]), array(reDraw.rawDat[:, 1]), s=5)
    # reDraw.a.scatter(reDraw.rawDat[:,0],reDraw.rawDat[:,1],s=5)
    reDraw.a.plot(reDraw.testDat,yHat,linewidth=2.0)
    reDraw.canvas.draw()

# 理解用户输入内容
def getInputs():
    try:
        tolN = int(tolNentry.get())
    except:
        tolN = 10
        print("enter Integer for tolN")
        tolNentry.delete(0,END)
        tolNentry.insert(0,'10')
    try:
        tolS = float(tolSentry.get())
    except:
        tolS = 1.0
        print("enter Float for tolS")
        tolSentry.delete(0,END)
        tolSentry.insert(0,'1.0')
    return tolN,tolS
 
 
def drawNewTree():
    # 得到用户输入的数值
    tolN,tolS = getInputs()
    # 重新画出拟合的直线
    reDraw(tolS,tolN)
 
root = Tk()
Label(root,text="Plot Place Holder").grid(row = 0,columnspan=3)
Label(root,text="tolN").grid(row=1,column=0)
tolNentry = Entry(root)
tolNentry.grid(row = 1,column=1)
tolNentry.insert(0,'10')
Label(root,text='tolS').grid(row=2,column=0)
tolSentry = Entry(root)
tolSentry.grid(row = 2,column = 1)
tolSentry.insert(0,'1.0')
# 按钮的执行函数
Button(root,text='ReDraw',command=drawNewTree).grid(row=1,column = 2,rowspan=3)
chkBtnVar = IntVar()
chkBtn = Checkbutton(root,text='Model Tree',variable=chkBtnVar)
chkBtn.grid(row=3,column = 0,columnspan=2)
# 加载数据
reDraw.rawDat = mat(loadDataSet("sine.txt"))
reDraw.testDat = arange(min(reDraw.rawDat[:,0]),max(reDraw.rawDat[:,0]),0.01)
# 设置画布大小
reDraw.f = Figure(figsize=(5,4),dpi = 100)
reDraw.canvas = FigureCanvasTkAgg(reDraw.f,master=root)
reDraw.canvas.draw()
reDraw.canvas.get_tk_widget().grid(row = 0,columnspan = 3)
# 画出拟合的直线图像
reDraw(1.0,10)
root.mainloop()

得到的输出结果为:

 更改tolN和tolS的值,并且根据是否选择构建模型树,可以得到不同的回归图像

8 本章小结

数据集中经常包含一些复杂的相互关系,使得输入数据和目标变量之间呈现非线性关系。对于这些复杂的关系建模,一种可行的方式时使用树来预测值分段,包括分段常数或分段直线。一般采用树结构来对这种数据建模。相应的,若叶结点使用的模型是分段常数则称为回归树,若叶节点使用的模型是线性回归方程则称为模型树。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/32607.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UG旋钮盖模具设计与加工

文章目录三维造型设计创建草图旋转拉伸拉伸求差圆周阵列倒圆抽壳二板模模具设计分型面初始化项目定义模具坐标定义成形镶件定义一模四腔的布局创建型芯和型腔检测区域创建区域和分型线创建分型面创建型芯和型腔加载模架创建模架添加标准件添加定位圈添加浇口套添加旋钮盖顶杆修…

【JavaScript】浏览器调试控制台console的功能有了解多少

在我们学会JavaScript编程以后&#xff0c;编程调试通常使用console.log() &#xff0c;那有没有想过&#xff0c;console除了log&#xff0c;还有很多是没有用到的&#xff0c;久而久之&#xff0c;就忘记了怎么用&#xff0c;接下来熟悉一下&#xff0c;温故而知新&#xff0…

网页大作业代码自取

&#x1f468;‍&#x1f393;静态网站的编写主要是用HTML DIVCSS JS等来完成页面的排版设计&#x1f469;‍&#x1f393;,常用的网页设计软件有Dreamweaver、EditPlus、HBuilderX、VScode 、Webstorm、Animate等等&#xff0c;用的最多的还是DW&#xff0c;当然不同软件写出的…

Red Eye Camera开发日记之API 移植I2C 和关键接口函数

API 说明文件里面有官方的移植指导&#xff0c;但我觉得可以把重点放在与 MLX90640 具体操作有关的几个函数上&#xff0c;而与标准 I2C 相关的函数和文件结构还是按照自己习惯的套路实现。这样更符合我们开发人员的可控性的习惯。步骤如下&#xff1a; 建立标准 I2C 文件 IIC…

第P9周:YOLOv5-Backbone模块实现

● &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客 ● &#x1f366; 参考文章&#xff1a;Pytorch实战 | 第P9周&#xff1a;YOLOv5-Backbone模块实现(训练营内部成员可读) ● &#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 说明&…

电脑技巧:推荐4个冷门且功能非常强大的效率工具

目录 1、Seafile 企业云盘神器 2、PPSSPP PSP模拟器神器 3、按键精灵 键盘鼠标模拟神器 4、BenVista PhotoZoom Pro 图片无损放大神器 今天给大家推荐4个冷门且功能非常强大的效率工具&#xff0c;一起来看看吧&#xff01; 1、Seafile 企业云盘神器 Seafile 是一个开源的网…

middlebury立体匹配评估使用方法总结(二)——python版离线教程

系列文章目录 middlebury立体匹配评估使用方法总结&#xff08;一&#xff09;——网站说明 middlebury立体匹配评估使用方法总结&#xff08;二&#xff09;——python版离线教程 文章目录系列文章目录前言1.下载内容2.配置环境3.elas编译4. 运行评估总结前言 最近想使用midd…

vim配置systemverilog环境

参考文章: vim中systemverilog的高亮显示 - 乔_木 - 博客园vim中systemverilog的高亮显示https://www.cnblogs.com/OneFri/p/6087847.html 一、.vimrc配置文件中添加 filetype on "打开文件类型检测 二、创建运行目录 mkdir -p ~/.vim/ftdetect mkdir -p ~/.vim/synta…

Python基础知识入门(一)

Python基础知识入门&#xff08;二&#xff09; 一、发展历程 Python的创始人为荷兰人吉多范罗苏姆&#xff08;Guido van Rossum&#xff09;。1989年圣诞节期间&#xff0c;在阿姆斯特丹&#xff0c;Guido为了打发圣诞节的无趣&#xff0c;决心开发一个新的脚本解释程序&…

第五章《类的继承》第2节:子类对象的构建过程

5.1小节讲解了类的继承机制。通过学习5.1小节的内容可知:子类能够继承父类的属性和方法,在此基础上,子类常常会扩展出属于自身特有的属性和方法,因此子类对象中的属性和方法可以分为两部分:从父类中继承而来的部分和自身所定义的部分。图5-3展示了Person和Student父子两个…

C++中的继承(上)

&#x1f9f8;&#x1f9f8;&#x1f9f8;各位大佬大家好&#xff0c;我是猪皮兄弟&#x1f9f8;&#x1f9f8;&#x1f9f8; 文章目录一、继承概述二、继承方式与访问限定符三、继承中的作用域四、基类和派生类对象赋值兼容转换五、继承当中默认成员函数的问题1.构造函数2.拷…

我做整车疲劳耐久分析9年积累的22条建模经验

作者&#xff1a;孙老师 对于承受交变应力的设备&#xff0c;疲劳分析在有限元分析占有重要地位。在进行疲劳分析时&#xff0c;有限元模型的正确搭建又至关重要。我们都知道&#xff0c;模型的质量直接影响分析的精度&#xff0c;所以好的建模方式是疲劳分析的第一步&#xf…

OpenGL原理与实践——核心模式(一):VBO、VAO等原理解析及项目初始设置

目录 序言——OpenGL在是什么&#xff1f;为什么&#xff1f;做什么? OpenGL实现了什么 OpenGL内模型数据的本质——顶点数据 我们需要研究什么——三角形&#xff0c;一个图形基元 MVP变换 OpenGL渲染流程的关键——摄像机变换 OpenGL渲染管线概览 准备——项目配置…

dpdk结合sriov测试vpp ipsec性能

目的 测试vpp ipsec转发性能&#xff0c;想当作openstack VPNaas的一种driver&#xff0c;提高ipsec网关的转发能力。 环境 测试资源很有限&#xff0c;没有测试仪&#xff0c;物理机之外的交换机不受控制。 只有两台物理机&#xff0c;各有一张测试网卡&#xff0c;网卡有…

分布式存储之 etcd 的集群管理

在分布式文件存储中&#xff0c;我们通常会面临集群选主&#xff0c;配置共享和节点状态监控的问题。通过 etcd&#xff08;基于 Raft 协议)&#xff09;可以实现超大规模集群的管理&#xff0c;以及多节点的服务可靠性。今天&#xff0c;我们就聊聊 etcd 在分布式存储中的具体…

作业-11.24

1、多线程并发服务器 #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <string.h> #include <pthread.h> #include <stdlib.h> #include <…

MCE | 间歇性禁食增强抗癌疗效

越来越多的研究表明&#xff0c;“禁食”不仅与免疫系统调控 、血糖调节有关&#xff0c;还对多种疾病的治疗有改善效果&#xff0c;如心血管疾病和癌症等。这里的“禁食”与节食不同&#xff0c;一般指的是间歇性禁食&#xff0c;包括多种方案&#xff0c;例如 FMD (Fasting-m…

LeetCode135. 分发糖果(贪心算法)

1 题目描述 n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。 你需要按照以下要求&#xff0c;给这些孩子分发糖果&#xff1a; 每个孩子至少分配到 1 个糖果。相邻两个孩子评分更高的孩子会获得更多的糖果。 请你给每个孩子分发糖果&#xff0c;计算并返回…

pyinstaller打包教程(pycharm)

PyInstaller简介 PyInstaller是一个跨平台的Python应用打包工具&#xff0c;支持 Windows/Linux/MacOS三大主流平台&#xff0c;能够把 Python 脚本及其所在的 Python 解释器打包成可执行文件&#xff0c;从而允许最终用户在无需安装 Python 的情况下执行应用程序。 PyInstalle…

IOS安全测试学习-DVIA-v2

前言 为学习IOS知识并加深理解&#xff0c;故通过IOS漏洞靶场来直接体现IOS环境中的常见漏洞。 环境准备 iPhone X ios 13.4.1 已越狱 MacOS Big Sur 11.0 Bate 虚拟机 DVIA-v2 IOS 漏洞靶场app grapefruit、objection #pip3 install frida、pip3 install frida-tools、sudo …