Не удается создать кривую ROC-AUC из наивного байесовского классификатора.

Я пытаюсь предсказать этническую принадлежность, используя функции, полученные из определенных переменных. Из моего предыдущего вопроса Как интерпретировать эту кривую ROC AUC треугольной формы? я научился использовать функцию решения или прогнозировать_пробу вместо фактических прогнозов, чтобы соответствовать кривой ROC.

Я могу создать график ROC-AUC, используя следующие коды, с классификатором SVM

# coding=utf-8
import pandas as pd
from pandas import DataFrame, Series
import numpy as np
import nltk
import re
import random
from random import randint
import csv
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

from sklearn.metrics import classification_report
from sklearn.svm import LinearSVC
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction import DictVectorizer
from sklearn.metrics import confusion_matrix as sk_confusion_matrix
from sklearn.metrics import roc_curve, auc
import matplotlib.pyplot as plt

# multi_class : str, {'ovr', 'multinomial'}
#$$
lr = LogisticRegression()
#lr = LogisticRegression(penalty='l2', class_weight='auto', solver='lbfgs', multi_class='multinomial')
nb = MultinomialNB(fit_prior=False)
#$$
svm = LinearSVC(class_weight='auto')

dv = DictVectorizer()

# Get csv file into data frame
data = pd.read_csv("FamilySearchData_All_OCT2015_newEthnicity_filledEthnicity_processedName_trimmedCol.csv", header=0, encoding="utf-8")
df = DataFrame(data)

# Class list
ethnicity2 = ['fr', 'en', 'ir', 'sc', 'others', 'ab', 'rus', 'ch', 'it', 'ja']
Ab_group = ['fr', 'en', 'ir', 'sc', 'others', 'ab', 'rus', 'ch', 'it', 'ja', 'fn', 'metis', 'inuit']
Ab_lang = ['fr', 'en', 'ir', 'sc', 'others', 'ab', 'rus', 'ch', 'it', 'ja', 'x', 'y']

############################################
########## CONTROL ROOM ####################
# change-tag: '#$$'
# Output file name decoration
# Total N = 5031794
#$$
featureUsed = 8
#$$
subsample_size = 50000
#$$
ethnicity_var = 'ethnicity2' # Ab_group, Ab_tribe, Ab_lang
count = 0

# Declaration
print 'No. features=', featureUsed
print 'N=', subsample_size, 'Training_N=', subsample_size/2, 'Test_N=', subsample_size/2
print 'ethnicity_var:', ethnicity_var
#$$
print ethnicity2
#$$
print 'ML classifier:', 'svm = LinearSVC(class_weight=\'auto\')'
print ''
print '//////////////////////////////////////////////////////'
print ''

