python机器学习算法与实战(用Python做科学计算工具篇)
python机器学习算法与实战(用Python做科学计算工具篇)测试集上的性能不能衡量过拟合(如上所述)在测试集上的表现回归模型也会出现此问题。在下文中,我们将另一个名为“决策树”的基于实例的模型拟合到我们之前介绍的波士顿房价数据集:>>>>>> from sklearn.datasets import load_boston >>> from sklearn.tree import DecisionTreeRegressor >>> data = load_boston() >>> clf = DecisionTreeRegressor().fit(data.data data.target) >>> predicted = clf.predict(data.data) >>> expected = data.target
所需基本库
- numpy
- scipy
- matplotlib
- 简介:问题设置
- 使用 scikit-learn 进行机器学习的基本原理
- 监督学习:手写数字的分类
- 监督学习:住房数据的回归
- 测量预测性能
- 无监督学习:降维和可视化
- 特征脸示例:链接 PCA 和 SVM
- 特征脸示例:链接 PCA 和 SVM
- 参数选择、验证和测试
6.5 . 测量预测性能6.5.1. K-neighbors 分类器的快速测试
在这里,我们将继续查看数字数据,但我们将切换到 K-Neighbors 分类器。K-neighbors 分类器是一个基于实例的分类器。K-neighbors 分类器根据参数空间中K个最近点的标签来预测未知点的标签。
>>>
>>> # Get the data
>>> from sklearn.datasets import load_digits
>>> digits = load_digits()
>>> X = digits.data
>>> y = digits.target
>>> # Instantiate and train the classifier
>>> from sklearn.neighbors import KNeighborsClassifier
>>> clf = KNeighborsClassifier(n_neighbors=1)
>>> clf.fit(X y)
KNeighborsClassifier(...)
>>> # Check the results using metrics
>>> from sklearn import metrics
>>> y_pred = clf.predict(X)
>>> print(metrics.confusion_matrix(y_pred y))
[[178 0 0 0 0 0 0 0 0 0]
[ 0 182 0 0 0 0 0 0 0 0]
[ 0 0 177 0 0 0 0 0 0 0]
[ 0 0 0 183 0 0 0 0 0 0]
[ 0 0 0 0 181 0 0 0 0 0]
[ 0 0 0 0 0 182 0 0 0 0]
[ 0 0 0 0 0 0 181 0 0 0]
[ 0 0 0 0 0 0 0 179 0 0]
[ 0 0 0 0 0 0 0 0 174 0]
[ 0 0 0 0 0 0 0 0 0 180]]
显然,我们找到了一个完美的分类器!但由于我们之前看到的原因,这是具有误导性的:分类器本质上“记住”了它已经看到的所有样本。为了真正测试这个算法的效果,我们需要尝试一些它还没有见过的样本。
回归模型也会出现此问题。在下文中,我们将另一个名为“决策树”的基于实例的模型拟合到我们之前介绍的波士顿房价数据集:
>>>
>>> from sklearn.datasets import load_boston
>>> from sklearn.tree import DecisionTreeRegressor
>>> data = load_boston()
>>> clf = DecisionTreeRegressor().fit(data.data data.target)
>>> predicted = clf.predict(data.data)
>>> expected = data.target
>>> plt.scatter(expected predicted)
<matplotlib.collections.PathCollection object at ...>
>>> plt.plot([0 50] [0 50] '--k')
[<matplotlib.lines.Line2D object at ...]
这里的预测再次看起来很完美,因为模型能够完美地记住训练集。
在测试集上的表现
测试集上的性能不能衡量过拟合(如上所述)
6.5.2. 正确的方法:使用验证集学习预测函数的参数并在相同的数据上对其进行测试是一个方法论错误:一个模型只会重复它刚刚看到的样本的标签,它会获得完美的分数,但无法预测任何有用的东西——看不见的数据。
为了避免过度拟合,我们必须定义两个不同的集合:
- 训练集 X_train y_train 用于学习预测模型的参数
- 用于评估拟合预测模型的测试集 X_test y_test
在 scikit-learn 中,可以使用以下 train_test_split()函数快速计算这样的随机分割:
>>>
>>> from sklearn import model_selection
>>> X = digits.data
>>> y = digits.target
>>> X_train X_test y_train y_test = model_selection.train_test_split(X y
... test_size=0.25 random_state=0)
>>> print("%r %r %r" % (X.shape X_train.shape X_test.shape))
(1797 64) (1347 64) (450 64)
现在我们在训练数据上进行训练,并在测试数据上进行测试:
>>>
>>> clf = KNeighborsClassifier(n_neighbors=1).fit(X_train y_train)
>>> y_pred = clf.predict(X_test)
>>> print(metrics.confusion_matrix(y_test y_pred))
[[37 0 0 0 0 0 0 0 0 0]
[ 0 43 0 0 0 0 0 0 0 0]
[ 0 0 43 1 0 0 0 0 0 0]
[ 0 0 0 45 0 0 0 0 0 0]
[ 0 0 0 0 38 0 0 0 0 0]
[ 0 0 0 0 0 47 0 0 0 1]
[ 0 0 0 0 0 0 52 0 0 0]
[ 0 0 0 0 0 0 0 48 0 0]
[ 0 0 0 0 0 0 0 0 48 0]
[ 0 0 0 1 0 1 0 0 0 45]]
>>> print(metrics.classification_report(y_test y_pred))
precision recall f1-score support
0 1.00 1.00 1.00 37
1 1.00 1.00 1.00 43
2 1.00 0.98 0.99 44
3 0.96 1.00 0.98 45
4 1.00 1.00 1.00 38
5 0.98 0.98 0.98 48
6 1.00 1.00 1.00 52
7 1.00 1.00 1.00 48
8 1.00 1.00 1.00 48
9 0.98 0.96 0.97 47
avg / total 0.99 0.99 0.99 450
平均 f1 分数通常用作衡量算法整体性能的便捷指标。它出现在分类报告的最后一行;也可以直接访问:
>>>
>>> metrics.f1_score(y_test y_pred average="macro")
0.991367...
我们之前看到的过拟合可以通过计算训练数据本身的 f1-score 来量化:
>>>
>>> metrics.f1_score(y_train clf.predict(X_train) average="macro")
1.0
回归指标在回归模型的情况下,我们需要使用不同的指标,例如解释方差。
6.5.3. 通过验证选择模型我们已将高斯朴素、支持向量机和 K-最近邻分类器应用于数字数据集。现在我们已经有了这些验证工具,我们可以定量地询问三个估计器中哪一个最适合这个数据集。
- 使用每个估计器的默认超参数,在验证集上给出最好的 f1 分数?回想一下,超参数是实例化分类器时设置的参数:例如,n_neighbors在clf = KNeighborsClassifier(n_neighbors=1)
from sklearn.naive_bayes import GaussianNB
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import LinearSVC
X = digits.data
y = digits.target
X_train X_test y_train y_test = model_selection.train_test_split(X y
test_size=0.25 random_state=0)
for Model in [GaussianNB KNeighborsClassifier LinearSVC]:
clf = Model().fit(X_train y_train)
y_pred = clf.predict(X_test)
print('%s: %s' %
(Model.__name__ metrics.f1_score(y_test y_pred average="macro")))
- 对于每个分类器,超参数的哪个值可以为数字数据提供最佳结果?对于LinearSVC,使用 loss='l2'和loss='l1'。因为 KNeighborsClassifier我们使用 n_neighbors1 到 10。请注意, GaussianNB它没有任何可调整的超参数。
LinearSVC(loss='l1'): 0.930570687535
LinearSVC(loss='l2'): 0.933068826918
-------------------
KNeighbors(n_neighbors=1): 0.991367521884
KNeighbors(n_neighbors=2): 0.984844206884
KNeighbors(n_neighbors=3): 0.986775344954
KNeighbors(n_neighbors=4): 0.980371905382
KNeighbors(n_neighbors=5): 0.980456280495
KNeighbors(n_neighbors=6): 0.975792419414
KNeighbors(n_neighbors=7): 0.978064579214
KNeighbors(n_neighbors=8): 0.978064579214
KNeighbors(n_neighbors=9): 0.978064579214
KNeighbors(n_neighbors=10): 0.975555089773
from sklearn import model_selection datasets metrics
from sklearn.svm import LinearSVC
from sklearn.naive_bayes import GaussianNB
from sklearn.neighbors import KNeighborsClassifier
digits = datasets.load_digits()
X = digits.data
y = digits.target
X_train X_test y_train y_test = model_selection.train_test_split(X y
test_size=0.25 random_state=0)
for Model in [LinearSVC GaussianNB KNeighborsClassifier]:
clf = Model().fit(X_train y_train)
y_pred = clf.predict(X_test)
print('%s: %s' %
(Model.__name__ metrics.f1_score(y_test y_pred average="macro")))
print('------------------')
# test SVC loss
for loss in ['l1' 'l2']:
clf = LinearSVC(loss=loss).fit(X_train y_train)
y_pred = clf.predict(X_test)
print("LinearSVC(loss='{0}'): {1}".format(loss
metrics.f1_score(y_test y_pred average="macro")))
print('-------------------')
# test the number of neighbors
for n_neighbors in range(1 11):
clf = KNeighborsClassifier(n_neighbors=n_neighbors).fit(X_train y_train)
y_pred = clf.predict(X_test)
print("KNeighbors(n_neighbors={0}): {1}".format(n_neighbors
metrics.f1_score(y_test y_pred average="macro")))
6.5.4. 交叉验证
交叉验证包括重复地将数据拆分为成对的训练集和测试集,称为“折叠”。Scikit-learn 带有一个功能,可以自动计算所有这些折叠的分数。这里我们 KFold使用 k=5。
>>>
>>> clf = KNeighborsClassifier()
>>> from sklearn.model_selection import cross_val_score
>>> cross_val_score(clf X y cv=5)
array([0.9478022 0.9558011 0.96657382 0.98039216 0.96338028])
我们可以使用不同的分裂策略,比如随机分裂:
>>>
>>> from sklearn.model_selection import ShuffleSplit
>>> cv = ShuffleSplit(n_splits=5)
>>> cross_val_score(clf X y cv=cv)
array([...])
scikit-learn 中存在许多不同的交叉验证策略 。它们通常对于考虑非 iid 数据集很有用。
6.5.5. 交叉验证的超参数优化考虑正则化线性模型,例如使用 l2正则化的Ridge Regression和使用 l1 正则化的Lasso Regression 。选择它们的正则化参数很重要。
让我们在糖尿病数据集上设置这些参数,这是一个简单的回归问题。糖尿病数据包括 442 名患者的 10 个生理变量(年龄、性别、体重、血压)测量值,以及一年后疾病进展的指标:
>>>
>>> from sklearn.datasets import load_diabetes
>>> data = load_diabetes()
>>> X y = data.data data.target
>>> print(X.shape)
(442 10)
使用默认超参数:我们计算交叉验证分数:
>>>
>>> from sklearn.linear_model import Ridge Lasso
>>> for Model in [Ridge Lasso]:
... model = Model()
... print('%s: %s' % (Model.__name__ cross_val_score(model X y).mean()))
Ridge: 0.409427438303
Lasso: 0.353800083299
基本超参数优化
我们将交叉验证分数计算为 alpha 的函数,即 和 的正则化Lasso 强度Ridge。我们在 0.0001 和 1 之间选择 20 个 alpha 值:
>>>
>>> alphas = np.logspace(-3 -1 30)
>>> for Model in [Lasso Ridge]:
... scores = [cross_val_score(Model(alpha) X y cv=3).mean()
... for alpha in alphas]
... plt.plot(alphas scores label=Model.__name__)
[<matplotlib.lines.Line2D object at ...
sklearn.grid_search.GridSearchCV由估计器以及要搜索的参数值字典构成。我们可以通过这种方式找到最佳参数:
>>>
>>> from sklearn.grid_search import GridSearchCV
>>> for Model in [Ridge Lasso]:
... gscv = GridSearchCV(Model() dict(alpha=alphas) cv=3).fit(X y)
... print('%s: %s' % (Model.__name__ gscv.best_params_))
Ridge: {'alpha': 0.062101694189156162}
Lasso: {'alpha': 0.01268961003167922}
内置超参数搜索
对于 scikit-learn 中的某些模型,可以在大型数据集上更有效地执行交叉验证。在这种情况下,包含特定模型的交叉验证版本。和 的交叉验证版本分别是 Ridge和 。可以按如下方式对这些估计器进行参数搜索:LassoRidgeCVLassoCV
>>>
>>> from sklearn.linear_model import RidgeCV LassoCV
>>> for Model in [RidgeCV LassoCV]:
... model = Model(alphas=alphas cv=3).fit(X y)
... print('%s: %s' % (Model.__name__ model.alpha_))
RidgeCV: 0.0621016941892
LassoCV: 0.0126896100317
我们看到结果与 GridSearchCV 返回的结果相匹配
嵌套交叉验证我们如何衡量这些估计器的性能?我们已经使用数据来设置超参数,所以我们需要在实际的新数据上进行测试。我们可以通过cross_val_score() 在我们的 CV 对象上运行来做到这一点。这里有 2 个交叉验证循环正在进行,这称为“嵌套交叉验证”:
for Model in [RidgeCV LassoCV]:
scores = cross_val_score(Model(alphas=alphas cv=3) X y cv=3)
print(Model.__name__ np.mean(scores))
请注意,这些结果与我们上面曲线的最佳结果不匹配,并且LassoCV似乎表现不佳RidgeCV。原因是 Lasso 的超参数设置比较困难,因此该超参数的估计误差较大。
因此该超参数的估计误差较大。
相关文章:
- 用Python做科学计算(工具篇)——scikit-learn(机器学习)4
- 用Python做科学计算(工具篇)——scikit-learn(机器学习)3
- 用Python做科学计算(工具篇)——scikit-learn(机器学习)2
- 用Python做科学计算(工具篇)——scikit-learn(机器学习)1
- 用Python做科学计算——matplotlib绘图实例
- 用Python做科学计算(工具篇)——sympy使用指南(符号运算)
- 用Python做科学计算(工具篇)——scipy 使用指南
- 用Python做科学计算(工具篇)——1.1. NumPy 数组对象
- 用Python做科学计算(工具篇)——numpy1.2.数组的数值运算
- 用Python做科学计算(工具篇)——numpy1.4 高级操作
- 用Python做科学计算(工具篇)——numpy1.3 更精细的数组