如何在pyspark 2.3中的二进制问题(BinaryClassificationEvaluator)中为CrossValidator evaluator使用f1score

2024-09-29 21:22:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我的用例是一个常见的用例:带有不平衡标签的二进制分类,因此我们决定通过交叉验证使用f1分数进行超参数选择,我们使用pyspark 2.3和pyspark.ml,我们创建了一个CrossValidator对象,但对于evaluator,问题如下:

  • BinaryClassificationEvaluator没有f1分数作为评估指标
  • MultiClassificationEvaluator有f1分数,但返回了错误的结果,我猜它为每个类计算f1(在本例中仅为2),并返回它们之间的某种平均值,因为负类(y=0)占主导地位,它生成高f1,但模型非常糟糕(正类的f1分数为0)
  • MultiClassificationEvaluator在最新版本中添加了参数evaluator.metricLabel,我认为该参数允许指定要使用的标签(在我的情况下,我会将其设置为1),但在spark 2.3上不可用

但问题是:我使用的公司/企业spark群集没有升级当前版本(2.3)的计划,因此问题是:考虑到我们仅限于spark 2.3,如何在二进制情况下的CrossValidator计算器中使用f1分数


Tags: 版本参数evaluator二进制分类情况标签用例
2条回答

如果可以使用Spark v3.0+,最简单的方法是使用F-measure by label度量并指定标签(并将beta设置为1):

evaluator = MulticlassClassificationEvaluator(metricName='fMeasureByLabel', metricLabel=1, beta=1.0) 

但由于您仅限于v2.3,因此您可以

  1. 重新实现交叉验证程序功能pyspark.mllib.evaluation.MulticlassMetrics通过label方法具有fMeasure。请参阅example以获取参考

  2. 将度量从BinaryClassificationEvaluator更改为areaUnderPR,这是一种“模型的优点”度量,应该可以为您完成这项工作(重新平衡标签)。这个blogpost比较F1和AUC-PR

您可以为此创建一个类。我公司的spark 2.4也有同样的问题,所以我试着为二元分类制作一个F1分数评估器。我必须为新类指定.evaluate.isLargerBetter方法。以下是我尝试使用this数据集时的示例代码:

class F1BinaryEvaluator():

    def __init__(self, predCol="prediction", labelCol="label", metricLabel=1.0):
        self.labelCol = labelCol
        self.predCol = predCol
        self.metricLabel = metricLabel

    def isLargerBetter(self):
        return True

    def evaluate(self, dataframe):
        tp = dataframe.filter(self.labelCol + ' = ' + str(self.metricLabel) + ' and ' + self.predCol + ' = ' + str(self.metricLabel)).count()
        fp = dataframe.filter(self.labelCol + ' != ' + str(self.metricLabel) + ' and ' + self.predCol + ' = ' + str(self.metricLabel)).count()
        fn = dataframe.filter(self.labelCol + ' = ' + str(self.metricLabel) + ' and ' + self.predCol + ' != ' + str(self.metricLabel)).count()
        return tp / (tp + (.5 * (fn +fp)))


f1_evaluator = F1BinaryEvaluator()

from pyspark.ml.tuning import ParamGridBuilder, CrossValidator
from pyspark.ml.classification import GBTClassifier
gbt = GBTClassifier()
paramGrid = (ParamGridBuilder()
             .addGrid(gbt.maxDepth, [3, 5, 7])
             .addGrid(gbt.maxBins, [10, 30])
             .addGrid(gbt.maxIter, [10, 15])
             .build())
cv = CrossValidator(estimator=gbt, estimatorParamMaps=paramGrid, evaluator=f1_evaluator, numFolds=5)

cvModel = cv.fit(train)
cv_pred = cvModel.bestModel.transform(test)

简历过程运行没有问题,尽管我不知道性能如何。我还尝试将evaluator与sklearn.metrics.f1_score进行比较,结果接近

from sklearn.metrics import f1_score
print("made-up F1 Score evaluator : ", f1_evaluator.evaluate(cv_pred))
print("sklearn F1 Score evaluator : ", f1_score(cv_pred.select('label').toPandas(), cv_pred.select('prediction').toPandas()))

made-up F1 Score evaluator :  0.9363636363636364
sklearn F1 Score evaluator :  0.9363636363636363

相关问题 更多 >

    热门问题