性能度量
错误率(error rate)和精度(accuracy)
"""
错误率 = 分类错误样本/样本总数
精度 = 分类正确样本/样本总数
"""
# 计算错误率
def error_rate(y_true, y_pred):
error_count = 0
for pred, true in zip(y_pred, y_true):
if pred != true:
error_count += 1
error_rate = error_count / len(y_pred)
return error_rate
# 计算精度
def accuracy(y_true, y_pred):
error_rate_ = error_rate(y_true, y_pred)
accuracy_score = 1 - error_rate_
return accuracy_score
y_pred = [1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1]
y_true = [1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1]
print("错误率:", error_rate(y_true, y_pred))
print("精度:", accuracy(y_true, y_pred))
错误率: 0.25
精度: 0.75
from sklearn.metrics import accuracy_score
# 对比一下sklearn中的accuracy_score方法,结果一样
print("精度:", accuracy_score(y_true, y_pred))
精度: 0.75
查准率(Precision)、查全率(Recall)与F1
"""
虽然说精度和错误率常用,但是在某些问题上并不能很好的度量分类器的性能。比如说,有一个10000样本的数据集,其中有100个是艾滋病患者,其余的是正常人
如果用错误率和精度进行度量,即便分类器将所有的艾滋病患者识别为正常人,错误率也相当低,仅0.01, 精度则达到了0.99,看似效果很好,实则卵用。
所以说需要其他的度量标准。在了解Recall,Precision和F1之前,首先要了解混淆矩阵(confusion matrix):
"""
# 注:在机器学习二分类任务中,通常将阳性或者正例标记为1,阴性或负例标记为0
# TP(真正例): 预测结果为阳,真实结果为阳
def true_positive(y_true, y_pred):
tp = 0
for true, pred in zip(y_true, y_pred):
if true == 1 and pred == 1:
tp += 1
return tp
# FP(假正例): 预测结果为阳,真实结果为阴
def false_positive(y_true, y_pred):
fp = 0
for true, pred in zip(y_true, y_pred):
if true == 0 and pred == 1:
fp += 1
return fp
# TN(真反例): 预测结果为阴,真实结果为阴
def true_negative(y_true, y_pred):
tn = 0
for true, pred in zip(y_true, y_pred):
if true == 0 and pred == 0:
tn += 1
return tn
# FN(假反例): 预测结果为阴,真实结果为阳
def false_negative(y_true, y_pred):
fn = 0
for true, pred in zip(y_true, y_pred):
if true == 1 and pred == 0:
fn += 1
return fn
# 构造混淆矩阵
def confusion_matrix(y_true, y_pred):
tp = true_positive(y_true, y_pred)
fp = false_positive(y_true, y_pred)
tn = true_negative(y_true, y_pred)
fn = false_negative(y_true, y_pred)
m = np.array([[tp, fn],
[fp, tn]])
cm = pd.DataFrame(m, columns=["P_pred", "N_pred"], index=["P_true", "N_true"])
return cm
y_pred = [1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1]
y_true = [1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1]
# 就上面的数据计算混淆矩阵
print("手动计算的混淆矩阵:")
cm = confusion_matrix(y_true, y_pred)
cm
手动计算的混淆矩阵:
P_pred | N_pred | |
---|---|---|
P_true | 7 | 3 |
N_true | 2 | 8 |
from sklearn.metrics import confusion_matrix
# 注意使用sklearn中的confusion_matrix方法时,它展示的顺序不一样
skl_cm = confusion_matrix(y_true, y_pred)
print("使用sklearn的confusion_matrix方法计算的混淆矩阵:")
skl_cm = pd.DataFrame(skl_cm, columns=["N_pred", "P_pred"], index=["N_true", "P_true"])
skl_cm
使用sklearn的confusion_matrix方法计算的混淆矩阵:
N_pred | P_pred | |
---|---|---|
N_true | 8 | 2 |
P_true | 3 | 7 |
P
r
e
c
i
s
i
o
n
=
T
P
/
(
T
P
+
F
P
)
Precision = TP / (TP + FP)
Precision=TP/(TP+FP)
R
e
c
a
l
l
=
T
P
/
(
T
P
+
F
N
)
Recall = TP / (TP + FN)
Recall=TP/(TP+FN)
"""
万事开头难,了解了混淆矩阵的知识之后,理解查准率Precision和查全率Recall就很容易了
只需要记住两个公式:
Precision = TP / (TP + FP)
Recall = TP / (TP + FN)
如果光看公式还是难以理解这两个指标,那么举个例子就很好理解了。
依旧用艾滋病作为例子,查准率(Precision)的高低可以这样理解,
"假如你现在去医院检查是否患有艾滋病(当然只是假设哈,没有其他意思),如果你知道医院的仪器里面的分类算法模型的Precision得分仅0.2,
然后一查它告诉你,你的检查结果为阳性,你觉得你会信嘛?当然不信,因为从得分可以看出,这个笨蛋算法查出来的阳性的人里面,只有20%是真正患病的
而一向生活自爱的你怎么会是艾滋病呢。但是如果这个算法模型的Precision得分高达0.98,它告诉你,你阳性了,那你可能会自己好好反思一下,什么
时候不小心染上了艾滋病了,因为它查出来是阳性的人里面,98%都是真的患艾滋病了!"
接下来用艾滋病的例子去理解查全率(Recall),也十分的清晰。
假如说,你现在接到一个任务,要把一批人中的全部艾滋病患者找出来,那么你在训练模型的时候,就要考虑将Recall提高,
因为Recall越高,说明你的算法模型越能将所有的阳性找出来。
就艾滋病这个例子来说,最简单的理解就是,提高Precision可以降低误诊的风险,提高Recall可以降低漏诊的风险
"""
# 查准率
def Precision(y_true, y_pred):
TP = true_positive(y_true, y_pred)
FP = false_positive(y_true, y_pred)
return TP / (TP + FP)
# 查全率
def Recall(y_true, y_pred):
TP = true_positive(y_true, y_pred)
FN = false_negative(y_true, y_pred)
return TP / (TP + FN)
y_pred = [1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1]
y_true = [1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1]
print(f"手动计算Precision = {Precision(y_true, y_pred)}")
print(f"手动计算Recall = {Recall(y_true, y_pred)}")
手动计算Precision = 0.7777777777777778
手动计算Recall = 0.7
from sklearn.metrics import recall_score, precision_score
print(f"sklearn计算 Precision = {precision_score(y_true, y_pred)}")
print(f"sklearn计算 Recall = {recall_score(y_true, y_pred)}")
sklearn计算 Precision = 0.7777777777777778
sklearn计算 Recall = 0.7
"""
事实上,只有在小数据集上面才能Precision和Recall才可能会出现两个都比较好的情况,
实际上Precision和Recall是一对相互矛盾的指标,Precision高,Recall一般就会低,反之
在二分类任务中,通过设置不同的Threshold来将概率转化为标签,通过设定不同的阈值可以
获得对应的Precision和Recall得分序列,将Precision作为纵坐标,Recall作为横坐标,得到P-R曲线
图示有三个分类器ABC,A和B的性能需要根据具体场景确定,但AB都优于C 因为AB的PR曲线完全将C包在内部了
"""
F 1 = ( 2 ⋅ P ⋅ R ) / ( P + R ) F1 = (2 · P · R) / (P + R) F1=(2⋅P⋅R)/(P+R)
"""
由于Precision和Recall是一对矛盾的指标,所以F1 score 出现了, F1 socre是基于
查全率和查准率的调和平均定义的,综合考量了两个指标的值
"""
from sklearn .metrics import f1_score
f1_score(y_true, y_pred, average="macro")
0.7493734335839599
ROC和AUC
∗
真正率
∗
T
P
R
=
T
P
/
(
T
P
+
F
N
)
*真正率* \space TPR = TP / (TP + FN)
∗真正率∗ TPR=TP/(TP+FN)
∗
假正率
∗
F
P
R
=
F
P
/
(
T
N
+
F
P
)
*假正率* \space FPR = FP / (TN + FP)
∗假正率∗ FPR=FP/(TN+FP)
"""
假设我们有一个用于预测肿瘤是否为恶性的分类模型。我们可以使用ROC曲线来评估该模型的准确性。
首先,我们需要准备一个测试数据集,其中包含一些已知肿瘤类型(恶性或良性)的样本,并且我们已经用模型进行预测。
对于每个样本,模型会给出一个预测概率,表示肿瘤为恶性的可能性。接下来,我们可以使用不同的阈值来确定模型的预测结果。
例如,对于一个样本,如果预测概率大于0.5,则将其分类为恶性肿瘤,否则分类为良性肿瘤。
通过改变阈值,我们可以得到不同的真阳性率(True Positive Rate,TPR)和假阳性率(False Positive Rate,FPR)。
ROC曲线是以TPR为纵轴,FPR为横轴的二维图形。我们可以根据不同的阈值计算出多个TPR和FPR对,并将它们绘制在ROC曲线上。
ROC曲线能够展示模型在不同阈值下的性能表现。通过观察ROC曲线,我们可以确定最佳的阈值选择,以平衡TPR和FPR。
通常情况下,曲线越靠近左上角,模型的性能越好。ROC曲线下方的面积(Area Under the ROC Curve,AUC)也是一个常用的性能指标,
可以用来评估模型的整体准确性。因此,通过使用ROC曲线和AUC,我们可以对二分类模型进行准确性评估,并选择最佳的阈值来平衡模型的性能。
"""
import numpy as np
from sklearn.metrics import roc_curve, roc_auc_score
import matplotlib.pyplot as plt
# 假设这是真实的样品标签
y_true = np.array(np.random.randint(0, 2, size=5000))
# 假设这是模型的预测概率
y_scores = np.random.randn(5000)
# 计算ROC曲线的TPR和FPR
fpr, tpr, thresholds = roc_curve(y_true, y_scores)
# 计算AUC
auc = roc_auc_score(y_true, y_scores)
# 绘制ROC曲线
plt.plot(fpr, tpr, label='ROC curve (AUC = %0.2f)' % auc)
plt.plot([0, 1], [0, 1], 'k--') # 绘制对角线
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver Operating Characteristic')
plt.legend(loc="lower right")
plt.show()
代价敏感错误率与代价曲线
"""
代价敏感错误率是一种在分类问题中考虑不同类别错误分类代价的评估指标。在某些实际应用中,错误地将某个类别分类为另一个类别可能会导致不同的后果或成本。
比如将正常人诊断为病人,只会多增加几次检查的时间,而将病人诊断为正常人,可能会错失医治导致死亡。代价敏感错误率考虑了这些不同的代价,并提供了更全面的性能评估。
假设我们定义以下代价参数:
- 将正类错误分类为负类的代价为C01(False Negative Cost)。
- 将负类错误分类为正类的代价为C10(False Positive Cost)。
代价敏感错误率 = (C01 * FN + C10 * FP) / (C01 * FN + C10 * FP + TN + TP)
还可以绘制代价曲线来可视化在不同分类阈值下的代价敏感错误率。通过分析代价曲线,我们可以选择最优的分类阈值,以最小化总体错误代价或满足特定需求。
"""
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix
# 生成一个具有2个类别的随机分类数据集
X, y = make_classification(n_samples=1000, n_features=10, n_classes=2, random_state=42)
# 将数据集拆分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建一个逻辑回归分类器
classifier = LogisticRegression()
# 在训练集上拟合分类器
classifier.fit(X_train, y_train)
# 在测试集上获取预测概率
y_scores = classifier.predict_proba(X_test)[:, 1]
# 设置不同的分类阈值
thresholds = np.arange(0.1, 1.1, 0.1)
# 初始化代价列表
costs = []
# 计算不同阈值下的代价敏感错误率
for threshold in thresholds:
y_pred = (y_scores >= threshold).astype(int)
cm = confusion_matrix(y_test, y_pred)
cost = (cm[0, 1] * 1 + cm[1, 0] * 10) / np.sum(cm)
costs.append(cost)
# 绘制代价曲线
plt.plot(thresholds, costs, marker='o')
plt.xlabel('Classification Threshold')
plt.ylabel('Cost-sensitive Error Rate')
plt.title('Cost Curve')
plt.grid(True)
plt.show()
偏差与方差
"""
在机器学习中,偏差(Bias)、方差(Variance)和噪声(Noise)是用来描述模型的三个重要性质。它们一起构成了模型的泛化误差(Generalization Error)。
1. 偏差(Bias):偏差是指模型预测与真实值之间的系统性偏离程度。它衡量了模型对问题的简化程度以及对训练数据的拟合能力。高偏差的模型往往对训练数据和测试数据都表现不足,
无法捕捉到数据中的复杂模式和关系。例如,线性回归模型在非线性数据集上可能存在较高的偏差。
2. 方差(Variance):方差是指模型在不同训练数据集上预测结果的不稳定性。它衡量了模型对训练数据的过拟合程度,即对训练数据中的噪声和随机性过度敏感。
高方差的模型可能在训练数据上表现良好,但在未见过的测试数据上表现较差。例如,高阶多项式回归模型可能会在训练数据上产生高方差,因为它过度拟合了训练数据中的噪声。
3. 噪声(Noise):噪声是指数据中的随机性和不可预测的部分,它对于模型是不可控的。噪声是由数据本身或数据收集过程中的随机因素引起的。
在机器学习中,我们希望模型能够从数据中学习到真实的模式和关系,而不受噪声的干扰。噪声的存在使得模型无法达到零泛化误差。在模型的泛化误差中,偏差度量了模型对问题的错误假设,
方差度量了模型对训练数据的过度敏感,而噪声则是不可控的随机因素。偏差和方差通常是一种权衡,称为偏差-方差权衡。增加模型复杂度可以降低偏差,但可能增加方差;
减小模型复杂度可以降低方差,但可能增加偏差。在实际应用中,我们需要根据问题的特性和数据的性质来选择适当的模型复杂度,以平衡偏差和方差,从而实现更好的泛化能力。
"""