Python机器学习回归算法

2016/11/12 Python scikitlearn

Python机器学习回归算法

回归是指研究一组随机变量(输入变量)和另一组变量(输出变量)之间关系的统计分析方法。如果输入变量的值发生变化时,输出变量随之改变,则可以使用回归算法预测输入变量和输出变量之间的关系。回归用于预测与给定对象相关联的连续值属性,而分类用于预测与给定对象相关联的离散属性,这是区分分类和回归问题的重要标志。和分类问题一样,回归问题也属于监督学习的一类。回归问题按照输入变量的个数,可以分为一元回归和多元回归;按照输入变量与输出变量之间的关系,可以分为线性回归和非线性回归。

评价一个分类模型的性能相对容易,因为一个样本属于某个类别是一个是非判断问题,分类模型对某个样本的分类只有正确和错误两种结果。但是评价一个回归模型的性能就要复杂得多。例如用回归预测某地区房价,其结果并无正确与错误之分,只能用偏离实际价格的程度来评价这个结果。

线性回归算法

线性回归算法是使用线性方程对数据集进行拟合的算法,是一个非常常见的回归算法。本章首先从最简单的单变量线性回归算法开始介绍,然后介绍了多变量线性回归算法,其中成本函数以及梯度下降算法的推导过程会用到部分线性代数和偏导数;接着重点介绍了梯度下降算法的求解步骤以及性能优化方面的内容;

  • 单变量线性回归算法的原理;
  • 多变量线性回归算法的原理;
  • 梯度下降算法的原理及步骤;

算法原理

我们先考虑最简单的单变量线性回归算法,即只有一个输入特征。

预测函数

针对数据集x和y,预测函数会根据输入特征x来计算输出值h(x)。其输入和输出的函数关系如下:


这个方程表达的是一条直线。我们的任务是构造一个hθ函数,来映射数据集中的输入特征x和输出值y,使得预测函数hθ计算出来的值与真实值y的整体误差最小。构造hθ函数的关键,就是找到合适θ0,θ1的值,θ0,θ1称为模型参数。 假设我们有如下数据集:


假设模型参数θ0=1,θ1=3,则模型函数为hθ(x)=1+3x。针对数据集中的第一个样本,输入为1,根据模型函数预测出来的值是4,与输出值y是吻合的。针对第二个样本,输入为2,根据模型函数预测出来的值是7,与实际输出值y相差1。模型的求解过程,就是找出一组最合适的模型参数θ0,θ1,以便能最好地拟合数据集。

怎样来判断最好地拟合了数据集呢?回顾之前学过的知识,不难猜出,当拟合成本最小时,即找到了最好的拟合参数。

成本函数

单变量线性回归算法的成本函数是:


其中,h(x(i))-y(i)是预测值和实际值的差,故成本就是预测值和实际值的差的平方的平均值,之所以乘以1/2是为了计算方便。这个函数也称为均方差方程。有了成本函数,就可以精确地测量模型对训练样本拟合的好坏程度。

梯度下降算法

有了预测函数,也可以精确地测量预测函数对训练样本的拟合情况。我们要怎样求解模型参数θ0,θ1的值呢?这时梯度下降算法就派上了用场。

我们的任务是找到合适的θ0,θ1,使得成本函数J(θ0,θ1)最小。为了便于理解,我们切换到三维空间来描述这个任务。在一个三维空间里,以θ0作为x轴,以θ1作为y轴,以成本函数J(θ0,θ1)为z轴,那么我们的任务,就是要找出当z轴上的值最小的时候所对应的x轴上的值和y轴上的值。

梯度下降算法的原理是,先随机选择一组θ0,θ1,同时选择一个参数α作为移动的步幅。然后,让x轴上的θ0和y轴上的θ1分别向特定的方向移动一小步,这个步幅的大小就由参数α指定。经过多次迭代之后,x轴和y轴上的值决定的点就慢慢地靠近z轴上的最小值处,如图5-1所示。

这是个等高线图,就是说在我们描述的三维空间里,你的视角在正上方,看到一圈一圈z轴值相同的点构成的线。在图5-1中,随机选择的点在X0处,经过多次迭代后,慢慢地靠近圆心处,即z轴上最小值附近。

