scikit-learn .predict () поріг за замовчуванням


75

Я працюю над проблемою класифікації з незбалансованими класами (5% 1). Я хочу передбачити клас, а не ймовірність.

У бінарної задачі класифікації є scikit - х , classifier.predict()використовуючи 0.5за замовчуванням? Якщо ні, який метод за замовчуванням? Якщо це так, як я можу це змінити?

У scikit деякі класифікатори мають class_weight='auto'можливість, але не всі. Чи використовували class_weight='auto'б .predict()фактичну частку населення як поріг?

Який спосіб зробити це в такому класифікаторі MultinomialNB, який не підтримує class_weight? Крім використання, predict_proba()а потім обчислення класів самостійно.

Відповіді:


42

чи classifier.predict()за замовчуванням scikit використовує 0,5?

У імовірнісних класифікаторах, так. Це єдиний розумний поріг з математичної точки зору, як пояснювали інші.

Який спосіб зробити це в класифікаторі, як MultinomialNB, який не підтримує class_weight?

Ви можете встановити значення class_prior, яке є попередньою ймовірністю P ( y ) для класу y . Це фактично зміщує межу прийняття рішення. Напр

# minimal dataset
>>> X = [[1, 0], [1, 0], [0, 1]]
>>> y = [0, 0, 1]
# use empirical prior, learned from y
>>> MultinomialNB().fit(X,y).predict([1,1])
array([0])
# use custom prior to make 1 more likely
>>> MultinomialNB(class_prior=[.1, .9]).fit(X,y).predict([1,1])
array([1])

Здається, для RandomForestClassifier немає class_prior. Як це зробити?
famargar

2
RandomForestClassifier не має параметра class_prior, але він має параметр class_weight, який можна використовувати.
lbcommer

4
Насправді значення за замовчуванням 0,5 є довільним і не повинно бути оптимальним, як зауважив, наприклад, у цій відповіді на резюме Френк Харрелл, який є резектованим органом.
Тім

"У імовірнісних класифікаторах, так. Це єдиний розумний поріг з математичної точки зору, як пояснювали інші". - Це здається абсолютно поза базою. Що робити, якщо ви хочете, наприклад, зважити вага надто точно?
cyniphile

39

Поріг можна встановити за допомогою clf.predict_proba()

наприклад:

from sklearn.tree import DecisionTreeClassifier
clf = DecisionTreeClassifier(random_state = 2)
clf.fit(X_train,y_train)
# y_pred = clf.predict(X_test)  # default threshold is 0.5
y_pred = (clf.predict_proba(X_test)[:,1] >= 0.3).astype(bool) # set threshold as 0.3

7
Для уточнення ви не встановлюєте поріг , оскільки це означатиме, що ви постійно змінюєте поведінку clf.predict(), чого не робите.
pcko1

Це правильна відповідь. Я не міг побачити у джерелі MLP, де вони роблять поріг 0,5, хоча ...
eggie5

Як би ви пов’язали це з GridSearchCV, де прогнозування є внутрішнім і недоступним для вас? Скажімо, поріг 0,3 дав би мені інший найкращий вибір моделі.
demongolem

2
Я думаю, що GridSearchCV використовуватиме лише порогове значення за замовчуванням 0,5. Нерозумно змінювати цей поріг під час тренувань, тому що ми хочемо, щоб все було чесно. Лише на заключній фазі прогнозування ми налаштовуємо поріг ймовірності на користь більш позитивного чи негативного результату. наприклад, щоб мати більшу швидкість захоплення (за рахунок вищої помилкової тривоги), ми можемо знизити поріг вручну.
Yuchao Jiang

37

Порогове значення в scikit learn становить 0,5 для двійкової класифікації, і будь-який клас має найбільшу ймовірність для багатокласової класифікації. У багатьох проблемах набагато кращий результат можна отримати, регулюючи поріг. Однак це потрібно робити обережно, а НЕ щодо даних випробувальних тестів, а шляхом перехресного підтвердження даних про навчання. Якщо ви виконуєте будь-яке коригування порогового значення для даних тесту, ви просто переоблаштовуєте дані тесту.

Більшість методів регулювання порогу базуються на робочих характеристиках приймача (ROC) та статистиці J Юдена, але це також може бути зроблено іншими методами, такими як пошук за генетичним алгоритмом.

Ось стаття журналу експертних оглядів, що описує це в медицині:

http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2515362/

Наскільки я знаю, для Python не існує пакету, але знайти його за допомогою грубої сили в Python досить просто (але неефективно).

Це якийсь код R, який це робить.

## load data
DD73OP <- read.table("/my_probabilites.txt", header=T, quote="\"")

