Аналитические данные, основанные на реальных наборах данных

Автор:: Юваль Коэн, Ноа Коэн и Авиад Атлас.

Введение

Одна из тем, с которой сталкивается каждый специалист по обработке данных, младший или старший, в каждом проекте по науке о данных - это выбор функций. В этой статье, состоящей из двух частей, мы хотим поделиться своим опытом решения реальных проблем. В части 1 ниже мы представляем временной анализ различных методов выбора функций, которые мы использовали, и описываем, как они влияют на точность наших моделей. Во второй части мы рассмотрим интересную идею комбинирования методов выбора функций - как это сделать и почему вам это нужно.

Наша команда по анализу данных в Blue dot (AKA - The Vatvengers) занимается производственными проблемами, а также исследовательскими задачами и новыми идеями. Как вы понимаете, одна из проблем, над которой мы много работаем, - это выбор функций. Некоторые из наших моделей содержат огромное количество функций, которые могут замедлить процесс обучения и вызвать потерю точности на тестовом наборе. Итак, мы решили глубже погрузиться в проблему и вернулись с новыми и интересными выводами.

Описание методов

ReliefF

Основная идея алгоритмов ReliefF состоит в том, чтобы оценить качество функций в зависимости от того, насколько хорошо функция может различать близкие друг к другу образцы. ReliefF принадлежит к семейству алгоритмов Relief, используемых специально для задач множественной классификации. Более подробную информацию об этом методе вы можете найти здесь.

import numpy as np
from ReliefF import ReliefF
def relieff(X_train, y_train, n_neighbors, n_features_to_keep):
   fs = ReliefF(n_neighbors=n_neighbors,    n_features_to_keep=n_features_to_keep)
   X_train_new = fs.fit_transform(np.array(X_train), np.array(y_train))
   pos = pd.DataFrame(fs.feature_scores.reshape(-1,1)).sort_values(by=0, ascending=False).head(n_features_to_keep).index.tolist()
   return list(X_train.columns[pos])

Хи-квадрат

В этом методе мы вычисляем статистику хи-квадрат между каждой характеристической переменной и целевой переменной, чтобы понять взаимосвязь между ними. Если целевая переменная не зависит от переменной функции, мы можем отбросить эту переменную функции. Если они зависимы, важна переменная функции. Более подробную информацию об этом методе вы можете найти здесь.

from sklearn.feature_selection import SelectKBest, chi2
def chi_square(X_train, y_train, n):
   selector = SelectKBest(chi2, k=n)
   selector.fit(X_train, y_train)
   cols = selector.get_support(indices=True)
   cols_names = list(X_train.iloc[:, cols].columns)
   return cols_names

Борута

Основная концепция состоит в том, что мы обучаем модель на основе дерева (например, случайный лес), а затем создаем теневые объекты для каждой функции в нашем наборе. Затем мы отфильтровываем элементы, которые плохо работали по сравнению с теневыми элементами, на основе важности встроенных функций модели. Вы можете найти более подробное объяснение здесь.