问题来了,X0(由[θ0,θ1]描述)怎么知道往哪个方向移动,才能靠近z轴上最小值附近?答案是往成本函数逐渐变小的方向移动。怎么表达成本函数逐渐变小的方向呢?答案是偏导数。

可以简单地把偏导数理解为斜率。我们要让θj不停地迭代,由当前θj的值,根据J(θ)的偏导数函数,算出J(θ)在θj上的斜率,然后再乘以学习率α,就可以让θj往前J(θ)变小的方向迈一小步。

用数学来描述上述过程,梯度下降的公式为:

公式中,下标j就是参数的序号,针对单变量线性回归,即0和1。α称为学习率,它决定每次要移动的幅度大小,它会乘以成本函数对参数θj的偏导数,以这个结果作为参数移动的幅度。如果幅度太小,意味着要计算很多次才能到达目的地,如果幅度太大,可能会直接跨过目的地,从而无法收敛。

把成本函数J(θ)的定义代入上面的公式中,不难推导出梯度下降算法公式:

对公式推导过程感兴趣的读者,可以参阅本章的扩展阅读的内容。

公式中,α是学习率;m是训练样本的个数;h(x(i))-y(i)是模型预测值和真实值的误差。需要注意的是,针对θ0和θ1分别求出了其迭代公式,在θ1的迭代公式里,累加器中还需要乘以xi。

数据归一化

当线性回归模型有多个输入特征时,特别是使用多项式添加特征时,需要对数据进行归一化处理。比如,特征x1的范围在[1,4]之间,特征x2的范围在[1,2000]之间,这种情况下,可以让x1除以4来作为新特征x1,同时让x2除以2000来作为新特征x2,该过程称为特征缩放(feature scaling)。可以使用特征缩放来对训练样本进行归一化处理,处理后的特征值范围在[0,1]之间。

为什么要进行数据归一化处理?归一化处理有哪些注意事项?

归一化处理的目的是让算法收敛更快,提升模型拟合过程中的计算效率。进行归一化处理后,当有个新的样本需要计算预测值时,也需要先进行归一化处理,再通过模型来计算预测值,计算出来的预测值要再乘以归一化处理的系数,这样得到的数据才是真实的预测数据。

在scikit-learn里,使用LinearRegression进行线性回归时,可以指定normalize=True来对数据进行归一化处理。具体可查阅scikit-learn文档。

示例:使用线性回归算法拟合正弦函数

本节用线性回归算法来模拟正统函数。首先,生成200个在区间内的正弦函数上的点,并且给这些点加上一些随机的噪声。

n_dots = 200
 
X = np.linspace(-2 * np.pi, 2 * np.pi, n_dots)
Y = np.sin(X) + 0.2 * np.random.rand(n_dots) - 0.1
X = X.reshape(-1, 1)
Y = Y.reshape(-1, 1);

其中,reshape()函数的作用是把Numpy的数组整形成符合scikit-learn输入格式的数组,否则scikit-learn会报错。接着,我们使用PolynomialFeatures和Pipeline创建一个多项式拟合模型:

from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
 
def polynomial_model(degree=1):
    polynomial_features = PolynomialFeatures(degree=degree,
                                             include_bias=False)
    linear_regression = LinearRegression(normalize=True)
    pipeline = Pipeline([("polynomial_features", polynomial_features),
                         ("linear_regression", linear_regression)])
    return pipeline

分别用2、3、5、10阶多项式来拟合数据集:

from sklearn.metrics import mean_squared_error
 
degrees = [2, 3, 5, 10]
results = []
for d in degrees:
    model = polynomial_model(degree=d)
    model.fit(X, Y)
    train_score = model.score(X, Y)
    mse = mean_squared_error(Y, model.predict(X))
    results.append({"model": model, "degree": d, "score":
      train_score, "mse": mse})
for r in results:
    print("degree: {}; train score: {}; mean squared error: {}".format(
        r["degree"], r["score"], r["mse"]))

算出每个模型拟合的评分,此外,使用mean_squared_error算出均方根误差,即实际的点和模型预测的点之间的距离,均方根误差越小说明模型拟合效果越好——上述代码的输出结果为:

degree: 2; train score: 0.147285454656; mean squared error: 0.42388701419
degree: 3; train score: 0.271740750281; mean squared error: 0.36201990526
degree: 5; train score: 0.895448999212; mean squared error: 0.0519726229563
degree: 10; train score: 0.993239572763; mean squared error: 
0.00336062910102

