Skip to content

Latest commit

 

History

History
165 lines (128 loc) · 9.58 KB

模型评估与改进.md

File metadata and controls

165 lines (128 loc) · 9.58 KB
# 加载数据集
import mglearn
X, y = mglearn.datasets.make_forge()
from sklearn.datasets import load_iris
iris_dataset = load_iris()
iris_dataset.keys()
iris_dataset['target_names']
iris_dataset.data
iris_datasrt.target

# 拆分数据集,成训练集和测试集 train_test_split(数据, 标签, 随机态(可保证获得同样的随机样本))
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(iris_dataset['data'],  			                                                       iris_dataset['target'],                                                                 random_state=0)

# KNN
from sklearn.neighbors import KNeighborsClassifier
from sklearn.neighbors import KNeighborsRegressor
knn = KNeighborsClassifier(n_neighbors=1)

# 线性回归
from sklearn.linear_model import LinearRegression
# 岭回归 L2正则化,系数w尽可能小 参数alpha 值越小,泛化越好,w越小
from sklearn.linear_model import Ridge
# L1正则化线性回归 某些系数刚好为0,模型忽略某些特征 参数:alpha正则参数, max_iter迭代次数
from sklearn.linear_model import Lasso
# 逻辑回归, 分类  正则强度参数C
from sklearn.linear_model import LogisticRegression
# SVM线性支持向量机 正则强度参数C
from sklearn.svm import LinearSVC
# 优点、 缺点和参数
#  线性模型的主要参数是正则化参数,在回归模型中叫作 alpha,在 LinearSVC 和 LogisticRegression 中叫作 C。 alpha 值较大或 C 值较小,说明模型比较简单。特别是对于回归模型而言,调节这些参数非常重要。通常在对数尺度上对 C 和 alpha 进行搜索。你还需要确定的是用 L1 正则化还是 L2 正则化。如果你假定只有几个特征是真正重要的,那么你应该用L1 正则化,否则应默认使用 L2 正则化。如果模型的可解释性很重要的话,使用 L1 也会有帮助。由于 L1 只用到几个特征,所以更容易解释哪些特征对模型是重要的,以及这些特征的作用。
#  线性模型的训练速度非常快,预测速度也很快。这种模型可以推广到非常大的数据集,对稀疏数据也很有效。如果你的数据包含数十万甚至上百万个样本,你可能需要研究如何使用 LogisticRegression 和 Ridge 模型的 solver='sag' 选项,在处理大型数据时,这一选项比默认值要更快。其他选项还有 SGDClassifier 类和 SGDRegressor 类,它们对本节介绍的线性模型实现了可扩展性更强的版本。
#  线性模型的另一个优点在于,利用我们之间见过的用于回归和分类的公式,理解如何进行预测是相对比较容易的。不幸的是,往往并不完全清楚系数为什么是这样的。如果你的数据集中包含高度相关的特征,这一问题尤为突出。在这种情况下,可能很难对系数做出解释。如果特征数量大于样本数量,线性模型的表现通常都很好。它也常用于非常大的数据集,只是因为训练其他模型并不可行。但在更低维的空间中,其他模型的泛化性能可能更好。

模型评估与改进

交叉验证

k 折交叉验证(k-fold cross-validation)

​ 其中 k 是由用户指定的数字,通常取 5 或 10。在执行 5 折交叉验证时,首先将数据划分为(大致)相等的 5 部分,每一部分叫作折(fold)。接下来训练一系列模型。使用第 1 折作为测试集、其他折(25)作为训练集来训练第一个模型。利用 25 折中的数据来构建模型,然后在 1 折上评估精度。之后构建另一个模型,这次使用 2 折作为测试集, 1、 3、 4、 5 折中的数据作为训练集。利用 3、 4、 5 折作为测试集继续重复这一过程。对于将数据划分为训练集和测试集的这 5 次划分,每一次都要计算精度。最后我们得到了 5 个精度值

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))
print("Average cross-validation score: {:.2f}".format(scores.mean()))

