机器学习基础:(Python)训练集测试集分割与交叉验证

在上一篇关于Python中的线性回归的文章之后,我想再写一篇关于训练测试分割和交叉验证的文章。在数据科学和数据分析领域中,这两个概念经常被用作防止或最小化过度拟合的工具。我会解释当使用统计模型时,通常将模型拟合在训练集上,以便对未被训练的数据进行预测。

在统计学和机器学习领域中,我们通常把数据分成两个子集:训练数据和测试数据,并且把模型拟合到训练数据上,以便对测试数据进行预测。当做到这一点时,可能会发生两种情况:模型的过度拟合或欠拟合。我们不希望出现这两种情况,因为这会影响模型的可预测性。我们有可能会使用具有较低准确性或不常用的模型(这意味着你不能泛化对其它数据的预测)。

什么是模型的过度拟合(Overfitting)和欠拟合(Underfitting)?

过度拟合

过度拟合意味着模型训练得“太好”了,并且与训练数据集过于接近了。这通常发生在模型过于复杂的情况下,模型在训练数据上非常的准确,但对于未训练数据或者新数据可能会很不准确。因为这种模型不是泛化的,意味着你可以泛化结果,并且不能对其它数据进行任何推断,这大概就是你要做的。基本上,当发生这种情况时,模型学习或描述训练数据中的“噪声”,而不是数据中变量之间的实际关系。这种噪声显然不是任何新数据集的一部分,不能应用于它。

欠拟合

与过度拟合相反,当模型欠拟合的时候,它意味着模型不适合训练数据,因此会错过数据中的趋势特点。这也意味着该模型不能被泛化到新的数据上。你可能猜到了,这通常是模型非常简单的结果。例如,当我们将线性模型(如线性回归)拟合到非线性的数据时,也会发生这种情况。不言而喻,该模型对训练数据的预测能力差,并且还不能推广到其它的数据上。

实例

值得注意的是,欠拟合不像过度拟合那样普遍。然而,我们希望避免数据分析中的这两个问题。你可能会说,我们正在试图找到模型的欠拟合与过度拟合的中间点。像你所看到的,训练测试分割和交叉验证有助于避免过度拟合超过欠拟合。

训练测试分割

正如我之前所说的,我们使用的数据通常被分成训练数据和测试数据。训练集包含已知的输出,并且模型在该数据上学习,以便以后将其泛化到其它数据上。我们有测试数据集(或子集),为了测试模型在这个子集上的预测。

我们将使用Scikit-Learn library,特别是其中的训练测试分割方法。我们将从导入库开始:


快速地看一下导入的库:

· Pandas?—将数据文件作为Pandas数据帧加载,并对数据进行分析;

· 在Sklearn中,我导入了数据集模块,因此可以加载一个样本数据集和linear_model,因此可以运行线性回归;

· 在Sklearn的子库model_selection中,我导入了train_test_split,因此可以把它分成训练集和测试集;

· 在Matplotlib中,我导入了pyplot来绘制数据图表;

好了,一切都准备就绪,让我们输入糖尿病数据集,将其转换成数据帧并定义列的名称:


现在我们可以使用train_test_split函数来进行分割。函数内的test_size=0.2表明了要测试的数据的百分比,通常是80/20或70/30左右。

# create training and testing vars
X_train, X_test, y_train, y_test = train_test_split(df, y, test_size=0.2)
print X_train.shape, y_train.shape
print X_test.shape, y_test.shape
(353, 10) (353,)
(89, 10) (89,)

现在我们将在训练数据上拟合模型:

# fit a model
lm = linear_model.LinearRegression()
model = lm.fit(X_train, y_train)
predictions = lm.predict(X_test)

正如所看到的那样,我们在训练数据上拟合模型并尝试预测测试数据。让我们看一看都预测了什么:

predictions[0:5]
array([ 205.68012533,   64.58785513,  175.12880278,  169.95993301,
        128.92035866])

注:因为我在预测之后使用了[0:5],它只显示了前五个预测值。去掉[0:5]的限制就会使它输出我们模型创建的所有预测值。

让我们来绘制模型:

## The line / model
plt.scatter(y_test, predictions)
plt.xlabel(“True Values”)
plt.ylabel(“Predictions”)

打印准确度得分:

print “Score:”, model.score(X_test, y_test)
Score: 0.485829586737

总结:将数据分割成训练集和测试集,将回归模型拟合到训练数据,基于该数据做出预测,并在测试数据上测试预测结果。但是训练和测试的分离确实有其危险性,如果我们所做的分割不是随机的呢?如果我们数据的一个子集只包含来自某个州的人,或者具有一定收入水平但不包含其它收入水平的员工,或者只有妇女,或者只有某个年龄段的人,那该怎么办呢?这将导致过度拟合,即使我们试图避免,这就是交叉验证要派上用场了。