从输出结果可以看出,多项式的阶数越高,拟合评分越高,均方差误差越小,拟合效果越好。最后,我们把不同模型的拟合效果在二维坐标上画出来,可以清楚地看到不同阶数的多项式的拟合效果:

from matplotlib.figure import SubplotParams
 
plt.figure(figsize=(12, 6), dpi=200, subplotpars=SubplotParams(hspace=0.3))
for i, r in enumerate(results):
    fig = plt.subplot(2, 2, i+1)
    plt.xlim(-8, 8)
    plt.title("LinearRegression degree={}".format(r["degree"]))
    plt.scatter(X, Y, s=5, c='b', alpha=0.5)
    plt.plot(X, r["model"].predict(X), 'r-')

线性回归

若输出变量与一个或多个输入变量之间存在线性关系,则对此关系的研究称为线性回归。一个常见的线性回归模型为

y=w0+w1x1+w2x2+…+wpxp

在Scikit-learn的线性模型子模块(linear_model)中,向量w=_(w1, w2, …, wp)被定义为coef,w0被定义为intercept_。LinearRegression回归模型利用最小二乘法拟合一个带有系数(w1, w2, …, wp)的线性模型,使得数据集实际观测数据和预测数据(估计值)之间的残差平方和最小。

以下代码使用样本生成器make s_parse_uncorrelated( )生成了有4个固定系数的线性组合,然后使用LinearRegression回归模型实现回归。

from sklearn.datasets import make_sparse_uncorrelated
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split as tsplit
X, y = make_sparse_uncorrelated(n_samples=100, n_features=4)
X.shape # 生成有4个特征维的100个样本
# (100, 4)
y.shape
# (100,)
X_train, X_test, y_train, y_test = tsplit(X, y, test_size=0.1)
reg = LinearRegression() # 实例化最小二乘法线性回归模型
reg.fit(X_train, y_train) # 训练
# LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None, normalize=False)
y_pred = reg.predict(X_test) # 预测
y_pred # 预测结果
# array([-1.19447686,  2.02005782,  4.04782835, -0.1486067 , -4.57228115,
#       -0.41483865,  0.38927926,  1.75847807, -2.5458123 , -4.34608263])
y_test # 实际结果
# array([-1.75205189,  2.30606061,  5.38758422,  1.77522356, -5.44545423,
#        1.13737928, -0.04875574,  2.06188724, -2.94278265, -5.42752369])

支持向量机回归

支持向量机属于监督学习算法,不仅可以用于分类,还可以用于回归。和支持向量机分类类似,支持向量机回归也有三种不同的回归模型,即SVR、NuSVR和LinearSVR。与分类不同的是,这三个模型的fit( )方法调用的y参数向量是浮点型而不是整型。

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> import mpl_toolkits.mplot3d
>>> x, y = np.mgrid[-2:2:50j,-2:2:50j] # 生成50×50的网格
>>> z = x*np.exp(-x**2-y**2) # 计算网格上每一点的高度值
>>> _x = np.random.random(100)*4 - 2 # 随机生成区间[-2,2)内的100个x
>>> _y = np.random.random(100)*4 - 2 # 随机生成区间[-2,2)内的100个y
>>> _z = _x*np.exp(-_x**2-_y**2) + (np.random.random(100)-0.5)*0.1
>>> ax = plt.subplot(111, projection='3d')
>>> ax.plot_surface(x,y,z,cmap=plt.cm.hsv,alpha=0.5) # 50×50的网格曲面
<mpl_toolkits.mplot3d.art3d.Poly3DCollection object at 0x0000020F3B20BE88>
>>> ax.scatter3D(_x, _y, _z, c='r') # 100个样本点
<mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x0000020F3B6DE8C8>
>>> plt.show()