折与折之间的精度有较大的变化 ,这可能意味着模型强烈依赖于将某个折用于训练,但也可能只是因为数据集的数据量太小

缺点:

[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2]

如果分类标签如上,简单的k折交叉验证便失效了,可以使用分层k折交叉验证

分层k折交叉验证 (stratified k-fold cross-validation)

在分层交叉验证中,我们划分数据,使每个折中类别之间的比例与整个数据集中的比例相同

交叉验证分离器(cross-validation splitter)

from sklearn.model_selection import KFold
kfold = KFold(n_splits=3, shuffle=True, random_state=0) # shuffle随机打乱
print("Cross-validation scores:\n{}".format(
cross_val_score(logreg, iris.data, iris.target, cv=kfold)))

留一法交叉验证

适合小型数据集

from sklearn.model_selection import LeaveOneOut
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()))

打乱划分交叉验证

每次划分为训练集取样 train_size 个点,为测试集取样 test_size 个(不相交的)点。将这一划分方法重复 n_iter 次 (你可以将 train_size和 test_size 设为整数来表示这两个集合的绝对大小,也可以设为浮点数来表示占整个数据集的比例)

from sklearn.model_selection import ShuffleSplit
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))

分组交叉验证

适用于数据中的分组高度相关时。比如你想构建一个从人脸图片中识别情感的系统,并且收集了 100 个人的照片的数据集,其中每个人都进行了多次拍摄,分别展示了不同的情感。我们的目标是构建一个分类器,能够正确识别未包含在数据集中的人的情感。你可以使用默认的分层交叉验证来度量分类器的性能。但是这样的话,同一个人的照片可能会同时出现在训练集和测试集中。对于分类器而言,检测训练集中出现过的人脸情感比全新的人脸要容易得多。因此,为了准确评估模型对新的人脸的泛化能力,我们必须确保训练集和测试集中包含不同人的图像。

使用 GroupKFold,它以 groups 数组作为参数,可以用来说明照片中对应的是哪个人。这里的 groups 数组表示数据中的分组,在创建训练集和测试集的时候不应该将其分开,也不应该与类别标签弄混。

from sklearn.model_selection import GroupKFold
# 创建模拟数据集
X, y = make_blobs(n_samples=12, random_state=0)
# 假设前3个样本属于同一组,接下来的4个属于同一组,以此类推
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))

dataset -> train, test

train -> 交叉验证

test -> 最终测试

网格搜索

scikit-learn 提 供 了GridSearchCV 类,它以估计器(estimator)的形式实现了这种方法。要使用 GridSearchCV 类,你首先需要用一个字典指定要搜索的参数。然后 GridSearchCV 会执行所有必要的模型拟合。字典的键是我们要调节的参数名称(在构建模型时给出,在这个例子中是 C 和gamma),字典的值是我们想要尝试的参数设置。如果 C 和 gamma 想要尝试的取值为 0.001、0.01、 0.1、 1、 10 和 100,可以将其转化为下面这个字典:

param_grid = {'C': [0.001, 0.01, 0.1, 1, 10, 100],
'gamma': [0.001, 0.01, 0.1, 1, 10, 100]}
print("Parameter grid:\n{}".format(param_grid))
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
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_)) #最佳参数对应的模型

“条件”(conditional)参数, GridSearchCV 的 param_grid 可以是字典组成的列表(a list of dictionaries)。列表中的每个字典可扩展为一个独立的网格

评估指标与评分

# 混淆矩阵
from sklearn.metrics import confusion_matrix
confusion = confusion_matrix(y_test, pred_logreg)
print("Confusion matrix:\n{}".format(confusion))
TN FP
FN TP
from sklearn.metrics import f1_score
from sklearn.metrics import classification_report
# 准确率-召回曲线
from sklearn.metrics import precision_recall_curve
precision, recall, thresholds = precision_recall_curve(
y_test, svc.decision_function(X_test))