模型评估与改进(学习记录)

引入

数据集创建

函数:sklearn.datasets.make_blobs()

x,y = sklearn.datasets.make_blobs(n_samples=100, n_features=2, centers=3, cluster_std=1.0, center_box=(-10.0, 10.0), shuffle=True, random_state=None)
# n_samples: (default=100) 样本数目
# n_features: (default=2) 每个样本的特征数
# center: (default=3)  样本的类别数
# cluster_std: (default=1.0) 每个类别的方差(限制每个类不同方差用列表存储)
# center_box: (default=(-10.0, 10.0)) 每个类别的边界
# shuffle:(default=True)
# random_state: (default=None) 随机数种子

数据集分组

函数:sklearn.model_selection.train_test_split()

X_train,X_test, y_train, y_test =cross_validation.train_test_split(train_data,train_target,test_size=0.3, random_state=0)
train_data:样本特征集
train_target:样本结果集
test_size:样本占比,整数是测试集的数量,浮点数(0,1)为测试集占比
random_state:是随机数的种子

简单练习

from sklearn.datasets import make_blobs
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import  train_test_split

X,y = make_blobs(random_state=0)
X_train, X_test, y_train, y_test = train_test_split(X,y,random_state=0)
logreg = LogisticRegression().fit(X_train,y_train)

print("Test set score:{:.2f}".format(logreg.score(X_test,y_test)))

交叉验证

简单实现

概述:
交叉验证(cross-validation)是一种评估泛化性能的统计学方法,它比单次划分训练集和测试集的方法更加稳定、全面。在交叉验证中,数据被多次划分,并且需要训练多个模型。 最常用的交叉验证是 k 折交叉验证(k-fold cross-validation),其中 $k$ 是由用户指定的数字, 通常取 5 或 10。在执行 5 折交叉验证时,首先将数据划分为(大致)相等的 5 部分,每一 部分叫作折(fold)。接下来训练一系列模型。使用第 1 折作为测试集、其他折(2~5)作 为训练集来训练第一个模型。利用 2~5 折中的数据来构建模型,然后在 1 折上评估精度。 之后构建另一个模型,这次使用 2 折作为测试集,1、3、4、5 折中的数据作为训练集。利 用 3、4、5 折作为测试集继续重复这一过程。对于将数据划分为训练集和测试集的这 5 次 划分,每一次都要计算精度。最后我们得到了 5 个精度值。

函数:sklearn.model_selection.cross_val_score()

score = sklearn.model_selection.cross_val_score(estimator, X, y=None, groups=None, scoring=None, cv=None, n_jobs=1, verbose=0, fit_params=None, pre_dispatch=‘2*n_jobs’)
# estimator: 模型
# X: 样本特征集
# y: 样本结果集
# groups: 如果数据需要分组采样使用(后面优化第四部使用)
# scoring: 评价方法
# cv: 分层数,默认为3,推荐5或10

对k层的的评分求均值得最终评分。

score.mean()

简单练习

from sklearn.model_selection import cross_val_score 
from sklearn.datasets import load_iris 
from sklearn.linear_model import LogisticRegression

iris = load_iris()
logreg = LogisticRegression()
scores = cross_val_score(logreg,iris.data,iris.target,cv=5)
print("Cross-validation scores: {}".format(scores.mean()))

优化

1. 打乱顺序交叉验证

KFold分离器类: 将数据按照特定要求进行划分

函数:sklearn.model_selection.KFold()

sklearn.model_selection.KFold(n_splits=3, shuffle=False, random_state=None)
# n_splits: 数据划分几等份
# shuffle: 是否打乱顺序
# random_state: 随机数种子

简单练习

from sklearn.model_selection import KFold 
from sklearn.model_selection import cross_val_score 
from sklearn.datasets import load_iris 
from sklearn.linear_model import LogisticRegression

iris = load_iris()
logreg = LogisticRegression()
kfold = KFold(n_splits=3,shuffle=True,random_state=0)
scores = cross_val_score(logreg, iris.data, iris.target, cv=kfold)
print("Cross-validation scores:\n{}".format(scores))

2. 留一法交叉验证

留一法:每次只取样本中的一个作为测试集,当有 $K$ 个样本,即要训练 $k$ 次。