支持向量机回归模型有很多参数,比较重要的有kernel参数和C参数。kernel参数用来选择内核算法;C是误差项的惩罚参数,取值一般为10的整数次幂,如0.001、0.1、1000等。通常,C值越大,对误差项的惩罚越大,因此训练集测试时准确率就越高,但泛化能力越弱;C值越小,对误差项的惩罚越小,因此容错能力越强,泛化能力也相对越强。

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> import mpl_toolkits.mplot3d
>>> from sklearn.svm import SVR
>>> x, y = np.mgrid[-2:2:50j,-2:2:50j]
>>> z = x*np.exp(-x**2-y**2)
>>> _x = np.random.random(100)*4 - 2
>>> _y = np.random.random(100)*4 - 2
>>> _z = _x*np.exp(-_x**2-_y**2) + (np.random.random(100)-0.5)*0.1
>>> X_train = np.stack((_x, _y), axis=1) # 训练样本集
>>> y_train = _z # 训练标签集
>>> X_test = np.stack((x.ravel(), y.ravel()), axis=1) # 测试样本集
>>> y_test = z.ravel() # 测试标签集
>>> svr_1 = SVR(kernel='rbf', C=0.1) # 实例化SVR模型,rbf核函数,C=0.1
>>> svr_2 = SVR(kernel='rbf', C=100) # 实例化SVR模型,rbf核函数,C=100
>>> svr_1.fit(X_train, y_train) # 模型训练
SVR(C=0.1, cache_size=200, coef0=0.0, degree=3, epsilon=0.1, gamma='scale',
    kernel='rbf', max_iter=-1, shrinking=True, tol=0.001, verbose=False)
>>> svr_2.fit(X_train, y_train) # 模型训练
SVR(C=100, cache_size=200, coef0=0.0, degree=3, epsilon=0.1, gamma='scale',
    kernel='rbf', max_iter=-1, shrinking=True, tol=0.001, verbose=False)
>>> z_1 = svr_1.predict(X_test) # 模型预测
>>> z_2 = svr_2.predict(X_test) # 模型预测
>>> score_1 = svr_1.score(X_test, y_test) # 模型评估
>>> score_2 = svr_2.score(X_test, y_test) # 模型评估
>>> score_1
0.7704232164121735
>>> score_2
0.8893209908625596
>>> ax = plt.subplot(121, projection='3d')
>>> ax.scatter3D(_x, _y, _z, c='r')
<mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x0000017EC7E9AD08>
>>> ax.plot_surface(x,y,z_1.reshape(x.shape),cmap=plt.cm.hsv,alpha=0.5)
<mpl_toolkits.mplot3d.art3d.Poly3DCollection object at 0x0000017EC7E9AC48>
>>> plt.title('score:%0.3f@kernel="rbf", C=0.1'%score_1)
Text(0.5, 0.92, 'score:0.761@kernel="rbf", C=0.1')
>>> ax = plt.subplot(122, projection='3d')
>>> ax.scatter3D(_x, _y, _z, c='r')
<mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x0000017EC2EA2048>
>>> ax.plot_surface(x,y,z_2.reshape(x.shape),cmap=plt.cm.hsv,alpha=0.5)
<mpl_toolkits.mplot3d.art3d.Poly3DCollection object at 0x0000017EC7FBCAC8>
>>> plt.title('score:%0.3f@kernel="rbf", C=100'%score_2)
Text(0.5, 0.92, 'score:0.860@kernel="rbf", C=100')
>>> plt.show()

上面的代码指定kernel参数为rbf核函数(高斯核函数),C值分别取0.1和100,gamma参数使用默认值。结果显示,C值取100比C值取0.1的回归结果更优,它几乎复现了生成样本所依赖的曲面

如果将核函数更换为线性(linear)核函数或多项式(poly)核函数,就本例而言,回归效果明显变差。

>>> svr_1 = SVR(kernel='linear', C=100) # 实例化SVR模型,线性核函数,C=100
>>> svr_2 = SVR(kernel='poly', C=100) # 实例化SVR模型,多项式核函数,C=100
>>> svr_1.fit(X_train, y_train) # 模型训练
SVR(C=100, cache_size=200, coef0=0.0, degree=3, epsilon=0.1, gamma='scale',
    kernel='linear', max_iter=-1, shrinking=True, tol=0.001, verbose=False)
>>> svr_2.fit(X_train, y_train) # 模型训练
SVR(C=100, cache_size=200, coef0=0.0, degree=3, epsilon=0.1, gamma='scale',
    kernel='poly', max_iter=-1, shrinking=True, tol=0.001, verbose=False)