交叉验证

在前一段中,我提到了训练测试分割方法中的注意事项。为了避免这种情况,我们可以执行交叉验证。它非常类似于训练测试分割,但是被应用于更多的子集。意思是,我们将数据分割成k个子集,并训练第k-1个子集。我们要做的是,为测试保留最后一个子集。

训练测试分割和交叉验证的可视化表示

有一组交叉验证方法,我来介绍其中的两个:第一个是K-Folds Cross Validation,第二个是Leave One Out Cross Validation (LOOCV)。

K-Folds 交叉验证

在K-Folds交叉验证中,我们将数据分割成k个不同的子集。我们使用第k-1个子集来训练数据,并留下最后一个子集作为测试数据。然后,我们对每个子集模型计算平均值,接下来结束模型。之后,我们对测试集进行测试。

K-Folds的可视化表示

这里有一个在Sklearn documentation上非常简单的K-Folds例子:

fromsklearn.model_selection import KFold # import KFold
X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]]) # create an array
y = np.array([1, 2, 3, 4]) # Create another array
kf = KFold(n_splits=2) # Define the split - into 2 folds
kf.get_n_splits(X) # returns the number of splitting iterations in the cross-validator
print(kf)
KFold(n_splits=2, random_state=None, shuffle=False)

让我们看看结果:

fortrain_index, test_index in kf.split(X):
 print(“TRAIN:”, train_index, “TEST:”, test_index)
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
(‘TRAIN:‘, array([2, 3]), ‘TEST:‘, array([0, 1]))
(‘TRAIN:‘, array([0, 1]), ‘TEST:‘, array([2, 3]))

正如看到的,函数将原始数据拆分成不同的数据子集。这是个非常简单的例子,但我认为它把概念解释的相当好。

弃一法交叉验证(Leave One Out Cross Validation,LOOCV)

这是另一种交叉验证的方法,弃一法交叉验证。在这种交叉验证中,子集的数量等于我们在数据集中观察到的数量。然后,我们计算所有子集的平均数,并利用平均值建立模型。然后,对最后一个子集测试模型。因为我们会得到大量的训练集(等于样本的数量),因此这种方法的计算成本也相当高,应该在小数据集上使用。如果数据集很大,最好使用其它的方法,比如kfold。

让我们看看Sklearn上的另一个例子:

fromsklearn.model_selectionimportLeaveOneOut
X = np.array([[1, 2], [3, 4]])
y = np.array([1, 2])
loo = LeaveOneOut()
loo.get_n_splits(X)

fortrain_index, test_indexinloo.split(X):
   print("TRAIN:", train_index, "TEST:", test_index)
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
   print(X_train, X_test, y_train, y_test)

以下是输出:

(‘TRAIN:‘, array([1]), ‘TEST:‘, array([0]))
(array([[3, 4]]), array([[1, 2]]), array([2]), array([1]))
(‘TRAIN:‘, array([0]), ‘TEST:‘, array([1]))
(array([[1, 2]]), array([[3, 4]]), array([1]), array([2]))

那么,我们应该使用什么方法呢?使用多少子集呢?拥有的子集越多,我们将会由于偏差而减少误差,但会由于方差而增加误差;计算成本也会上升,显然,拥有的子集越多,计算所需的时间就越长,也将需要更多的内存。如果利用数量较少的子集,我们减少了由于方差而产生的误差,但是由于偏差引起的误差会更大。它的计算成本也更低。因此,在大数据集中,通常建议k=3。在更小的数据集中,正如我之前提到的,最好使用弃一法交叉验证。

让我们看看以前用过的一个例子,这次使用的是交叉验证。我将使用cross_val_predict函数来给每个在测试切片中的数据点返回预测值。

# Necessary imports:
from sklearn.cross_validation import cross_val_score, cross_val_predict
from sklearn import metrics

之前,我给糖尿病数据集建立了训练测试分割,并拟合了一个模型。让我们看看在交叉验证之后的得分是多少:

# Perform 6-fold cross validation
scores = cross_val_score(model, df, y, cv=6)
print “Cross-validated scores:”, scores
Cross-validated scores: [ 0.4554861   0.46138572  0.40094084  0.55220736  0.43942775  0.56923406]

正如你所看到的,最后一个子集将原始模型的得分从0.485提高到0.569。这并不是一个惊人的结果,但我们得到了想要的。

现在,在进行交叉验证之后,让我们绘制新的预测图:

# Make cross validated predictions
predictions = cross_val_predict(model, df, y, cv=6)
plt.scatter(y, predictions)

