簡體   English   中英

如何在 pyspark 2.3 中的二元問題(BinaryClassificationEvaluator)中將 f1-score 用於 CrossValidator 評估器

[英]How to use f1-score for CrossValidator evaluator in a binary problem(BinaryClassificationEvaluator) in pyspark 2.3

我的用例是一個常見用例:帶有不平衡標簽的二元分類,因此我們決定使用 f1-score 通過交叉驗證進行超參數選擇,我們使用 pyspark 2.3 和 pyspark.ml,我們創建了一個 CrossValidator 對象,但對於評估者,問題如下:

  • BinaryClassificationEvaluator 沒有 f1 分數作為評估指標。
  • MulticlassClassificationEvaluator 有 f1 分數,但返回錯誤的結果,我的猜測是它為每個類計算 f1(在這種情況下只有 2)並返回它們的某種平均值,因為負類(y = 0)占主導地位,它產生高f1 但模型真的很糟糕(正類的 f1 分數為 0)
  • MulticlassClassificationEvaluator 在最近的版本中添加了參數 evaluator.metricLabel,我認為它允許指定要使用的標簽(在我的情況下,我將其設置為 1),但它在 spark 2.3 上不可用

但問題是:我使用公司/企業 Spark 集群,沒有升級當前版本(2.3)的計划,所以問題是:考慮到我們僅限於 Spark 2.3,我如何在 CrossValidator 評估器中使用 f1 分數進行二進制案例

如果您可以使用 Spark v3.0+,最簡單的方法是使用F-measure by label metric 並指定標簽(並將 beta 設置為 1):

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

但是由於您僅限於 v2.3,您可以

  1. 重新實現 CrossValidator 功能。 pyspark.mllib.evaluation.MulticlassMetricsfMeasure by label 方法。 請參閱示例以供參考。

  2. 改變你的度量areaUnderPRBinaryClassificationEvaluator ,這是一種“模型優度”指標,而應該為你做這項工作(重新平衡標簽)。 這篇博文比較了 F1 和 AUC-PR。

您可以為此創建一個類。 我公司的 spark 2.4 也有同樣的問題,所以我嘗試為二元分類制作一個 F1 分數評估器。 我必須為新類指定.evaluate.isLargerBetter方法。 這是我嘗試使用數據集時的示例代碼:

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)

CV 過程運行沒有問題,但我不知道性能。 我還嘗試將評估器與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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM