SciKit-Learn 自定义评估指标:为特定机器学习任务量身定制

好的,各位观众老爷,欢迎来到“SciKit-Learn 自定义评估指标:量身定制你的专属评分”专场!我是今天的讲师,人称“代码界的段子手”,保证让你们在欢声笑语中学到真本事!

今天咱们要聊的是机器学习里一个非常重要的环节——模型评估。你想啊,辛辛苦苦训练出一个模型,就像养了个孩子,总得看看他考多少分,有没有成为“别人家的孩子”的潜力吧?

SciKit-Learn 已经提供了很多常用的评估指标,比如准确率、精确率、召回率、F1-score,还有R方、均方误差等等。这些指标就像是“大众点评”,能让你对模型有个大概的了解。

但是!但是!重点来了!有些时候,“大众点评”并不能满足你的需求。就像你去吃饭,有些人喜欢吃辣,有些人喜欢吃甜,众口难调嘛!你的特定业务场景可能需要更精细、更个性化的评估指标。

所以,今天咱们要学习的就是如何自定义评估指标,打造你的专属“评分标准”,让你的模型评估更精准、更有效!

一、 为什么要自定义评估指标?

想象一下,你正在做一个医疗诊断的模型,目标是预测病人是否患有某种疾病。

  • 情况一: 假设这种疾病非常罕见,只有 1% 的人会得病。如果你的模型把所有人都预测为“健康”,那么它的准确率可以高达 99%!看起来很牛逼,对不对?但实际上,这个模型毫无价值,因为它一个病人也没诊断出来,完全错过了那些真正需要治疗的人。

  • 情况二: 假设误诊的代价非常高昂。如果把一个健康的人误诊为病人,可能会导致不必要的治疗和精神压力。在这种情况下,你可能更关心模型的“特异性”,也就是正确识别健康人的能力。

  • 情况三: 假设漏诊的代价更高。如果把一个病人漏诊了,可能会延误治疗,导致病情恶化甚至死亡。在这种情况下,你可能更关心模型的“敏感性”,也就是正确识别病人的能力。

你看,不同的业务场景,对模型的要求是不一样的。简单的准确率并不能反映模型的真实表现。我们需要根据实际情况,设计更有针对性的评估指标。

二、 如何自定义评估指标?

SciKit-Learn 提供了两种主要的方式来定义你的专属评分函数:

  1. 使用 make_scorer 函数: 这种方式最灵活,你可以直接定义一个 Python 函数,然后用 make_scorer 把这个函数转换成一个可以用于 cross_val_scoreGridSearchCV 等函数的评分器。

  2. 自定义评分类: 这种方式更适合复杂的评估逻辑,你可以创建一个继承自 sklearn.metrics.make_scorer 的类,并在类中实现你的评分逻辑。

咱们先从最简单的 make_scorer 开始。

2.1 使用 make_scorer 函数

make_scorer 函数的基本语法如下:

from sklearn.metrics import make_scorer

scorer = make_scorer(score_func, greater_is_better=True, needs_proba=False, needs_threshold=False, **kwargs)
  • score_func: 这是你的评分函数,它接受两个参数:y_true (真实标签) 和 y_predicted (预测结果)。
  • greater_is_better: 表示评分越高越好,默认为 True。如果你的评分越低越好,比如损失函数,那么需要设置为 False
  • needs_proba: 表示你的评分函数是否需要预测概率值。如果你的评分函数需要用到 predict_proba 的结果,那么需要设置为 True
  • needs_threshold: 表示你的评分函数是否需要用到预测阈值。
  • **kwargs: 其他额外的参数,可以传递给你的评分函数。

示例 1:自定义一个简单的准确率评分函数

import numpy as np
from sklearn.metrics import make_scorer
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification

# 创建一个模拟数据集
X, y = make_classification(n_samples=100, n_features=20, random_state=42)

# 定义一个自定义的准确率评分函数
def my_accuracy(y_true, y_pred):
    """
    计算准确率
    """
    correct_predictions = np.sum(y_true == y_pred)
    total_predictions = len(y_true)
    accuracy = correct_predictions / total_predictions
    return accuracy