函数: sklearn.model_selection.LeaveOneOut()

简单练习

from sklearn.model_selection import cross_val_score 
from sklearn.datasets import load_iris 
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import LeaveOneOut 

iris = load_iris()
logreg = LogisticRegression()
loo = LeaveOneOut() 
scores = cross_val_score(logreg, iris.data, iris.target, cv=loo) 
print("Number of cv iterations: ", len(scores)) 
print("Mean accuracy: {:.2f}".format(scores.mean()))

3. 打乱顺序交叉验证

函数:sklearn.model_selection.ShuffleSplit()

sklearn.model_selection.ShuffleSplit(n_splits=10, test_size=’default’, train_size=None,random_state=None)
# n_splits: 划分组数
# test_size: 测试集的占比
# train_size: 验证集的占比
# random_state: 随机数种子

ShuffleSplit和KFold区别:
KFold是划分 $k$ 份取一份作为测试集,其余作为训练集。
ShuffleSplit是划分 $k$ 份取规定数目作为测试集和训练集,相对比KFold更为灵活。

简单练习

from sklearn.model_selection import cross_val_score 
from sklearn.datasets import load_iris 
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import ShuffleSplit

iris = load_iris()
logreg = LogisticRegression()
shuffle_split = ShuffleSplit(test_size=.5, train_size=.5, n_splits=10) 
scores = cross_val_score(logreg, iris.data, iris.target, cv=shuffle_split) 
print("Cross-validation scores:\n{}".format(scores))

4.分组交叉验证

当样本中存在高度相关的数据,为了避免训练集和验证集存在相关性而误判模型的准确性,需要将相关的数据进行分组。

函数:sklearn.model_selection.GroupKFold()

sklearn.model_selection.GroupKFold(n_splits=3)
# n_splits: 划分折数

简单练习:

from sklearn.model_selection import GroupKFold 
import mglearn
X, y = make_blobs(n_samples=12, random_state=0) 
groups = [0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3] 
scores = cross_val_score(logreg, X, y, groups, cv=GroupKFold(n_splits=3)) 
print("Cross-validation scores:\n{}".format(scores))
mglearn.plots.plot_group_kfold()

分组后,同一组的数据不可能同时出现在训练集和测试集中!

网格搜索

简单网格搜索

概述:
模型的拟合优性往往取决于在构建模型时人工设定的模型参数,为了训练出合适的模型,我们需要不断更改模型参数,选取评分最高的模型。

注意: 在验证不同参数的评分时,不能只将数据划分为训练集和测试集,因为通过比较测试集的分数来确定模型的拟合性存在数据泄露问题

正确做法应该是将数据划分为训练集、验证集和测试集。
先用训练集和验证集找到合适的模型参数,再用训练集、验证集和模型参数重新建立模型,用测试集计算模型评分。

简单练习

from sklearn.model_selection import GroupKFold 
import mglearn
X, y = make_blobs(n_samples=12, random_state=0) 
groups = [0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3] 
scores = cross_val_score(logreg, X, y, groups, cv=GroupKFold(n_splits=3)) 
print("Cross-validation scores:\n{}".format(scores))
mglearn.plots.plot_group_kfold()
#%%
from sklearn.datasets import load_iris 
from sklearn.svm import SVC 

iris = load_iris()
# 将数据划分为训练+验证集与测试集 
X_trainval, X_test, y_trainval, y_test = train_test_split(iris.data, iris.target, random_state=0) 
# 将训练+验证集划分为训练集与验证集 
X_train, X_valid, y_train, y_valid = train_test_split(X_trainval, y_trainval, random_state=1) 
print("Size of training set: {}   size of validation set: {}   size of test set:" 
      " {}\n".format(X_train.shape[0], X_valid.shape[0], X_test.shape[0]))  

best_score = 0 

for gamma in [0.001, 0.01, 0.1, 1, 10, 100]: 
    for C in [0.001, 0.01, 0.1, 1, 10, 100]: 
        # 对每种参数组合都训练一个SVC 
        svm = SVC(gamma=gamma, C=C) 
        svm.fit(X_train, y_train) 
        # 在验证集上评估SVC 
        score = svm.score(X_valid, y_valid) 
        # 如果我们得到了更高的分数,则保存该分数和对应的参数 
        if score > best_score: 
            best_score = score 
            best_parameters = {'C': C, 'gamma': gamma} 
            
