机器学习“傻瓜式”理解(10)模型评估

过拟合与欠拟合问题

我们进行机器学习的目标是寻找出一个模型,使得这个模型对于我们的预测点能够给予准确的解答,而不是让其最大程度的拟合我们的训练数据集的样本点。我们将这种能力称之为模型的泛化能力。(解决模型泛化能力可以称之为机器学习领域十分重要的问题。)
评价方法
我们在之前的KNN中讲过均方误差(MSE),主要用来描述两组数之间的相同程度。我们通过对X_predict预测出y_predict,然后让其与y进行均方误差的评估,均方误差越小,拟合程度越高,模型就越可能产生过拟合现象;均方误差越大,拟合程度越低,模型就越可能产生欠拟合。当均方误差为0时,模型拟合住了所有的数据。
模型复杂度
我们上面提到,在我们进行数据的拟合过程中会产生过拟合和欠拟合现象,产生过拟合的现象便是模型的复杂度较高,反之欠拟合的现象则模型的复杂度较低。
对于我们前面所讲的算法,我们都可以通过超参数的调整来调整模型的复杂度。
在这里插入图片描述
概念解释:
欠拟合:我们所得到的模型无法完整的表述数据间的关系。
过拟合:我们所得到的的模型过多的表述了数据间的关系,通常情况下我们的模型可能学习到了噪音。
对应于过拟合和欠拟合,尤其是过拟合现象,是我们在机器学习的过程中一直要重点解决的问题。
解决的方案我们之前提到过,将数据分为训练数据集和测绘数据集,通过网格搜索的方式寻找在测试数据集上最优的模型。(此种方式仍不是最好,后续我们接着介绍其他方式)
案例代码 (使用scikit-learn)
①导入相关工具

import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.pipeline import Pipeline

②生成数据,进行线性拟合,计算MSE

np.random.seed(666)
x = np.random.uniform(-3.0,3.0,size = 100)
X = x.reshape(-1,1)
y = 0.5 * x**2 + x + 2 + np.random.normal(0, 1, size=100)

X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=666)
lin = LinearRegression()
lin.fit(X_train,y_train)
y_predict = lin.predict(X_test)
result =  mean_squared_error(y_test,y_predict)
print(result)  #均方误差:2.2199965269396573

③使用多项式回归

# degree = 2
poly_2 = polyCom(degree=2)
poly_2.fit(X_train,y_train)
y2_predict = poly_2.predict(X_test)
y2_result = mean_squared_error(y_test,y2_predict)
print(y2_result) #均方误差:0.80356410562979

# degree = 10
poly_10 = polyCom(degree=10)
poly_10.fit(X_train,y_train)
y10_predict = poly_10.predict(X_test)
y10_result = mean_squared_error(y_test,y10_predict)
print(y10_result) #均方误差:0.9212930722150794

# degree = 100
poly_100 = polyCom(degree=100)
poly_100.fit(X_train,y_train)
y100_predict = poly_2.predict(X_test)
y100_result = mean_squared_error(y_test,y100_predict)
print(y100_result) #均方误差:14075796419.234262

如何得出的结果很差,则很有可能产生了过拟合。

学习曲线

通过上节的解释我们可以了解到我们可以使用均方误差(MSE)来具体的评估机器学习算法的评估性能。我们这一节将使用学习曲线来进行评估性能。
学习曲线的具体作用便是查看模型的学习效果,然后我们可以直观可视化的查看到过拟合和欠拟合的现象。定义便是:随着训练样本的逐渐增多,算法训练出的模型的表现能力。
代码封装:

def plot_learning_curve(algo,X_train,y_train,X_test,y_test):
    train_score = []
    test_score = []

    for i in range(1,len(X_train) + 1):
        algo.fit(X_train[:i],y_train[:i])

        y_train_predict = algo.predict(X_train[:i])
        train_score.append(mean_squared_error(y_train[:i],y_train_predict))

        y_test_train = algo.predict(X_test[:i])
        test_score.append(mean_squared_error(y_test[:i],y_test_train))

    plt.plot([i for i in range(1,len(X_train) + 1)],np.sqrt(train_score),label="train")
    plt.plot([i for i in range(1, len(X_train) + 1)], np.sqrt(test_score), label="test")

    plt.legend()
    plt.axis([0,len(X_train)+1,0,4])
    plt.show()