library("pROC")
# No smoothing
roc_OP <- roc(DD73OP$tc, DD73OP$prob)
auc_OP <- auc(roc_OP)
auc_OP
Area under the curve: 0.8909
plot(roc_OP)

# Best threshold
# Method: Youden
#Youden's J statistic (Youden, 1950) is employed. The optimal cut-off is the threshold that maximizes the distance to the identity (diagonal) line. Can be shortened to "y".
#The optimality criterion is:
#max(sensitivities + specificities)
coords(roc_OP, "best", ret=c("threshold", "specificity", "sensitivity"), best.method="youden")
#threshold specificity sensitivity 
#0.7276835   0.9092466   0.7559022

5
Чудовий пост! Найважливіший момент: "Якщо ви виконуєте будь-яке коригування порогового значення для ваших тестових даних, ви просто переорієнтуєте тестові дані".
Sven R. Kunze,

7

Здається, ви плутаєте тут поняття. Поріг не є поняттям "загального класифікатора" - найбільш базові підходи базуються на певному регульованому порозі, але більшість існуючих методів створюють складні правила класифікації, які не можуть (або, принаймні, не повинні) розглядатися як порогові значення.

Отже, спочатку - не можна відповісти на ваше запитання щодо порогу за замовчуванням класифікатора scikit, оскільки такого немає.

Зважування другого класу - це не поріг, це здатність класифікатора мати справу з незбалансованими класами, і це щось, що залежить від конкретного класифікатора. Наприклад - у випадку SVM це спосіб зважування слабких змінних у задачі оптимізації, або, якщо ви віддаєте перевагу, верхні межі значень множників Лагранжа, пов’язані з певними класами. Встановити для цього значення "авто" означає використання певної евристики за замовчуванням, але ще раз - це не може бути просто переведено в деяке порогове значення.

Наївний Байєс, з іншого боку, безпосередньо оцінює ймовірність занять за набором тренувань. Він називається "class prior", і ви можете встановити його в конструкторі зі змінною "class_prior".

З документації :

Попередні ймовірності занять. Якщо вказано, пріоритети не коригуються відповідно до даних.


2
Дозвольте пояснити це по-іншому, тоді можете сміливо сказати, що я все ще розгублений :-) Скажімо, у мене два класи. Більшість класифікаторів прогнозують ймовірність. Я можу використати ймовірність для оцінки своєї моделі, скажімо, використовуючи ROC. Але якби я хотів передбачити клас, мені потрібно було б вибрати межу, скажімо 0,5, і сказати: "кожне спостереження з р <0,5 переходить до класу 0, а ті, хто має р> 0,5, переходять до класу 1. Це, як правило, добре вибір, якщо ваші пріоритети складають 0,5-0,5. Але для незбалансованих проблем мені знадобиться інший відсік. Моє питання справді задавав питання про те, як обробляється це відсікання в scikit при використанні .predict ().
ADJ

Більшість класифікаторів не є імовірнісними. Той факт, що вони можуть якось "продукувати" цю ймовірність (оцінку), не означає, що вони насправді "використовують її" для прогнозування. Ось чому я розглядаю це як можливу плутанину. Прогнозування викликає рутину оригінальної моделі, яка використовується для прогнозування, вона може бути імовірнісною (NB), геометричною (SVM), заснованою на регресії (NN) або заснованою на правилах (Дерева), тому питання щодо значення ймовірності всередині predict () здається концептуальна плутанина.
lejlot

2
@lejlot, якщо це так, то чи не стала б також неактуальною і вся концепція кривої roc, побудована за допомогою predict_proba? Чи не застосовуються до результатів predict_proba різні точки кривої roc, побудовані на різних порогах?
Євген Брагін

2

На випадок, якщо хтось відвідає цей потік, сподіваючись на готову до використання функцію (python 2.7). У цьому прикладі відсікання призначене для відображення співвідношення подій та не подій у вихідному наборі даних df , тоді як y_prob може бути результатом методу .predict_proba (припускаючи розшарування поділу поїзд / тест).

def predict_with_cutoff(colname, y_prob, df):
    n_events = df[colname].values
    event_rate = sum(n_events) / float(df.shape[0]) * 100
    threshold = np.percentile(y_prob[:, 1], 100 - event_rate)
    print "Cutoff/threshold at: " + str(threshold)
    y_pred = [1 if x >= threshold else 0 for x in y_prob[:, 1]]
    return y_pred

Не соромтеся критикувати / змінювати. Сподіваюся, це допомагає у рідкісних випадках, коли про балансування класів не може бути й мови, а сам набір даних є дуже незбалансованим.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.