>>> z_1 = svr_1.predict(X_test) # 模型预测
>>> z_2 = svr_2.predict(X_test) # 模型预测
>>> score_1 = svr_1.score(X_test, y_test) # 模型评估
>>> score_2 = svr_2.score(X_test, y_test) # 模型评估
>>> score_1
0.2396389420473286
>>> score_2
0.021762800917930814
>>> ax = plt.subplot(121, projection='3d')
>>> ax.scatter3D(_x, _y, _z, c='r')
<mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x0000017EC837C348>
>>> ax.plot_surface(x,y,z_1.reshape(x.shape),cmap=plt.cm.hsv,alpha=0.5)
<mpl_toolkits.mplot3d.art3d.Poly3DCollection object at 0x0000017EC837C448>
>>> plt.title('score:%0.3f@kernel="linear", C=100'%score_1)
Text(0.5, 0.92, 'score:0.245@kernel="linear", C=100')
>>> ax = plt.subplot(122, projection='3d')
>>> ax.scatter3D(_x, _y, _z, c='r')
<mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x0000017EC837CCC8>
>>> ax.plot_surface(x,y,z_2.reshape(x.shape),cmap=plt.cm.hsv,alpha=0.5)
<mpl_toolkits.mplot3d.art3d.Poly3DCollection object at 0x0000017EC7653BC8>
>>> plt.title('score:%0.3f@kernel="poly", C=100'%score_2)
Text(0.5, 0.92, 'score:0.007@kernel="poly", C=100')
>>> plt.show()

上面的代码分别指定kernel参数为线性核函数和多项式核函数,C值固定为100,回归结果变得几乎不可用

k-近邻回归

k-近邻回归和k-近邻分类都是基于最近邻算法实现的,不同的是,k-近邻分类适用于数据标签为离散变量的情况,而k-近邻回归适用于数据标签为连续变量的情况。k-近邻回归预测样本的标签由它最近邻标签的均值计算而来。

Scikit-learn提供了两个不同的最近邻回归类:KneighborsRegressor类基于每个查询点的k个最近邻实现,其中k是用户指定的整数值;RadiusNeighborsRegressor类基于每个查询点的固定半径r内的邻点数量实现,其中r是用户指定的浮点数值。

下面的代码使用KneighborsRegressor类(默认参数)对已知曲面上的样本点做回归分析,取得了不错的效果,性能评分仅次于使用rbf核函数的支持向量机回归。

>>> import numpy as np
>>> from sklearn.neighbors import KNeighborsRegressor
>>> import matplotlib.pyplot as plt
>>> import mpl_toolkits.mplot3d
>>> x, y = np.mgrid[-2:2:50j,-2:2:50j] # 生成50×50的网格
>>> z = x*np.exp(-x**2-y**2) # 计算网格上每一个点的高度值
>>> _x = np.random.random(100)*4 - 2 # 随机生成区间[-2,2)内的100个x
>>> _y = np.random.random(100)*4 - 2 # 随机生成区间[-2,2)内的100个y
>>> _z = _x*np.exp(-_x**2-_y**2) + (np.random.random(100)-0.5)*0.1
>>> X_train = np.stack((_x, _y), axis=1) # 训练样本集
>>> y_train = _z # 训练标签集
>>> X_test = np.stack((x.ravel(), y.ravel()), axis=1) # 测试样本集
>>> y_test = z.ravel() # 测试标签集
>>> knr = KNeighborsRegressor() # 实例化模型
>>> knr = KNeighborsRegressor().fit(X_train, y_train) # 模型训练
>>> z_knr = knr.predict(X_test) # 模型预测
>>> score = knr.score(X_test, y_test) # 模型评估
>>> score
0.8918972416840268
>>> ax = plt.subplot(111, projection='3d')
>>> ax.scatter3D(_x, _y, _z, c='r')
<mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x0000017EC8603588>
>>> ax.plot_surface(x,y,z_knr.reshape(x.shape),cmap=plt.cm.hsv,alpha=0.5)
<mpl_toolkits.mplot3d.art3d.Poly3DCollection object at 0x0000017EC8603488>
>>> plt.show()

是对三维曲面上样本点做k-近邻回归分析的结果。显然,k-近邻回归依赖数量较多的训练样本,当训练样本数量较少时,k-近邻回归没有支持向量机回归的结果平滑。

决策树回归