# 使用 make_scorer 创建一个评分器
my_accuracy_scorer = make_scorer(my_accuracy, greater_is_better=True)

# 创建一个 Logistic Regression 模型
model = LogisticRegression(random_state=42)

# 使用 cross_val_score 进行交叉验证,并使用自定义评分器
scores = cross_val_score(model, X, y, cv=5, scoring=my_accuracy_scorer)

# 打印交叉验证的评分结果
print("交叉验证的评分结果:", scores)
print("平均准确率:", np.mean(scores))

这个例子非常简单,就是把 SciKit-Learn 自带的准确率计算方法重新实现了一遍。但是,它展示了 make_scorer 的基本用法。

示例 2:自定义一个考虑了误诊和漏诊代价的评分函数

假设我们现在要评估一个疾病诊断模型,误诊一个健康人的代价是 100 元,漏诊一个病人的代价是 1000 元。我们可以定义一个如下的评分函数:

import numpy as np
from sklearn.metrics import make_scorer
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification

# 创建一个模拟数据集
X, y = make_classification(n_samples=100, n_features=20, random_state=42)

# 定义一个自定义的代价敏感评分函数
def cost_sensitive_score(y_true, y_pred, cost_fp=100, cost_fn=1000):
    """
    计算代价敏感的评分
    """
    fp = np.sum((y_true == 0) & (y_pred == 1))  # 假阳性 (误诊)
    fn = np.sum((y_true == 1) & (y_pred == 0))  # 假阴性 (漏诊)
    cost = cost_fp * fp + cost_fn * fn
    return -cost  # 评分越低,代价越高,所以取负数

# 使用 make_scorer 创建一个评分器
cost_sensitive_scorer = make_scorer(cost_sensitive_score, greater_is_better=True)

# 创建一个 Logistic Regression 模型
model = LogisticRegression(random_state=42)

# 使用 cross_val_score 进行交叉验证,并使用自定义评分器
scores = cross_val_score(model, X, y, cv=5, scoring=cost_sensitive_scorer)

# 打印交叉验证的评分结果
print("交叉验证的评分结果:", scores)
print("平均代价:", -np.mean(scores)) # 注意取负数,因为我们希望代价越低越好

在这个例子中,我们定义了一个 cost_sensitive_score 函数,它计算了误诊和漏诊的总代价。然后,我们把这个函数传递给 make_scorer,创建了一个代价敏感的评分器。注意,我们把 greater_is_better 设置为 True,并且在返回代价的时候取了负数,因为我们希望代价越低越好。

示例 3:自定义一个需要预测概率值的评分函数

有些评分指标,比如 AUC (Area Under the ROC Curve),需要用到模型的预测概率值。在这种情况下,我们需要把 needs_proba 设置为 True

import numpy as np
from sklearn.metrics import make_scorer, roc_auc_score
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification

# 创建一个模拟数据集
X, y = make_classification(n_samples=100, n_features=20, random_state=42)

# 定义一个自定义的 AUC 评分函数
def my_auc(y_true, y_proba):
    """
    计算 AUC
    """
    auc = roc_auc_score(y_true, y_proba[:, 1])  # y_proba 是一个二维数组,我们需要取正类的概率值
    return auc

# 使用 make_scorer 创建一个评分器
my_auc_scorer = make_scorer(my_auc, greater_is_better=True, needs_proba=True)

# 创建一个 Logistic Regression 模型
model = LogisticRegression(random_state=42)

# 使用 cross_val_score 进行交叉验证,并使用自定义评分器
scores = cross_val_score(model, X, y, cv=5, scoring=my_auc_scorer)

# 打印交叉验证的评分结果
print("交叉验证的评分结果:", scores)
print("平均 AUC:", np.mean(scores))

在这个例子中,我们定义了一个 my_auc 函数,它使用了 SciKit-Learn 自带的 roc_auc_score 函数来计算 AUC。注意,我们需要把 needs_proba 设置为 True,并且在 my_auc 函数中,y_proba 是一个二维数组,我们需要取正类的概率值 (即 y_proba[:, 1])。

2.2 自定义评分类