你可以看到这和原来的图有很大的不同,是原来图的点数的六倍,因为我用的cv=6。

最后,让我们检查模型的R2得分(R2是一个“表示与自变量分离的可预测的因变量中方差的比例的数量”)。可以看一下我们的模型有多准确:

accuracy = metrics.r2_score(y, predictions)
print “Cross-Predicted Accuracy:”, accuracy
Cross-Predicted Accuracy: 0.490806583864

原文链接
本文为云栖社区原创内容,未经允许不得转载。

原文地址:https://www.cnblogs.com/yunqishequ/p/10006890.html

时间: 2024-11-05 20:25:01

机器学习基础:(Python)训练集测试集分割与交叉验证的相关文章

随机切分csv训练集和测试集

使用numpy切分训练集和测试集 觉得有用的话,欢迎一起讨论相互学习~Follow Me 序言 在机器学习的任务中,时常需要将一个完整的数据集切分为训练集和测试集.此处我们使用numpy完成这个任务. iris数据集中有150条数据,我们将120条数据整合为训练集,将30条数据整合为测试集. iris.csv下载 程序 import csv import os import numpy as np '''将iris.csv中的数据分成train_iris和test_iris两个csv文件,其中t

关于训练集,验证集,测试集的划分

首先需要说明的是:训练集(training set).验证集(validation set)和测试集(test set)本质上并无区别,都是把一个数据集分成三个部分而已,都是(feature, label)造型.尤其是训练集与验证集,更无本质区别.测试集可能会有一些区别,比如在一些权威计算机视觉比赛中,测试集的标签是private的,也就是参赛者看不到测试集的标签,可以把预测的标签交给大赛组委会,他们根据你提交的预测标签来评估参赛者模式识别系统的好坏,以防作弊. 通常,在训练有监督的机器学习模型

将数据划分为训练集和测试集;缩放特征区间

导入葡萄酒数据: 1 import numpy as np 2 import pandas as pd 3 4 df_wine = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data", header=None) 5 df_wine.columns = ["class label", "alcohol", 6 "mal

sklearn——train_test_split 随机划分训练集和测试集

sklearn--train_test_split 随机划分训练集和测试集 sklearn.model_selection.train_test_split随机划分训练集和测试集 官网文档:http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html 一般形式: train_test_split是交叉验证中常用的函数,功能是从样本中随机的按比例选取train data和

sklearn获得某个参数的不同取值在训练集和测试集上的表现的曲线刻画

from sklearn.svm import SVC from sklearn.datasets import make_classification import numpy as np X,y = make_classification() def plot_validation_curve(estimator,X,y,param_name="gamma", param_range=np.logspace(-6,-1,5),cv=5,scoring="accuracy&

AI - MLCC06 - 训练集和测试集 (Training and Test Sets)

原文链接:https://developers.google.com/machine-learning/crash-course/training-and-test-sets 1- 拆分数据 可将单个数据集拆分为一个训练集和一个测试集. 训练集 - 用于训练模型的子集. 测试集 - 用于测试训练后模型的子集. 训练集的规模越大,模型的学习效果越好.测试集规模越大,对于评估指标的信心越充足,置信区间就越窄.在创建一个能够很好地泛化到新数据模型的过程中,测试集充当了新数据的代理. 拆分数据的一些注意

如何把数据集划分成训练集和测试集

本文内容来自周志阳<机器学习> 问题: 对于一个只包含\(m\)个样例的数据集\(D=\{(x_1,y_1),(x_2,y_2),\cdots,(x_m,y_m)\),如何适当处理,从\(D\)中产生训练集\(S\)和测试集\(T\)? 下面介绍三种常见的做法: 留出法 交叉验证法 自助法 留出法(hold-out) 留出法直接将数据集\(D\)划分为两个互斥的集合,其中一个集合作为训练集\(S\),留下的集合作为测试集\(T\),即\(D=S \cup T, S \cap T=\emptys

python 将数据随机分为训练集和测试集

# -*- coding: utf-8 -*- """ Created on Tue Jun 23 15:24:19 2015 @author: hd """ from sklearn import cross_validation c = [] j=0 filename = r'C:\Users\hd\Desktop\bookmarks\bookmarks.arff' out_train = open(r'C:\Users\hd\Desktop

Python数据预处理—训练集和测试集数据划分

使用sklearn中的函数可以很方便的将数据划分为trainset 和 testset 该函数为sklearn.cross_validation.train_test_split,用法如下: >>> import numpy as np >>> from sklearn.cross_validation import train_test_split >>> X, y = np.arange(10).reshape((5, 2)), range(5)