try:
    #$$
    for i in ethnicity2:
        count+=1
        ethnicity_tar = str(i) # fr, en, ir, sc, others, ab, rus, ch, it, ja
        # fn, metis, inuit; algonquian, iroquoian, athapaskan, wakashan, siouan, salish, tsimshian, kootenay
        ############################################
        ############################################

        def ethnicity_target(row):
            try:
                if row[ethnicity_var] == ethnicity_tar:
                    return 1
                else:
                    return 0
            except: return None
        df['ethnicity_scan'] = df.apply(ethnicity_target, axis=1)
        print '1=', ethnicity_tar
        print '0=', 'non-'+ethnicity_tar

        # Random sampling a smaller dataframe for debugging
        rows = random.sample(df.index, subsample_size)
        df = df.ix[rows] # Warning!!!! overwriting original df
        print 'Class count:'
        print df['ethnicity_scan'].value_counts()

        # Assign X and y variables
        X = df.raw_name.values
        y = df.ethnicity_scan.values

        # Feature extraction functions
        def feature_full_name(nameString):
            #... codes omitted

        # Transform format of X variables, and spit out a numpy array for all features
        my_dict = [{'last-name': feature_full_last_name(i)} for i in X]
        my_dict2 = [list_to_dict(feature_twoLetters(feature_full_last_name(i))) for i in X]
        my_dict3 = [list_to_dict(feature_threeLetters(feature_full_last_name(i))) for i in X]
        my_dict4 = [list_to_dict(feature_fourLetters(feature_full_last_name(i))) for i in X]

        my_dict5 = [{'first-name': feature_full_first_name(i)} for i in X]
        my_dict6 = [list_to_dict(feature_twoLetters(feature_full_first_name(i))) for i in X]
        my_dict7 = [list_to_dict(feature_threeLetters(feature_full_first_name(i))) for i in X]
        my_dict8 = [list_to_dict(feature_fourLetters(feature_full_first_name(i))) for i in X]

        all_dict = []
        for i in range(0, len(my_dict)):
            temp_dict = dict(my_dict[i].items() + my_dict2[i].items() + my_dict3[i].items() + my_dict4[i].items()
                + my_dict5[i].items() + my_dict6[i].items() + my_dict7[i].items() + my_dict8[i].items())
            all_dict.append(temp_dict)

        newX = dv.fit_transform(all_dict)

        # Separate the training and testing data sets
        half_cut = int(len(df)/2.0)*-1
        X_train = newX[:half_cut]
        X_test = newX[half_cut:]
        y_train = y[:half_cut]
        y_test = y[half_cut:]

        # Fitting X and y into model, using training data
        #$$
        svm.fit(X_train, y_train)

        # Making predictions using trained data
        #$$
        y_train_predictions = svm.predict(X_train)
        #$$
        y_test_predictions = svm.predict(X_test)

        #print (y_train_predictions == y_train).sum().astype(float)/(y_train.shape[0])
        print 'Accuracy:',(y_test_predictions == y_test).sum().astype(float)/(y_test.shape[0])

        print 'Classification report:'
        print classification_report(y_test, y_test_predictions)
        #print sk_confusion_matrix(y_train, y_train_predictions)
        print 'Confusion matrix:'
        print sk_confusion_matrix(y_test, y_test_predictions)

        #print y_test[1:20]
        #print y_test_predictions[1:20]

        #print y_test[1:10]
        #print np.bincount(y_test)
        #print np.bincount(y_test_predictions)

        # Find and plot AUC
        false_positive_rate, true_positive_rate, thresholds = roc_curve(y_test, y_test_predictions)
        roc_auc = auc(false_positive_rate, true_positive_rate)

        # Find and plot AUC
        y_score = svm.fit(X_train, y_train).decision_function(X_test)
        false_positive_rate, true_positive_rate, thresholds = roc_curve(y_test, y_score)
        roc_auc = auc(false_positive_rate, true_positive_rate)
        print 'AUC-'+ethnicity_tar+'=',roc_auc

        # Get different color each graph line
        colorSet = ['navy', 'greenyellow', 'deepskyblue', 'darkviolet', 'crimson', 
            'darkslategray', 'indigo', 'brown', 'orange', 'palevioletred', 'mediumseagreen',
            'k', 'darkgoldenrod', 'g', 'midnightblue', 'c', 'y', 'r', 'b', 'm', 'lawngreen'
            'mediumturquoise', 'lime', 'teal', 'drive', 'sienna', 'sandybrown']
        color = colorSet[count-1]

        # Plotting
        plt.title('ROC')
        plt.plot(false_positive_rate, true_positive_rate, c=color, label=('AUC-'+ethnicity_tar+'= %0.2f'%roc_auc))
        plt.legend(loc='lower right', prop={'size':8})
        plt.plot([0,1],[0,1], color='lightgrey', linestyle='--')
        plt.xlim([-0.05,1.0])
        plt.ylim([0.0,1.05])
        plt.ylabel('True Positive Rate')
        plt.xlabel('False Positive Rate')
        #plt.show()
        # Save ROC graphs
        plt.savefig('TESTROCXXX.jpg')

        print ''
        print '//////////////////////////////////////////////////////'
        print ''
except Exception as e:
    print 'Error:', str(e)
    print ''
    print '//////////////////////////////////////////////////////'
    print ''

Который дает:

введите здесь описание изображения

Но когда я пытаюсь использовать наивный байесовский классификатор, я сделал следующие изменения:

nb.fit(X_train, y_train) # from svm.fit(X_train, y_train)

y_train_predictions = nb.predict(X_train) # from y_train_predictions = svm.predict(X_train)

y_test_predictions = nb.predict(X_test) # from y_test_predictions = svm.predict(X_test)

y_score = nb.fit(X_train, y_train).predict_proba(X_test) # from y_score = svm.fit(X_train, y_train).decision_function(X_test)

Однако я получаю сообщение об ошибке:

Error: bad input shape (25000L, 2L)

Отредактировано: после добавления [:, 1], как было предложено, я показал 4 графика ROC, последние два - NB, которые выглядят странно.

введите здесь описание изображения

введите здесь описание изображения

введите здесь описание изображения

введите здесь описание изображения


person KubiK888    schedule 20.10.2015    source источник
comment
В какой именно строке возникает эта ошибка? Какую форму имеют X_test и X_train? Кроме того, почему вы называете fit на nb (и svm) второй раз? У вас уже есть обученная модель на этих данных. Вы можете просто вызвать nb.predict_proba(X_test) в последней строке.   -  person Ibraim Ganiev    schedule 20.10.2015
comment
Вы импортируете nltk в свой пример. Это все еще необходимо?   -  person colidyre    schedule 20.10.2015
comment
@Olologin Ошибка возникает после оператора predict_proba, в частности, в «false_positive_rate, true_positive_rate, thresholds = roc_curve (y_test, y_score)». X_test и X_train представляют собой разреженные матрицы формы (25000, 63470).   -  person KubiK888    schedule 20.10.2015
comment
@colidyre Нет, это не обязательно, но это не имеет значения   -  person KubiK888    schedule 20.10.2015


Ответы (1)


Я забыл упомянуть в этом ответе https://stackoverflow.com/a/33218642/1030820, что вам нужно выбрать некоторые столбец (из двух возможных) в случае, если вы используете результаты predict_proba для roc_curve.

false_positive_rate, true_positive_rate, thresholds = roc_curve(y_test, y_score[:,1])

Это может сработать.

Добавлено: Ну, это Наивный Байес, в большинстве случаев он не должен побеждать LR. Это более простая модель, чем LR, и она не может улавливать взаимодействие между функциями (кстати, поэтому она называется наивной). В статьях по машинному обучению авторы часто используют NB только для того, чтобы сделать некую отправную точку в точности, показать результат простейшего алгоритма машинного обучения и сравнить с ним более продвинутые алгоритмы.

Смотрите также здесь: http://scikit-learn.org/stable/modules/naive_bayes.html#naive-bayes

С другой стороны, несмотря на то, что наивный байесовский метод известен как достойный классификатор, известно, что он является плохой оценкой, поэтому к выходным данным по вероятности, получаемым от predict_proba, не следует относиться слишком серьезно.

person Ibraim Ganiev    schedule 20.10.2015
comment
Я добавил его (пожалуйста, смотрите мои правки выше). Он генерирует график ROC и AUC, но это выглядит странно (что-то вроде моего предыдущего вопроса). - person KubiK888; 20.10.2015
comment
Так что, вероятно, это не из-за моей возможной ошибки в кодировании, несмотря на странный вид графика для NB? Я делаю ошибку где-то, о чем я не знаю, вот о чем я беспокоюсь. - person KubiK888; 20.10.2015
comment
Также по другому вопросу: «fr» всегда получает очень высокий RUC, несмотря на то, что я намеренно использую очень низкие тренировочные данные 1k (50:50 обучение/тест). Это ожидается? («fr» — один из самых высоких классов распространенности, включающий около 1/3 всех данных) - person KubiK888; 20.10.2015
comment
Я не проверял ваш код, но графики выглядят нормально. Вы тренируете классификаторы как OneVsAll? то есть вы обучаете каждого классификатора различать его классы и любые другие? - person Ibraim Ganiev; 20.10.2015
comment
pred_proba[:,1] — это ключ. Если вы передадите pred_proba без выбора 1-го столбца, вы получите сообщение об ошибке, что вы передаете двумерный массив в одномерный параметр. - person Golden Lion; 02.12.2020