如果你需要更复杂的评估逻辑,或者需要在评分过程中维护一些状态,那么可以考虑自定义评分类。

自定义评分类需要继承自 sklearn.metrics.make_scorer,并重写 __call__ 方法。

示例:自定义一个评分类,用于计算 F-beta score

F-beta score 是 F1-score 的一个推广,它允许你调整精确率和召回率的权重。F-beta score 的公式如下:

F_beta = (1 + beta^2) * (precision * recall) / (beta^2 * precision + recall)

当 beta = 1 时,F-beta score 就是 F1-score。当 beta > 1 时,召回率的权重更大。当 beta < 1 时,精确率的权重更大。

import numpy as np
from sklearn.metrics import make_scorer, precision_score, recall_score
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification

# 创建一个模拟数据集
X, y = make_classification(n_samples=100, n_features=20, random_state=42)

# 自定义一个 F-beta score 类
class FBetaScorer:
    def __init__(self, beta=1.0):
        self.beta = beta

    def __call__(self, y_true, y_pred):
        precision = precision_score(y_true, y_pred)
        recall = recall_score(y_true, y_pred)
        f_beta = (1 + self.beta**2) * (precision * recall) / (self.beta**2 * precision + recall)
        return f_beta

# 创建一个 FBetaScorer 实例
f_beta_scorer = FBetaScorer(beta=0.5)  # 设置 beta 值为 0.5,表示更看重精确率

# 使用 make_scorer 创建一个评分器
f_beta_scorer = make_scorer(f_beta_scorer, greater_is_better=True)

# 创建一个 Logistic Regression 模型
model = LogisticRegression(random_state=42)

# 使用 cross_val_score 进行交叉验证,并使用自定义评分器
scores = cross_val_score(model, X, y, cv=5, scoring=f_beta_scorer)

# 打印交叉验证的评分结果
print("交叉验证的评分结果:", scores)
print("平均 F-beta score:", np.mean(scores))

在这个例子中,我们定义了一个 FBetaScorer 类,它在初始化时接受一个 beta 参数。然后,我们在 __call__ 方法中计算 F-beta score。注意,__call__ 方法的参数是 y_truey_pred,和 make_scorer 的评分函数一样。

三、 总结和注意事项

自定义评估指标是机器学习中一个非常重要的技能,它可以让你更精准地评估模型,并根据实际业务场景进行优化。

  • 理解你的业务场景: 在定义评估指标之前,一定要深入理解你的业务场景,明确你的目标是什么,哪些错误的代价更高。
  • 选择合适的评估指标: 根据你的业务场景,选择合适的评估指标。如果准确率不够用,可以考虑精确率、召回率、F1-score、AUC 等指标。如果误诊和漏诊的代价不一样,可以考虑代价敏感的评分函数。
  • 测试你的评分函数: 在使用自定义评分函数之前,一定要进行充分的测试,确保它能够正确地计算评分。
  • 注意 greater_is_better 参数: 确保 greater_is_better 参数设置正确。如果你的评分越低越好,那么需要设置为 False
  • 使用 needs_proba 参数: 如果你的评分函数需要用到预测概率值,那么需要把 needs_proba 设置为 True

表格总结

功能 make_scorer 函数 自定义评分类
适用场景 简单的评分逻辑,不需要维护状态 复杂的评分逻辑,需要在评分过程中维护状态
实现方式 定义一个 Python 函数,然后用 make_scorer 函数把这个函数转换成一个评分器 创建一个继承自 sklearn.metrics.make_scorer 的类,并重写 __call__ 方法
灵活性 较高,可以自定义任何 Python 函数作为评分函数 更高,可以自定义类的属性和方法,实现更复杂的评分逻辑
代码复杂度 较低 较高
适用性示例 简单的准确率计算,代价敏感的评分,AUC 计算 F-beta score 计算,需要在评分过程中维护状态的评分

好了,今天的课程就到这里。希望大家能够掌握自定义评估指标的技巧,打造出更精准、更有效的机器学习模型!记住,模型评估不是一件枯燥的事情,而是一件充满乐趣的事情!就像品尝美食一样,你需要不断尝试、不断调整,才能找到最适合你的口味!

下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注