0

У меня есть результаты машинного обучения, которые я пытаюсь понять. Задача состоит в том, чтобы предсказать/обозначить «ирландский» и «неирландский». Python 2.7 в выходной:Как объяснить высокий AUC-ROC с посредственной точностью и отзывом в несбалансированных данных?

1= ir 
0= non-ir 
Class count: 
0 4090942 
1  940852 
Name: ethnicity_scan, dtype: int64 
Accuracy: 0.874921350119 
Classification report: 
      precision recall f1-score support 

      0  0.89  0.96  0.93 2045610 
      1  0.74  0.51  0.60 470287 

avg/total  0.87  0.87  0.87 2515897 

Confusion matrix: 
[[1961422 84188] 
[ 230497 239790]] 
AUC-ir= 0.9

Как вы можете видеть, точность и вспомнить посредственные, но АУК-ROC выше (~ 0,90). И я пытаюсь выяснить, почему, что, как я подозреваю, связано с дисбалансом данных (около 1: 5). Основываясь на матрице путаницы, и используя ирландский в качестве цели (+), я вычислил TPR = 0,51 и FPR = 0,04. Если я рассматриваю неирландский как (+), то TPR = 0,96 и FPR = 0,49. Итак, как я могу получить 0.9 AUC, в то время как TPR может быть всего 0,5 при FPR = 0,04?

коды:

try: 
    for i in mass[k]: 
     df = df_temp # reset df before each loop 
     #$$ 
     #$$ 
     if 1==1: 
     ###if i == singleEthnic: 
      count+=1 
      ethnicity_tar = str(i) # fr, en, ir, sc, others, ab, rus, ch, it, jp 
      # 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 = df.sample(n=subsample_size, random_state=seed) # Seed gives fixed randomness 
      df = DataFrame(rows) 
      print 'Class count:' 
      print df['ethnicity_scan'].value_counts() 

      # Assign X and y variables 
      X = df.raw_name.values 
      X2 = df.name.values 
      X3 = df.gender.values 
      X4 = df.location.values 
      y = df.ethnicity_scan.values 

      # Feature extraction functions 
      def feature_full_name(nameString): 
       try: 
        full_name = nameString 
        if len(full_name) > 1: # not accept name with only 1 character 
         return full_name 
        else: return '?' 
       except: return '?' 

      def feature_full_last_name(nameString): 
       try: 
        last_name = nameString.rsplit(None, 1)[-1] 
        if len(last_name) > 1: # not accept name with only 1 character 
         return last_name 
        else: return '?' 
       except: return '?' 

      def feature_full_first_name(nameString): 
       try: 
        first_name = nameString.rsplit(' ', 1)[0] 
        if len(first_name) > 1: # not accept name with only 1 character 
         return first_name 
        else: return '?' 
       except: return '?' 

      # 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_dict5 = [{'first-name': 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_dict5[i].items() 
        ) 
       all_dict.append(temp_dict) 

      newX = dv.fit_transform(all_dict) 

      # Separate the training and testing data sets 
      X_train, X_test, y_train, y_test = cross_validation.train_test_split(newX, y, test_size=testTrainSplit) 

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

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

вставленные коды для передискретизации:

try: 
    for i in mass[k]: 
     df = df_temp # reset df before each loop 
     #$$ 
     #$$ 
     if 1==1: 
     ###if i == singleEthnic: 
      count+=1 
      ethnicity_tar = str(i) # fr, en, ir, sc, others, ab, rus, ch, it, jp 
      # 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 

      # Resampled 
      df_resampled = df.append(df[df.ethnicity_scan==0].sample(len(df)*5, replace=True)) 

      # Random sampling a smaller dataframe for debugging 
      rows = df_resampled.sample(n=subsample_size, random_state=seed) # Seed gives fixed randomness 
      df = DataFrame(rows) 
      print 'Class count:' 
      print df['ethnicity_scan'].value_counts() 

      # Assign X and y variables 
      X = df.raw_name.values 
      X2 = df.name.values 
      X3 = df.gender.values 
      X4 = df.location.values 
      y = df.ethnicity_scan.values 

      # Feature extraction functions 
      def feature_full_name(nameString): 
       try: 
        full_name = nameString 
        if len(full_name) > 1: # not accept name with only 1 character 
         return full_name 
        else: return '?' 
       except: return '?' 

      def feature_full_last_name(nameString): 
       try: 
        last_name = nameString.rsplit(None, 1)[-1] 
        if len(last_name) > 1: # not accept name with only 1 character 
         return last_name 
        else: return '?' 
       except: return '?' 

      def feature_full_first_name(nameString): 
       try: 
        first_name = nameString.rsplit(' ', 1)[0] 
        if len(first_name) > 1: # not accept name with only 1 character 
         return first_name 
        else: return '?' 
       except: return '?' 

      # 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_dict5 = [{'first-name': 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_dict5[i].items() 
        ) 
       all_dict.append(temp_dict) 

      newX = dv.fit_transform(all_dict) 

      # Separate the training and testing data sets 
      X_train, X_test, y_train, y_test = cross_validation.train_test_split(newX, y, test_size=testTrainSplit) 

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

      # Making predictions using trained data 
      y_train_predictions = classifierUsed2.predict(X_train) 
      y_test_predictions = classifierUsed2.predict(X_test) 
+0

Возможный дубликат [Хорошая кривая ROC, но плохая кривая критического значения) (http://stackoverflow.com/questions/33294574/good-roc-curve-but-poor-precision-recall-curve) – Calimo

ответ

1

Ваша модель выводит вероятности P (от 0 до 1) для каждой строки в тесте установлено, что она набирает. Суммарная статистика (точность, отзыв и т. Д.) Относится к одному значению P в качестве порога прогнозирования, вероятно, P = 0,5, если вы не изменили это в своем коде. Однако ROC содержит больше информации, идея состоит в том, что вы, вероятно, не захотите использовать это значение по умолчанию в качестве порога прогнозирования, поэтому ROC рассчитывается путем вычисления отношения истинных положительных значений к ложным срабатываниям через каждый порог прогнозирования betwen 0 и 1.

Если вы указали на своих неирландских людей данные без изменений, то вы правы, что AUC и точность будут завышены; если ваш набор данных составляет всего 5000 строк, тогда у вас не будет проблем с запуском вашей модели на более крупном наборе тренировок; просто перебалансируйте свой набор данных (путем выборочного опроса, чтобы увеличить ваши неирландские люди), пока вы точно не отразите свою выборку населения.

+0

Я не знаю, t изменил значение P, поэтому оно должно быть 0,5. Для целей отчетности, нормально ли мне сообщать о существующей точности, отзыве и ROC как есть (при использовании значения по умолчанию P = 0,5)? – KubiK888

+0

Нет, это определенно не нормально, вы будете сильно преувеличивать, насколько эффективна ваша модель, не делайте этого! – maxymoo

+0

Пожалуйста, помогите мне понять, откуда вы пришли, вы, кажется, намекаете на возможное «преувеличение» эффективности из-за дисбаланса данных. Но я использую показатели производительности, которые должны быть чувствительны к нему (например, оценка F1, точность и отзыв). Итак, почему отчетность даже оценка, точность и отзыв F1 преувеличивают производительность? (примечание: я слышал о методе перерасчета/понижающей дискретизации для данных дисбаланса, но у них есть свои собственные ловушки, такие как потеря информации или слишком тщательное моделирование с дублированным шумом и т. д.) – KubiK888

 Смежные вопросы

  • Нет связанных вопросов^_^