CV.py
# Load libraries
from sklearn import datasets
from sklearn import metrics
from sklearn.model_selection import KFold, cross_val_score
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
# 加载手写数字数据集
digits = datasets.load_digits()
# 特征矩阵
features = digits.data
# 目标向量
target = digits.target
# 标准化
standardizer = StandardScaler()
# 逻辑回归
logit = LogisticRegression()
# 复合估计器
pipeline = make_pipeline(standardizer, logit)
# 创建KFold cv
kf = KFold(n_splits=10, shuffle=True, random_state=1)
# 执行 k-fold cross-validation
cv_results = cross_val_score(pipeline, # Pipeline
features, # Feature matrix
target, # Target vector
cv=kf, # Cross-validation technique
scoring="accuracy", # Loss function
n_jobs=-1) # Use all CPU scores
# 计算平均值
print(cv_results.mean())
我们的目标不是评估模型在我们的训练数据上的表现如何,而是它在从未见过的数据(例如,新客户、新犯罪、新图像)上的表现如何。出于这个原因,我们的评估方法应该帮助我们了解模型能够如何从他们从未见过的数据中做出预测。
一种策略可能是推迟一部分数据进行测试。这称为验证(或保留)。
更好的策略:KFCV —— k重交叉验证
在 KFCV 中,我们将数据分成 k 个部分,称为“折叠”。 然后使用 k – 1 折对模型进行训练——合并为一个训练集——然后将最后一个折用作测试集.
我们重复这 k 次,每次使用不同的折叠作为测试集。 然后对每个 k 次迭代的模型性能进行平均以产生整体测量。
在案例中,我们使用了10折进行KFCV,并将结果输出到cv_results
# 查看结果
print(cv_results)
KFCV的三个要点:
IID:首先,KFCV 假设每个观察都是独立于另一个创建的(即数据是独立同分布). 如果数据是独立同分布的,那么在分配给折叠时打乱观察是个好主意。 在 scikit-learn
中,我们可以设置shuffle=True
来执行洗牌。
通常在k个folder中,每个类所占的百分比基本相同。在 scikit-learn
中,我们可以通过将 KFold
类替换为 StratifiedKFold
来进行分层 k 折交叉验证。
当我们使用验证集或交叉验证时,重要的是基于训练集预处理数据,然后将这些转换应用于训练集和测试集。如,当我们进行标准化时,我们只计算训练集的均值和方差(fit)。 然后我们将该StandardScaler
(transform)到应用于训练集和测试集:
# Import library
from sklearn.model_selection import train_test_split
# 创建测试集和训练集
features_train, features_test, target_train, target_test = train_test_split(
features, target, test_size=0.1, random_state=1)
# Fit 训练集,不运用到测试集
standardizer.fit(features_train)
# transform 训练集和测试集
features_train_std = standardizer.transform(features_train)
features_test_std = standardizer.transform(features_test)
这样做的原因是因为我们假装测试集是未知数据。如果我们使用来自训练集和测试集的观察来拟合我们的预处理器,则来自测试集的一些信息会泄漏到我们的训练集中。此规则适用于任何预处理步骤,例如特征选择。
scikit-learn’s pipeline
package:
pipeline
包很容易做到上述第三点,首先我们创建一个pipeline;
然后我们使用该管道运行 KFCV,scikit 为我们完成所有工作;
# 创建 pipeline
pipeline = make_pipeline(standardizer, logit)
# Do k-fold cross-validation scikit 为我们完成所有工作
cv_results = cross_val_score(pipeline, # 管道
features, # 特征矩阵
target, # 目标向量
cv=kf, # CV 采用的方法,这里是KFolder
scoring="accuracy", # 损失函数,这里是准确度
n_jobs=-1) # 使用所有CPU来评估,如果是正数并行的数量
cross_val_score 带有三个值得注意的参数
cv 决定了我们的交叉验证技术。常用的有:KFold、LeaveOneOut
文档:3.3. Metrics and scoring: quantifying the quality of predictions — scikit-learn 1.1.1 documentation
DummyRegressor
dummyRegressorExample.py
# Load libraries
from sklearn.datasets import load_boston
from sklearn.dummy import DummyRegressor
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_california_housing
# 波士顿房价数据集被移除,换成fetch_california_housing
housing = fetch_california_housing()
# 特征矩阵、目标
features, target = housing.data, housing.target
# 分离测试集和训练集
features_train, features_test, target_train, target_test = train_test_split(
features, target, random_state=0)
# 创建一个DummyRegressor
dummy = DummyRegressor(strategy='mean')
# 训练它
dummy.fit(features_train, target_train)
# 得到R^2得分
print(dummy.score(features_test, target_test))
# Load library
from sklearn.linear_model import LinearRegression
# 训练一个简单的线性模型
ols = LinearRegression()
ols.fit(features_train, target_train)
# 得分
print(ols.score(features_test, target_test))
# 每一次都预测为20
clf = DummyRegressor(strategy='constant', constant=20)
clf.fit(features_train, target_train)
# 得分
print(clf.score(features_test, target_test))
R 2 R^2 R2评分:
R 2 = 1 − Σ i ( y i − y i ^ ) Σ i ( y i − y ‾ ) R^2 = 1- \frac{\Sigma_i(y_i-\hat{y_i})}{\Sigma_i(y_i-\overline{y})} R2=1−Σi(yi−y)Σi(yi−yi^)
y i ^ \hat{y_i} yi^是预测值, y ‾ \overline{y} y是目标均值
R 2 R^2 R2越接近1,目标向量中由特征解释的方差越大,拟合越好。
DummyClassifier
dummyClassifier.py
# Load libraries
from sklearn.datasets import load_iris
from sklearn.dummy import DummyClassifier
from sklearn.model_selection import train_test_split
# 莺尾花数据
iris = load_iris()
# 创建target vector feature matrix
features, target = iris.data, iris.target
# 分离训练集和测试集
features_train, features_test, target_train, target_test = train_test_split(
features, target, random_state=0)
# 创建 dummy classifier
dummy = DummyClassifier(strategy='uniform', random_state=1)
# "训练" model
dummy.fit(features_train, target_train)
# 获得准确性的评分
print(dummy.score(features_test, target_test))
# Load library
from sklearn.ensemble import RandomForestClassifier
# 创建一个随机森林的分类器(14章会介绍原理)
classifier = RandomForestClassifier()
# 训练模型
classifier.fit(features_train, target_train)
# 得到准确性的评分
print(classifier.score(features_test, target_test))
DummyClassifier
就是进行随机猜测。strategy
:
scoring="accuracy"
evaluateClassifier.py
# Load libraries
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification
# 生成 features matrix and target vector
X, y = make_classification(n_samples=10000,
n_features=3,
n_informative=3,
n_redundant=0,
n_classes=2,
random_state=1)
# 创建 logistic regression
logit = LogisticRegression()
# CV打分函数,scoring为accuracy
# 与原书不同,现在cv函数打分的默认k值改成了5,所以数组有5个元素
print(cross_val_score(logit, X, y, scoring="accuracy"))
precision:实际预测正确的阳性观察结果在预测正确中的比例。
P r e c i s i o n = T P T P + F P Precision=\frac{TP}{TP+FP} Precision=TP+FPTP
high-precision模型是悲观的,因为它们只有在非常确定的时候才认为观测结果是阳性
# CV 打分函数 scoring为 precision
print(cross_val_score(logit, X, y, scoring="precision"))
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N8g91Qwc-1658503259994)(C:\Users\12587\AppData\Roaming\Typora\typora-user-images\image-20220721231443766.png)]
recall:预测为阳性的结果在真正为阳性的比率。
R e c a l l = T P T P + F N Recall=\frac{TP}{TP+FN} Recall=TP+FNTP
衡量模型识别正类观察的能力。
high-recall的模型是乐观的,因为他们把一个类判断成阳性的标准较低
# CV 打分函数 scoring为 recall
print(cross_val_score(logit, X, y, scoring="recall"))
我们希望precision和recall间能有某种平衡:F1
F1 分数是调和平均值
F 1 = 2 × P r e c i s i o n × R e c a l l P r e c i s i o n + R e c a l l F_1=2\times \frac{Precision\times Recall}{Precision+Recall} F1=2×Precision+RecallPrecision×Recall
# CV 打分函数 scoring为 f1
print(cross_val_score(logit, X, y, scoring="f1"))
作为一种评估指标,准确率具有一些有价值的特性,尤其是其简单的直觉。
更好的指标通常涉及使用精确度和召回率的某种平衡——即我们模型的乐观和悲观之间的权衡。 F1 代表召回率和准确率之间的平衡,其中两者的相对贡献相等。
作为使用 cross_val_score 的替代方法,如果我们已经有了真实的 y 值和预测的 y 值,我们可以直接计算准确度和召回等指标:
# Load library
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 创建测试集和训练集
X_train, X_test, y_train, y_test = train_test_split(X,
y,
test_size=0.1,
random_state=1)
# 对目标向量作出预测
y_hat = logit.fit(X_train, y_train).predict(X_test)
# Calculate accuracy
print(accuracy_score(y_test, y_hat))
ROC
曲线rob_curveExample.py
# Load libraries
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_curve, roc_auc_score
from sklearn.model_selection import train_test_split
# 创建特征矩阵和目标向量
features, target = make_classification(n_samples=10000, # 10000个样本
n_features=10, # 10个特征
n_classes=2, # 2个类别
n_informative=3, # 参与建模的特征数为3个
random_state=3) # 随机种子
# 分离训练集和测试集
features_train, features_test, target_train, target_test = train_test_split(
features, target, test_size=0.1, random_state=1)
# 创建LogisticRegression 分类器
logit = LogisticRegression()
# 训练模型
logit.fit(features_train, target_train)
# 预测结果
target_probabilities = logit.predict_proba(features_test)[:, 1]
# 错误和正确的比例
false_positive_rate, true_positive_rate, threshold = roc_curve(target_test,
target_probabilities)
# 使用pyplot绘制ROC曲线图
plt.title("Receiver Operating Characteristic")
plt.plot(false_positive_rate, true_positive_rate)
plt.plot([0, 1], ls="--")
plt.plot([0, 0], [1, 0], c=".7"), plt.plot([1, 1], c=".7")
plt.ylabel("True Positive Rate")
plt.xlabel("False Positive Rate")
plt.show()
predict_proba
查看第一次观察的预测概率:# 获取第一个observation的分类概率
print(logit.predict_proba(features_test)[0:1])
预测的类别classes_
# 预测的结果
print(logit.classes_)
第一次观察有大约 87% 的机会属于阴性类 (0),有 13% 的机会属于阳性类 (1)。默认情况下,如果概率大于 0.5(称为阈值),scikit-learn 会预测观察结果是阳性类的一部分。
出于实质性原因,我们通常希望明确地偏向我们的模型以使用不同的阈值,而不是中间立场。例如,如果误报对我们公司来说代价高昂,我们可能更喜欢具有高概率阈值的模型。
当一个观察结果被预测为阳性时,我们可以非常确信预测是正确的。这种权衡以真阳性率 (TPR) 和假阳性率 (FPR) 表示。真阳性率是正确预测为真的观察值除以所有真阳性观察值:
T P R = T P T P + F N TPR=\frac{TP}{TP+FN} TPR=TP+FNTP
F P R = F P T N + F P FPR=\frac{FP}{TN+FP} FPR=TN+FPFP
ROC 曲线代表每个概率阈值的相应 TPR 和 FPR。 例如,在我们的解决方案中,大约 0.50 的阈值具有 0.81 的 TPR 和 0.15 的 FPR
# 阈值大约为0.5
print("Threshold:", threshold[116])
print("True Positive Rate:", true_positive_rate[116])
print("False Positive Rate:", false_positive_rate[116])
然而,如果我们将阈值提高到约 80%(即,提高模型在预测观察结果为正之前必须具有的确定性),TPR 会显着下降,但 FPR 也会下降:
# 阈值提升到0.8
print("Threshold:", threshold[45])
print("True Positive Rate:", true_positive_rate[45])
print("False Positive Rate:", false_positive_rate[45])
除了能够可视化 TPR 和 FPR 之间的权衡之外,ROC 曲线还可以用作模型的通用度量。 模型越好,曲线就越高,因此曲线下的面积就越大。
通常通过计算 ROC 曲线下面积 (AUCROC) 来判断模型在所有可能阈值下的整体相等性。 AUCROC 越接近 1,模型越好。 在 scikit-learn 中,我们可以使用 roc_auc_score 计算 AUCROC:
# 计算曲线面积
print(roc_auc_score(target_test, target_probabilities))
cross-validation
evaluateMultiClassifier.py
# Load libraries
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification
# 特征矩阵,目标向量
features, target = make_classification(n_samples=10000,
n_features=3,
n_informative=3,
n_redundant=0,
n_classes=3,
random_state=1)
# 创建 logistic regression
logit = LogisticRegression()
# 使用accuracy指标进行判断
# 与原书不同,现在cv函数打分的默认k值改成了5,所以数组有5个元素
print(cross_val_score(logit, features, target, scoring='accuracy'))
当我们有分布平衡的类时(例如,目标向量的每个类中的观察数量大致相等),就像在二元类设置中一样,准确度是评估指标的一个简单且可解释的选择。准确性是正确预测的数量除以观察的数量,并且在多类和二元设置中的效果一样好。然而,当我们有不平衡的类(一种常见情况)时,我们应该倾向于使用其他评估指标。
许多 scikit-learn 的内置指标用于评估二元分类器。
但是,当我们有两个以上的类时,可以扩展这些指标中的许多指标以供使用。精度、召回率和 F1 分数是我们在之前的秘籍中已经详细介绍过的有用指标。虽然它们最初都是为二元分类器设计的,但我们可以通过将我们的数据视为一组二元类来将它们应用于多类设置。
# Cross-validate模型 使用 macro averaged F1 score
print(cross_val_score(logit, features, target, scoring='f1_macro'))
这里的scoring函数后面带着_macro其实是用于平均类评估参数的方法,下面是比较常见的多类评估后缀:
macro:
计算每个类的度量分数的平均值,对每个类进行平均加权。(平均值)
weighted:
计算每个类的度量分数的平均值,根据数据中的大小对每个类进行加权。
micro
计算每个类的度量分数的平均值,根据数据中的大小对每个类进行加权。
通俗的来说其实是:
参考资料:(97条消息) 多分类算法的评估指标_taon1607的博客-CSDN博客_多分类算法评价标准
confusionMatrix.py
seaborn库需要安装
conda install seaborn
# Load libraries
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
import pandas as pd
# 莺尾花数据集
iris = datasets.load_iris()
# 特征矩阵
features = iris.data
# 特征向量
target = iris.target
# 创建一个数组包含所有类别的名字
class_names = iris.target_names
# 创建训练集和测试集
features_train, features_test, target_train, target_test = train_test_split(
features, target, random_state=1)
# sigmoid函数回归
classifier = LogisticRegression()
# 训练并且预测
target_predicted = classifier.fit(features_train,
target_train).predict(features_test)
# confusion_matrix创建混淆矩阵
matrix = confusion_matrix(target_test, target_predicted)
# 创建 pandas dataframe(绘制需要是pandas的格式)
dataframe = pd.DataFrame(matrix, index=class_names, columns=class_names)
# 创建heatmap
sns.heatmap(dataframe, annot=True, cbar=None, cmap="Blues")
plt.title("Confusion Matrix"), plt.tight_layout()
plt.ylabel("True Class"), plt.xlabel("Predicted Class")
plt.show()
混淆矩阵是分类器性能的简单、有效的可视化。
矩阵的每一列(通常可视化为heatmap)
关于混淆矩阵,有三件事值得注意。
关于sklearn.metrics中的混淆矩阵相关的函数:sklearn.metrics.confusion_matrix — scikit-learn 1.1.1 documentation
mean squared error (MSE)
,中文翻译应该是均方误差MSE.py
# Load libraries
from sklearn.datasets import make_regression
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LinearRegression
# 生成 features matrix, target vector
features, target = make_regression(n_samples=100,
n_features=3,
n_informative=3,
n_targets=1,
noise=50,
coef=False,
random_state=1)
# 创建线性回归模型
ols = LinearRegression()
# 交叉检验法 linear regression 使用 (negative) MSE
print(cross_val_score(ols, features, target, scoring='neg_mean_squared_error'))
# 交叉检验法 linear regression 使用 R方
print(cross_val_score(ols, features, target, scoring='r2'))
silhouette coefficients(轮廓系数)
silhouetteCoeff.py
import numpy as np
from sklearn.metrics import silhouette_score
from sklearn import datasets
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
# Generate 特征矩阵
features, _ = make_blobs(n_samples=1000,
n_features=10,
centers=2,
cluster_std=0.5, # 聚类的标准差
shuffle=True,
random_state=1)
# 使用 k-means 去预测分类(第19章介绍)
model = KMeans(n_clusters=2, random_state=1).fit(features)
# 获得分完类预测所得到的标签
target_predicted = model.labels_
# 使用silhouette coefficients 预测
print(silhouette_score(features, target_predicted))
silhouette coefficients
是一个同时衡量这两个属性的单一值
silhouette_score
返回的值是所有observation的平均轮廓系数。轮廓系数介于 –1 和 1 之间,其中 1 表示密集、分离良好的集群。
make_scorer
make_scorer.py
# Load libraries
from sklearn.metrics import make_scorer, r2_score
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Ridge
from sklearn.datasets import make_regression
# 生成特征矩阵和目标向量
features, target = make_regression(n_samples=100,
n_features=3,
random_state=1)
# 生成测试集和训练集
features_train, features_test, target_train, target_test = train_test_split(
features, target, test_size=0.10, random_state=1)
# 创建一个自定义的评估度量函数
def custom_metric(target_test, target_predicted):
# 计算r2_score
r2 = r2_score(target_test, target_predicted)
# 返回
return r2
# 定义scorer,然后greater_is_better表明分数越高模型越好
score = make_scorer(custom_metric, greater_is_better=True)
# 脊回归
classifier = Ridge()
# 训练脊回归模型
model = classifier.fit(features_train, target_train)
# 使用自定义的scorer
print(score(model, features_test, target_test))
make_scorer需要我们定义一个函数f:
make_scorer需要greater_is_better
指定是否是分越高越好
在案例中我们将R2假装成我们自定义的判断方法来作为
# 预测值
target_predicted = model.predict(features_test)
# 使用r2_score评分
print(r2_score(target_test, target_predicted))
关于示例出现的Ridge回归:(中文翻译用岭回归也有翻译成脊回归的)
评估Observation的数量对模型质量的影响
绘制learning curve
learningCurve.py
# Load libraries
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_digits
from sklearn.model_selection import learning_curve
# 手写数字集
digits = load_digits()
# 特征矩阵和目标向量
features, target = digits.data, digits.target
# 创建多种数据集大小对应的cv检验的结果
train_sizes, train_scores, test_scores = learning_curve(
# 分类器——随机森林
RandomForestClassifier(),
# 特征矩阵
features,
# 目标向量
target,
# Kfolds
cv=10,
# 评估函数
scoring='accuracy',
# 所有CPU参与评估
n_jobs=-1,
# 大小为50
# 训练集
train_sizes=np.linspace(
0.01, #百分之1
1.0, #百分百
50))
# 训练集平均值和标准差
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
# 测试集的平均值和标准差
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# 绘制
plt.plot(train_sizes, train_mean, '--', color="#111111", label="Training score")
plt.plot(train_sizes, test_mean, color="#111111", label="Cross-validation score")
# 绘制条带
plt.fill_between(train_sizes, train_mean - train_std,
train_mean + train_std, color="#DDDDDD")
plt.fill_between(train_sizes, test_mean - test_std,
test_mean + test_std, color="#DDDDDD")
# 坐标系
plt.title("Learning Curve")
plt.xlabel("Training Set Size"), plt.ylabel("Accuracy Score"),
plt.legend(loc="best")
plt.tight_layout()
plt.show()
classification_report
textReportofEvaluation.py
# Load libraries
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
# 加载莺尾花数据集
iris = datasets.load_iris()
# 特征矩阵
features = iris.data
# 目标向量
target = iris.target
# 类的名字
class_names = iris.target_names
# 训练集和测试集
features_train, features_test, target_train, target_test = train_test_split(
features, target, random_state=1)
# 创建 logistic regression
classifier = LogisticRegression()
# 训练模型并作出预测
model = classifier.fit(features_train, target_train)
target_predicted = model.predict(features_test)
# 创建分类器评估结果的简短描述
print(classification_report(target_test,
target_predicted,
target_names=class_names))
评估不同超参数对模型的影响
绘制validation curve
validationCurve.py
# Load libraries
import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import load_digits
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import validation_curve
# 手写数字集
digits = load_digits()
# 特征矩阵,目标矩阵
features, target = digits.data, digits.target
# 生成一个数组从1到250,步长为2作为超参数数组
param_range = np.arange(1, 250, 2)
# 通过不同的参数生成training and test
train_scores, test_scores = validation_curve(
# 随机森林的分类器
RandomForestClassifier(),
# 特征矩阵
features,
# 目标向量
target,
# 超参数
param_name="n_estimators",
# 超参数的范围
param_range=param_range,
# KFold的k值
cv=3,
# 评估标准
scoring="accuracy",
# 使用所有CPU
n_jobs=-1)
# 计算训练集的平均值和标准差
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
# 计算测试集的平均值和标准差
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
# 绘制accuracy
plt.plot(param_range, train_mean, label="Training score", color="black")
plt.plot(param_range, test_mean, label="Cross-validation score", color="dimgrey")
# 绘制accuracy的条带
plt.fill_between(param_range, train_mean - train_std,
train_mean + train_std, color="gray")
plt.fill_between(param_range, test_mean - test_std,
test_mean + test_std, color="gainsboro")
# 绘制
plt.title("Validation Curve With Random Forest")
plt.xlabel("Number Of Trees")
plt.ylabel("Accuracy Score")
plt.tight_layout()
plt.legend(loc="best")
plt.show()
validation curve
来展示了不同决策树数量对于最后准确度的影响validation_curve
param_name
:超参数的名称param_range
:超参数的范围scoring
:评估的方式和之前一样:accuracy、precision等等