然后我们在根据上节进行的步骤进行拟合:
通过一张图片分析学习曲线:
在这里插入图片描述

验证数据集和交叉验证

我们进行模型评估的目的是为了得出最佳的模型,也就是在测试数据集上表现比较好的模型,因为这种方式得到的模型泛化能力强。为了得到这种最佳的模型,我们需要通过不同的调参进行确定最佳模型。
通过划分数据集进行调整参数有下面几种方式:
①全部使用
将所有的数据全部投入试验,得到模型后直接用于生产,这样的做法看起来是在当前的数据集上误差相对较小,但是如果发生了过拟合现象我们无从得知,因此此种方法不推荐。
②从笔记一开始我们便使用的方法,训练测试分离,我们将在训练数据集上训练模型,然后通过测试数据集调整参数,目标便是使得在测试数据集上的均方误差最小。但是此种方式也存在一定的弊端,那便是我们有可能实现产生在测试数据集上进行过拟合。
③此种方式是第二种方法的改进,我们将数据分为训练,验证,测试数据集,相应的,每个数据集的功能一目了然,我们在训练数据集上进行训练模型,然后在验证数据集上训练适宜的超参数,然后拿到测试数据集上进行测试,但是这样做同样存在着问题,我们很有可能在验证数据集上产生过拟合现象。因为我们只有一份验证数据集,如果验证数据集上存在极端的数据然后通过此得到的准确率高的模型是不准确的。
④由此我们便得到了第四种方式,交叉验证方式,我们将训练数据集分为三份,一份做验证,另外两份做训练,每一种都进行这样的划分,得出的m个模型的性能平均值作为最终衡量该组参数的对应的模型的性能指标。缺点便是性能较慢。极端情况下,这种方法可演变为“留一法”,也就是训练集一个为验证,其余都是训练,循环m次。
案例代码演示
我们之前使用网格搜索(GridSearchCV:CV便是cross validation)就是使用的交叉验证的方式。

import numpy as np
from sklearn.kneighbors import KNeighborsClassifier
# 使用scikit中的手写数字数据集
from sklearn import datasets
from sklearn.model_selectino import train_test_split
# 交叉验证
from sklearn.model_selection import GridSearchCV

digits = datasets.load_digits()
X = digits.data
y = digits.target

X_train,X_test,y_train,y_test = train_test_split(X,y)

param_grid = [
	{
		'weights',['distance'],
		'n_neighbors',[i for i in range(1,10)],
		'p',[i for i in range(1,6)]
	}
]
knn_clf = KNeighborsClassifier()
gd = GridSearchCV(knn_clf, param_grid, verbose=1, cv=3)
gd.fit(X_train, y_train)

# 学习
gd.best_params_
# 输出:{'n_neighbors': 2, 'p': 2, 'weights': 'distance'}

# 获取最佳的分类器,也就是最佳的模型,
best = gd.best_estimator_
best.score(X_test,y_test)
# 输出:0.980528511821975 这便是真生的泛化能力值

偏差方差问题

我们在机器学习预测出的模型中会产生各种误差,其中包括主要的两种:
①偏差(Bias):结果偏离目标位置
②方差(Variance):数据间的分布状态,数据分布的越集中方差越低,数据分布的越分散,方差越高。
一般来说,我们在预测模型时产生的错误包括偏差+方差+不可避免的误差。
我们通常的目标是去寻求一个偏差与方差的均衡。
原因分析
偏差产生的原因:
首先我们可能对模型本来的假设便不准确,例如最终模型将是一个多项式回归模型,但是我们的假设确实普通的线性模型,另外一个,模型的欠拟合现象也会导致偏差的产生。
方差产生的原因:
有可能模型在学习的过程中学习到很多的噪音,或者来说产生了过拟合现象,或者是预测出来的模型太过复杂,都有可能导致方差产生。

另外,方差和偏差两者相互矛盾,在机器学习领域,我们解决的主要的问题是高方差的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值