from boruta import BorutaPy
import numpy as np
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_jobs=-1)
def boruta(clf, X, y):
   boruta = BorutaPy(estimator=clf, n_estimators='auto', max_iter=100  # number of trials to perform)
   ### fit Boruta (it accepts np.array, not pd.DataFrame)
   boruta.fit(np.array(X), np.array(y))
   green_area = X.columns[boruta.support_].to_list()
   blue_area = X.columns[boruta.support_weak_].to_list()
   return green_area, blue_area

Важность перестановки

В этом методе мы перетасовываем каждую функцию отдельно и подбираем новую модель. Мы сохраняем функции, для которых наблюдаем более высокое падение точности (или любой другой показатель). Вы найдете дополнительные пояснения в документации sklearn.

from sklearn.inspection import permutation_importance
def permutation_importance(clf, X, y, n_repeats):
   result = permutation_importance(clf, X, y, n_repeats=n_repeats, random_state=0)
"""
The following is a proposal in scikit-learn's doc to select the features
"""
   chosen_feats = []
   for i in result.importances_mean.argsort()[::-1]:
   if result.importances_mean[i] - 2 * result.importances_std[i] >0:
   chosen_feats.append(X.columns[i])
   return chosen_feats, result

RFE

RFE - это алгоритм выбора функций типа оболочки. RFE работает путем поиска подмножества функций, начиная со всех функций в наборе обучающих данных и успешно удаляя функции, пока не останется желаемое число. Чем это отличается от обратного выбора? После создания полной модели мы измеряем значение важности функции для каждой функции и сортируем предикторы от самого высокого до самого низкого. На каждой итерации мы отбрасываем наименее важные предикторы. Чтобы вычислить важность функции, у нас есть алгоритмы машинного обучения, которые предлагают нам эти оценки (например, случайный лес) или используют
более общий подход, который не зависит от полной модели. Смотрите дополнительные пояснения здесь.

from sklearn.feature_selection import RFE
from sklearn.tree import DecisionTreeClassifier
def rfe(X_train, y_train, n):
   model = DecisionTreeClassifier()
   rfe = RFE(model, n_features_to_select=n, step=1, verbose=2)
   rfe = rfe.fit(X_train, y_train)
   return rfe.support_

MI

Взаимная информация используется для измерения зависимости между двумя переменными. Чтобы описать МИ, мы начнем с определения энтропии Шеннона:

Это уравнение представляет неопределенность выхода Y. Предположим, мы наблюдаем переменную X; тогда условная энтропия определяется как:

И это уравнение подразумевает, что, наблюдая за переменной X, уменьшается неопределенность выхода Y. Уменьшение неопределенности выражается как:

Этот метод можно использовать как в контролируемых, так и в неконтролируемых задачах выбора функций. Мы можем применять его как в регрессии, так и в классификации, поскольку нас интересует только связь между любыми двумя переменными или между каждой переменной и переменной ответа. В нашем случае мы измерили показатель MI между каждой функцией и соответствующей ей меткой и создали список оценок. Теперь, чтобы отфильтровать менее значимые функции, у нас есть несколько вариантов. Давайте посмотрим на три из них:

  1. K-лучшие функции: выберите k лучших функций с наивысшими показателями MI.
  2. 2.Установка порогового значения: возьмите все функции, превышающие заданный порог.
  3. .3.Кумулятивная «энергия»: рассчитайте новую оценку для каждой функции:

Другими словами, соотношение между оценкой MI для i-го признака и суммой всех оценок MI, отсортируйте их сверху вниз, а затем вычислите совокупную сумму по нему. Теперь мы можем установить «энергетический» порог (например, 80%) и взять набор функций, которые объединяют порог.

from sklearn.feature_selection import mutual_info_classif
def mi_fs_classification(X, y, discrete_features):
    mi = pd.DataFrame(mutual_info_classif(X, y, discrete_features=discrete_features, random_state=42, n_neighbors=3, copy=True))
   return mi

Результаты

В следующей таблице сравниваются различные методы, описанные выше. Мы взяли три разных набора табличных данных из нашего домена и проверили точность и время выполнения методов. Для обучения мы использовали древовидную модель - случайный лес. Для каждого набора данных мы создали пять наборов тестов, которые позволили нам более точно сравнить точность методов выбора признаков. Мы также сравнили результаты выполнения t-теста (представленного в виде кортежа t-значения, p-значения) между точностью при использовании всех функций и точностью при использовании только выбранных функций в соответствии с используемым методом. следующее:

  • Dataset1 - мультиклассовая классификация. Обучающий набор из 100 тыс. Строк с 4391 элементами.
  • Dataset2 - мультиклассовая классификация. Обучайте набор из 10 тыс. Строк с 400 функциями.
  • Dataset3 - двоичная классификация. Набор из 398 тыс. Строк с 44 элементами.

Код для расчета t-критерия с использованием пакета scipy:

from scipy.stats import ttest_ind
ttest_ind(accuracies_all_feats, accuracies_selected_feats)

Это выводит значение t и соответствующее значение p.

Если вы не знакомы с концепцией проверки гипотез, вот описание использования нашего t-критерия:

  1. 1. Нулевая гипотеза (H0) всегда является консервативным предположением. В нашем случае мы будем предполагать, что точность полной модели равна точности частичной модели.
  2. Альтернативная гипотеза (H1) - это предположение, которое мы хотим проверить. В нашем случае мы хотим проверить, не равна ли точность полной модели точности частичной модели. Это называется тестом с двумя хвостами, потому что мы тестируем оба направления (т.е. x ›y или x‹ y).

Если нам удастся отклонить H0, мы можем заключить H1. Но что, если мы не откажемся от H0? В этом случае мы можем сделать вывод, что точность остается той же, но с меньшим количеством функций.

Основные моменты из таблицы:

1. Метод Boruta имеет тенденцию фильтровать многие функции. Преимущество состоит в том, что количество функций, которые нужно оставить, не нужно определять, но иногда удаляется слишком много функций (набор данных2)

2. Метод Chi2 работает очень быстро, и мы видим, что он устойчив во всех наборах данных. Единственным недостатком является то, что нам нужно определить, сколько функций оставить (возможно, возможен поиск по сетке).

3. Метод важности перестановки довольно надежен (и не требует определения количества функций). Обратной стороной является то, что он работает долго.

4. Метод RFE не очень применим, поскольку мы не могли запустить его на наборе данных1, пока не остановили его.

Резюме

В этой статье мы кратко описали некоторые полезные методы выбора функций. Мы также провели сравнение этих методов выбора функций на реальных наборах данных. Мы показали, что в целом методы полезны для уменьшения размерности, хотя обычно они не улучшают точность модели (а в некоторых случаях точность сильно упала).

В Части 2 мы покажем более сложный метод выбора функций, объединяющий результаты различных методов, описанных выше. Пожалуйста, присоединяйся к нам!