最近做了一个随机森林的多分类multiclass任务,要在sklearn中使用make_scorer自定义一个评价指标scoring,发现网上没有太多相关经验贴,走了很多弯路,最终还是在官方文档中找到了答案,在此记录一下。
这是sklearn.metrics.make_scorer的官方文档
https://scikit-learn.org/stable/modules/generated/sklearn.metrics.make_scorer.html
-
首先介绍一下我的数据集,这是一个4分类的任务。特征df和标签labels都是dataframe格式,其中labels没有做onehot编码,就是[1,2,3,4]这样的标签。
-
下面自定义scoring函数。我想将错误分类的样本比例error_rate作为交叉验证时的scoring,按照文档,我们导入所需要的包,然后定义我们的函数。函数的入参为 y_true 和 y_pred ,尝试后发现,由于labels定义为dataframe,所以y_true其实是 (n,1) 的矩阵,而y_pred是 (n,) 的一维向量,两个入参维度不同,所以很多计算会莫名其妙出错,这一点要注意。要不避开,要不将y_true转换成 (n,) 的。
也就是这个样子
y_true=np.array([[1],
[2],
[3],
[4]])
y_pred=np.array([1,2,3,4])
了解这个小问题之后,我们开始写代码。为了避免上面提到的问题,我用了混淆矩阵计算错分类个数。
import pandas as pd
import numpy as np
from sklearn.metrics import make_scorer,confusion_matrix # 自定义CV评估指标, 混淆矩阵
def misclassified_error(y_true, y_pred):
'''自定义错分类率为CV评估指标'''
cm = confusion_matrix(y_true, y_pred, labels = [1,2,3,4]) # 打印混淆矩阵
correct = np.trace(cm) # 混淆矩阵的迹是正确分类的个数
error = (len(y_true)-correct)/len(y_true) # 错分类率=错分类样本数/总样本数
return error
'''
通过make_scorer将函数变成sklearn认识的scoring,
greater_is_better指是否该指标越高代表模型效果越好,
needs_proba指自定义的函数中y_pred是否需要一个y_pred_proba这样的概率值
'''
error_rate = make_scorer(misclassified_error, greater_is_better=False)
- 看起来准备完善。然后我开始跑随机森林
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier
random_forest = RandomForestClassifier()
RF_score = cross_val_score(random_forest, df, labels, scoring=error_rate, n_jobs=4)
竟然得出来是负值!为什么比例会是负值!
让我们回到原文档中找一下答案。
原来问题出在greater_is_better这个参数上。当它为False的时候,最终的得分会取你定义的值的相反数。
那么,我们在定义的时候加上一个负号可不可以呢?这样greater_is_better这个参数就要改为True,最后得到的还是负值。所以只需在跑出结果之后,取相反数就好了。