决策树同样也可以用来做回归分析,不过有一点需要特别注意:基于决策树的回归模型不能外推,不能对训练数据范围外的样本进行预测。Scikit-learn的决策树子模块tree提供了DecisionTreeRegressor类来解决回归问题。和分类树一样,决策树深度(max_depth)也是回归树的重要参数,决策树深度的增加虽然可以增强训练集的拟合能力,但这也可能导致其泛化能力的下降。

下面的代码使用不同的决策树深度对已知曲面上的样本点做回归分析,但效果不尽如人意。

>>> import numpy as np
>>> from sklearn.tree import DecisionTreeRegressor
>>> import matplotlib.pyplot as plt
>>> import mpl_toolkits.mplot3d
>>> x, y = np.mgrid[-2:2:50j,-2:2:50j] # 生成50×50的网格
>>> z = x*np.exp(-x**2-y**2) # 计算网格上每一个点的高度值
>>> _x = np.random.random(100)*4 - 2 # 随机生成区间[-2,2)内的100个x
>>> _y = np.random.random(100)*4 - 2 # 随机生成区间[-2,2)内的100个y
>>> _z = _x*np.exp(-_x**2-_y**2) + (np.random.random(100)-0.5)*0.1
>>> X_train = np.stack((_x, _y), axis=1) # 训练样本集
>>> y_train = _z # 训练标签集
>>> X_test = np.stack((x.ravel(), y.ravel()), axis=1) # 测试样本集
>>> y_test = z.ravel() # 测试标签集
>>> dtr_1 = DecisionTreeRegressor(max_depth=5) # 实例化模型,决策树深度为5
>>> dtr_2 = DecisionTreeRegressor(max_depth=10) # 实例化模型,决策树深度为10
>>> dtr_1.fit(X_train, y_train) # 模型训练
DecisionTreeRegressor(ccp_alpha=0.0, criterion='mse', max_depth=5,
                      max_features=None, max_leaf_nodes=None,
                      min_impurity_decrease=0.0, min_impurity_split=None,
                      min_samples_leaf=1, min_samples_split=2,
                      min_weight_fraction_leaf=0.0, presort='deprecated',
                      random_state=None, splitter='best')
>>> dtr_2.fit(X_train, y_train) # 模型训练
DecisionTreeRegressor(ccp_alpha=0.0, criterion='mse', max_depth=10,
                      max_features=None, max_leaf_nodes=None,
                      min_impurity_decrease=0.0, min_impurity_split=None,
                      min_samples_leaf=1, min_samples_split=2,
                      min_weight_fraction_leaf=0.0, presort='deprecated',
                      random_state=None, splitter='best')
>>> z_1 = dtr_1.predict(X_test)
>>> z_2 = dtr_2.predict(X_test) # 模型预测
>>> score_1 = dtr_1.score(X_test, y_test) # 模型评估
>>> score_2 = dtr_2.score(X_test, y_test) # 模型评估
>>> score_1
0.7901477190145176
>>> score_2
0.8205039540519313
>>> ax = plt.subplot(121, projection='3d')
>>> ax.scatter3D(_x, _y, _z, c='r')
<mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x0000017EC7733E08>
>>> ax.plot_surface(x,y,z_1.reshape(x.shape),cmap=plt.cm.hsv,alpha=0.5)
<mpl_toolkits.mplot3d.art3d.Poly3DCollection object at 0x0000017EC7733D48>
>>> plt.title('score:%0.3f@max_depth=5'%score_1)
Text(0.5, 0.92, 'score:0.779@max_depth=5')
>>> ax = plt.subplot(122, projection='3d')
>>> ax.scatter3D(_x, _y, _z, c='r')
<mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x0000017EC75C4F08>
>>> ax.plot_surface(x,y,z_2.reshape(x.shape),cmap=plt.cm.hsv,alpha=0.5)
<mpl_toolkits.mplot3d.art3d.Poly3DCollection object at 0x0000017EC75C4D88>
>>> plt.title('score:%0.3f@max_depth=10'%score_2)
Text(0.5, 0.92, 'score:0.820@max_depth=10')
>>> plt.show()

随机森林回归

