0%

机器学习笔记——模型评估

模型评估

衡量模型的泛化能力通过模型评估方法获取具体的评价指标。在模型评估中,要对数据集进行划分,数据集划分通常要保证两个条件:

  • 训练集和测试集的分布要与样本真实分布一致,即训练集和测试集都要保证是从样本真实分布中独立同分布采样而得;
  • 训练集和测试集要互斥,即两个子集之间没有交集。

基于划分方式的不同,评估方法可以分为:留出法,交叉验证法及自助法;

1. 留出法

直接将数据集D划分为两个相斥的集合,其中一个集合作为训练集S,另一个作为测试集T,即D=S∪T,S∩T=∅。在S上训练出模型后,用T来评估其测试误差,作为泛化误差的估计。适用于大数据量。

常见做法是将大约2/3~4/5的样本用于训练,剩余样本用于测试。

根据《统计学习方法》中的观点:“如果给定的样本数据充足,进行模型选择的一种简单方法是随机地将数据集切分成三部分,分别为训练集(training set)、验证集(validation set)和测试集(test set)。训练集用来训练模型,验证集用来模型选择,而测试集用于最终对学习方法的评估。”

  • 如果数据集较小时,一般采用简单交叉验证的方法,即不设置验证集,而只设置训练集和测试集,根据西瓜书的观点,训练集和测试集的比例设置一般为2:1 ~ 4:1。目前大多数人将比例设置为7:3。
  • 如果数据量较大时(数据集以万为单位),一般训练集、验证集、测试集的分配比例为6:2:2。
  • 如果数据量更大时,例如百万级的数据集,一般划分比例在98:1:1以上(即根据情况再提高训练集的占比)。
2. 交叉验证法

先将数据集D划分为k个大小相同的互斥子集,即D=D1∪D2∪…∪Dk, Di∩Dj=∅(i≠j)。每个子集Di都尽可能保持数据分布的一致性,即从D中分层得到。然后每次用k-1个子集的并集作为训练集,余下的那个子集作为测试集;这样就可获得k组训练/测试集,从而可进行k次训练和测试,最终返回的是这k个测试结果的均值。通常把交叉验证法称为“k折交叉验证”,k最常用的取值是10、5、20。适用于中等数据量。

交叉验证本质上是要解决方差估计问题,是bias-var思想的一种实现。

交叉验证 sklearn.model_selection.cross_val_score()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import cross_val_score

k_range = [1, 5, 9, 15]
cv_scores = []
for k in k_range:
knn = KNeighborsClassifier(n_neighbors=k)
scores = cross_val_score(knn, X_train, y_train, cv=5)
cv_score = np.mean(scores)
print('k={},验证集上的准确率={:.3f}'.format(k, cv_score))
cv_scores.append(cv_score)

# k=1,验证集上的准确率=0.947
# k=5,验证集上的准确率=0.955
# k=9,验证集上的准确率=0.964
# k=15,验证集上的准确率=0.964
1
2
3
4
5
best_k = k_range[np.argmax(cv_scores)]
best_knn = KNeighborsClassifier(n_neighbors=best_k)
best_knn.fit(X_train, y_train)
print('测试集准确率:', best_knn.score(X_test, y_test))
# 测试集准确率:0.9736842105263158

网格搜索 sklearn.model_selection.GridSearchCV()

GridSearchCV根据给定的模型自动进行交叉验证,通过调节每一个参数来跟踪评分结果。

1
2
3
4
5
6
from sklearn.model_selection import GridSearchCV
from sklearn.tree import DecisionTreeClassifier

parameters = {'max_depth':[3, 5, 7, 9], 'min_samples_leaf': [1, 2, 3, 4]}
clf = GridSearchCV(DecisionTreeClassifier(), parameters, cv=5, scoring='accuracy')
clf.fit(X_train, y_train)
1
2
3
4
5
6
7
8
9
10
11
GridSearchCV(cv=5, error_score='raise',
estimator=DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
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=False, random_state=None,
splitter='best'),
fit_params=None, iid=True, n_jobs=1,
param_grid={'max_depth': [3, 5, 7, 9], 'min_samples_leaf': [1, 2, 3, 4]},
pre_dispatch='2*n_jobs', refit=True, return_train_score=True,
scoring='accuracy', verbose=0)
1
2
3
4
5
6
7
8
9
print('最优参数:', clf.best_params_)
print('验证集最高得分:', clf.best_score_)
# 最优参数:{'max_depth': 5, 'min_samples_leaf': 2}
# 验证集最高得分:0.9553571428571429

# 获取最优模型
best_model = clf.best_estimator_
print('测试集上准确率:', best_model.score(X_test, y_test))
# 测试集上准确率:0.9473684210526315
3. 自助法

给定包含m个样本的数据集D,对它进行采样产生D':每次随机从D中挑选一个样本,将其拷贝放入D',然后再将样本放回初始数据集D中,使得该样本在下次采样时仍有可能被采到;这个过程重复执行m次后,得到包含m个样本的数据集D'。将D'用作训练集,D-D∩D'用作测试集。

自助法常用于小数据量,因为其产生的数据集改变了初始数据集的分布,会引入估计偏差。

模型持久化(model persistence)

pickle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 使用pickle
import pickle
model_path1 = './trained_model1.pkl'

# 保存模型到硬盘
with open(model_path1, 'wb') as f:
pickle.dump(best_model, f)
# 加载保存的模型
with open(model_path1, 'rb') as f:
model = pickle.load(f)

# 预测
print('预测值为', model.predict([X_test[0, :]]))
print('真实值为', y_test[0])
# 预测值为[2]
# 真实值为2
joblib
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 使用joblib
from sklearn.externals import joblib

# 保存模型到硬盘
model_path2 = './trained_model2.pkl'
joblib.dump(best_model, model_path2)
# ['./trained_model2.pkl']

# 加载保存的模型
model = joblib.load(model_path2)

# 预测
print('预测值为', model.predict([X_test[0, :]]))
print('真实值为', y_test[0])
# 预测值为[2]
# 真实值为2
天生我材必有用,千金散尽还复来~
  • 本文作者: XTLei
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
-------------本文结束感谢您的阅读-------------