# 在训练+验证集上重新构建一个模型,并在测试集上进行评估 
svm = SVC(**best_parameters) 
svm.fit(X_trainval, y_trainval) 
test_score = svm.score(X_test, y_test) 
print("Best score on validation set: {:.2f}".format(best_score)) 
print("Best parameters: ", best_parameters) 
print("Test set score with best parameters: {:.2f}".format(test_score))

交叉验证的网格搜索

函数:sklearn.model_selection.GridSearchCV()

class sklearn.model_selection.GridSearchCV(estimator, param_grid, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch=‘2*n_jobs’, error_score=’raise’, return_train_score=’warn’)
# estimator: 训练的模型
# param_grid: 参数取值,值为字典类型或列表类型
# scoring:模型评判标准
# cv: 交叉验证对折数,默认为3

GridSearchCV()可以直接在训练集中通过交叉验证的方法直接寻找到最佳参数,所以只需将数据划分为训练集和测试集,将训练集数据放入GridSearchCV()即可拟合最优模型,再将测试集数据放入模型中进行评分。

函数方法:

grid_search = GridSearchCV() 
grid_search.score(X_test, y_test) # 测试集对模型评分
grid_search.best_params_  # 模型最佳参数
grid_search.best_score_ # 模型训练集最佳参数下的评分
grid_search.best_estimator_ # 模型的所有参数

简单练习

from sklearn.datasets import load_iris 
from sklearn.model_selection import GridSearchCV 
from sklearn.svm import SVC 
iris = load_iris()
# 构建不同参数的字典
param_grid = {'C': [0.001, 0.01, 0.1, 1, 10, 100], 
              'gamma': [0.001, 0.01, 0.1, 1, 10, 100]} 
grid_search = GridSearchCV(SVC(), param_grid, cv=5)
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=0)
grid_search.fit(X_train, y_train)
print("Test set score: {:.2f}".format(grid_search.score(X_test, y_test)))
print("Best parameters: {}".format(grid_search.best_params_)) 
print("Best cross-validation score: {:.2f}".format(grid_search.best_score_))
print("Best estimator:\n{}".format(grid_search.best_estimator_))

评估指标与评分

二分类指标

真反率(TN):被模型预测为负的负样本
假反率(FN):被模型预测为负的正样本
真正率(TP):被模型预测为正的正样本
假正率(FP):被模型预测为正的负样本

混淆矩阵:

- 预测为反 预测为正
反类 TN FP
正类 FN TP

函数: sklearn.metrics.confusion_matrix() 构造混淆矩阵

sklearn.metrics.confusion_matrix(y_true, y_pred, labels=None, sample_weight=None)
# y_true: 样本真实值
# y_pred: 样本预测值
# lebels: 类别
# sample_weight: 样本权重

精度: 正确预测的数量处以样本数
$$ Accuracy = \frac {TP+TN}{TP+TN+FP+FN} $$

准确率: 被预测为正的样本中,正样本的个数
$$ Precision = \frac {TP}{TP+FP} $$

召回率: 正样本中有有多少被成功预测
$$ Recall = \frac {TP}{TP+FN} $$

f-score: 准确率和召回率的调和平均
$$ F = 2 × \frac {Precision × Recall}{Precision + Recall} $$

函数: sklearn.metrics.classification_report() 输出分类指标信息

sklearn.metrics.classification_report()
y_true:样本真实值。
y_pred:样本估计值
labels:array,shape = [n_labels],报表中包含的标签索引的可选列表。
target_names:字符串列表,与标签匹配的可选显示名称(相同顺序)。
sample_weight:类似于shape = [n_samples]的数组,可选项,样本权重。
digits:int,输出浮点值的位数.

函数: sklearn.metrics.precision_recall_curve 构造准确性-召回曲线

from sklearn.metrics import precision_recall_curve 
precision, recall, thresholds = precision_recall_curve(y_test, svc.decision_function(X_test))
# 返回一个列表

通过计算曲线下的面积即可计算平均准确率。

你可能感兴趣的:(列表,python,机器学习,深度学习,人工智能)