单棵决策树通常具有高方差,因此容易过拟合。随机森林回归模型能够通过组合不同的决策树降低方差,但有时会略微增加偏差。在实际应用中,方差降低通常比偏差增加更加显著,所以随机森林回归模型能够取得更好的效果。随机森林回归模型需要调整的参数主要是n_estimators和max_features。n_estimators参数用于设置随机森林回归模型里决策树的数量,通常数量越大,效果越好,但是计算时间也会随之增加。当决策树的数量超过一个临界值后,算法的效果并不会很显著地变好。max_features参数用于设置分割节点时考虑的特征的随机子集的大小。这个值越低,方差减小得越多,但是偏差的增大也越多。默认回归问题中设置max_features参数为None,意为选择所有特征。

>>> import numpy as np
>>> from sklearn.ensemble import RandomForestRegressor
>>> import matplotlib.pyplot as plt
>>> import mpl_toolkits.mplot3d
>>> x, y = np.mgrid[-2:2:50j,-2:2:50j] # 生成50×50的网格
>>> z = x*np.exp(-x**2-y**2) # 计算网格上每一个点的高度值
>>> _x = np.random.random(100)*4 - 2 # 随机生成区间[-2,2)内的100个x
>>> _y = np.random.random(100)*4 - 2 # 随机生成区间[-2,2)内的100个y
>>> _z = _x*np.exp(-_x**2-_y**2) + (np.random.random(100)-0.5)*0.1
>>> X_train = np.stack((_x, _y), axis=1) # 训练样本集
>>> y_train = _z # 训练标签集
>>> X_test = np.stack((x.ravel(), y.ravel()), axis=1) # 测试样本集
>>> y_test = z.ravel() # 测试标签集
>>> rfr_1 = RandomForestRegressor(n_estimators=20,max_depth=10)
>>> rfr_2 = RandomForestRegressor(n_estimators=50,max_depth=10)
>>> rfr_1.fit(X_train, y_train) # 模型训练
RandomForestRegressor(bootstrap=True, ccp_alpha=0.0, criterion='mse',
                      max_depth=10, max_features='auto', max_leaf_nodes=None,
                      max_samples=None, min_impurity_decrease=0.0,
                      min_impurity_split=None, min_samples_leaf=1,
                      min_samples_split=2, min_weight_fraction_leaf=0.0,
                      n_estimators=20, n_jobs=None, oob_score=False,
                      random_state=None, verbose=0, warm_start=False)
>>> rfr_2.fit(X_train, y_train) # 模型训练
RandomForestRegressor(bootstrap=True, ccp_alpha=0.0, criterion='mse',
                      max_depth=10, max_features='auto', max_leaf_nodes=None,
                      max_samples=None, min_impurity_decrease=0.0,
                      min_impurity_split=None, min_samples_leaf=1,
                      min_samples_split=2, min_weight_fraction_leaf=0.0,
                      n_estimators=50, n_jobs=None, oob_score=False,
                      random_state=None, verbose=0, warm_start=False)
>>> z_1 = rfr_1.predict(X_test) # 模型预测
>>> z_2 = rfr_2.predict(X_test) # 模型预测
>>> score_1 = rfr_1.score(X_test, y_test) # 模型评估
>>> score_2 = rfr_2.score(X_test, y_test) # 模型评估
>>> score_1
0.8855225918778594
>>> score_2
0.8754412572343655
>>> ax = plt.subplot(121, projection='3d')
>>> ax.scatter3D(_x, _y, _z, c='r')
<mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x0000017EC7E46C08>
>>> ax.plot_surface(x,y,z_1.reshape(x.shape),cmap=plt.cm.hsv,alpha=0.5)
<mpl_toolkits.mplot3d.art3d.Poly3DCollection object at 0x0000017EC7E464C8>
>>> plt.title('score:%0.3f@n_estimators=20,max_depth=10'%score_1)
Text(0.5, 0.92, 'score:0.914@n_estimators=20,max_depth=10')
>>> ax = plt.subplot(122, projection='3d')
>>> ax.scatter3D(_x, _y, _z, c='r')
<mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x0000017EC7E46808>
>>> ax.plot_surface(x,y,z_2.reshape(x.shape),cmap=plt.cm.hsv,alpha=0.5)
<mpl_toolkits.mplot3d.art3d.Poly3DCollection object at 0x0000017EC7ED5BC8>
>>> plt.title('score:%0.3f@n_estimators=50,max_depth=10'%score_2)
Text(0.5, 0.92, 'score:0.928@n_estimators=50,max_depth=10')
>>> plt.show()

Search

    微信好友

    博士的沙漏

    Table of Contents