PySpark: получить значения Threshold (cuttoff) для каждой точки кривой ROC - PullRequest
0 голосов
/ 29 января 2019

Я начинаю с PySpark, строю бинарные классификационные модели (логистическая регрессия), и мне нужно найти оптимальную точку порога (отсечки) для моих моделей.

Я хочу использовать кривую ROC, чтобы найтиэта точка, но я не знаю, как извлечь пороговое значение для каждой точки на этой кривой.Есть ли способ найти эти значения?

Вещи, которые я нашел:

  • В этом посте показано, как извлечь ROCкривая, но только значения для TPR и FPR.Это полезно для построения графика и выбора оптимальной точки, но я не могу найти пороговое значение.
  • Я знаю, что могу найти пороговые значения для каждой точки кривой ROC, используя H2O (я сделал этораньше), но я работаю над Pyspark.
  • Здесь - пост, описывающий, как это сделать с R ... но, опять же, мне нужно сделать это с Pyspark

Другие факты

  • Я использую Apache Spark 2.4.0.
  • Я работаю с фреймами данных (я действительнопока не знаю - как работать с СДР, но я не боюсь учиться;))

Ответы [ 2 ]

0 голосов
/ 04 августа 2019

Если вам конкретно необходимо сгенерировать кривые ROC для разных порогов, одним из подходов может быть создание списка пороговых значений, которые вас интересуют, и подгонка / преобразование в вашем наборе данных для каждого порога.Или вы можете вручную рассчитать ROC-кривую для каждой пороговой точки, используя поле probability в ответе от model.transform(test).

В качестве альтернативы, вы можете использовать BinaryClassificationMetrics , чтобы извлечь кривую, отображающую различныеметрики (оценка F1, точность, отзыв) по порогу.

К сожалению, похоже, что версия 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)
roc = 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

Вот пример кривой оценки F1 по пороговому значению, если выне состоят в браке с РПЦ: F1 score by threshold curve using BinaryClassificationMetrics

0 голосов
/ 29 января 2019

Одним из способов является использование 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. Я не уверен на 100%, что вектор вероятностей всегда будетупорядочено так, что положительный ярлык будет по индексу 1.Однако в случае проблемы двоичной классификации вы сразу узнаете, меньше ли ваш AUC, чем 0,5.В этом случае просто возьмите 1-p для вероятностей (поскольку вероятности класса составляют 1).
...