代码之家  ›  专栏  ›  技术社区  ›  Barranka Avinash Babu

PySpark:获取ROC曲线中每个点的阈值(cuttoff)

  •  0
  • Barranka Avinash Babu  · 技术社区  · 6 年前

    我从PySpark开始,建立二元分类模型(logistic回归),我需要为我的模型找到最佳阈值(cutoff)点。

    我想用ROC曲线来找到这个点,但是我不知道如何提取这个曲线中每个点的阈值。有没有办法找到这个值?

    我发现:

    • This post 显示如何提取ROC曲线,但仅显示TPR和FPR的值。它对绘图和选择最佳点很有用,但我找不到阈值。
    • Here 是一篇描述如何用R。。。不过,我还是要用Pypark

    其他事实

    • 我正在使用数据帧(我真的不知道如何使用RDD,但我不怕学习;)
    1 回复  |  直到 6 年前
        1
  •  3
  •   Alex Ross    5 年前

    probability 来自的响应中的字段 model.transform(test)

    或者,您可以使用 BinaryClassificationMetrics

    不幸的是,PySpark版本似乎没有实现Scala版本所实现的大多数方法,因此需要用Python包装类来实现。

    例如:

    from pyspark.mllib.evaluation import BinaryClassificationMetrics
    
    # Scala version implements .roc() and .pr()
    # Python: https://spark.apache.org/docs/latest/api/python/_modules/pyspark/mllib/common.html
    # Scala: https://spark.apache.org/docs/latest/api/java/org/apache/spark/mllib/evaluation/BinaryClassificationMetrics.html
    class CurveMetrics(BinaryClassificationMetrics):
        def __init__(self, *args):
            super(CurveMetrics, self).__init__(*args)
    
        def _to_list(self, rdd):
            points = []
            # Note this collect could be inefficient for large datasets 
            # considering there may be one probability per datapoint (at most)
            # The Scala version takes a numBins parameter, 
            # but it doesn't seem possible to pass this from Python to Java
            for row in rdd.collect():
                # Results are returned as type scala.Tuple2, 
                # which doesn't appear to have a py4j mapping
                points += [(float(row._1()), float(row._2()))]
            return points
    
        def get_curve(self, method):
            rdd = getattr(self._java_model, method)().toJavaRDD()
            return self._to_list(rdd)
    

    用法:

    import matplotlib.pyplot as plt
    
    preds = predictions.select('label','probability').rdd.map(lambda row: (float(row['probability'][1]), float(row['label'])))
    
    # Returns as a list (false positive rate, true positive rate)
    points = CurveMetrics(preds).get_curve('roc')
    
    plt.figure()
    x_val = [x[0] for x in points]
    y_val = [x[1] for x in points]
    plt.title(title)
    plt.xlabel(xlabel)
    plt.ylabel(ylabel)
    plt.plot(x_val, y_val)
    

    结果: ROC curve generated with BinaryClassificationMetrics

    下面是一个例子,如果你没有嫁给ROC,F1分数曲线的阈值: F1 score by threshold curve using BinaryClassificationMetrics

        2
  •  1
  •   pault Tanjin    6 年前

    一种方法是使用 sklearn.metrics.roc_curve .

    首先使用您的模型进行预测:

    from pyspark.ml.classification import LogisticRegression
    
    lr = LogisticRegression(labelCol="label", featuresCol="features")
    model = lr.fit(trainingData)
    predictions = model.transform(testData)
    

    1 :

    preds = predictions.select('label','probability')\
        .rdd.map(lambda row: (float(row['probability'][1]), float(row['label'])))\
        .collect()
    

    现在转换 preds 与…共事 roc_curve

    from sklearn.metrics import roc_curve
    
    y_score, y_true = zip(*preds)
    fpr, tpr, thresholds = roc_curve(y_true, y_score, pos_label = 1)
    

    笔记

    1. 我不是百分之百确定概率向量总是有序的,这样正标签就会在索引处 1 . 然而,在二进制分类问题中,如果AUC小于0.5,您将立即知道。如果是那样的话,那就吃吧 1-p