Выбор функций на основе ИИ в Python!

Подробное изучение методов машинного обучения для выбора функций в Python — часть 2

Вторая часть серии статей о выборе функций на основе ML, в которой мы обсуждаем популярные встроенные методы и методы-оболочки, такие как регрессия Лассо, бета-коэффициенты, рекурсивный выбор функций и т. д.

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

  1. В 2020 году ежедневно создавалось 2,5 квинтиллиона байтов данных.
  2. В 2020 году средний человек генерировал не менее 1,7 МБ данных в секунду.
  3. К 2025 году объем облачного хранилища данных составит более 200 зеттабайт.

Кажется немного пугающим, верно? Один из выводов, который я смог сделать из этого быстрого роста объема данных, заключался в том, что мы больше не можем использовать подход «кухонной раковины» к моделированию. Этот подход просто означает, что мы бросаем в модель «все, кроме кухонной раковины» в надежде найти какую-то закономерность. При таком подходе наши модели просто не смогут разобраться в больших наборах данных. Именно здесь крайне важно использовать методы выбора признаков, чтобы сначала избавиться от шума в данных, а затем приступить к разработке модели.

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

A) Бета-коэффициенты
B) Лассо-регрессия
C) Рекурсивный выбор признаков
D) Последовательный выбор признаков

Подробности о наборе данных и весь код (включая подготовку данных) можно найти в этом репозитории Github. Итак, без лишних слов, начнем!

A) Коэффициенты бета

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

Y = b0 + b1*X1 + b2*X2 + b3*X3 + …. bn*Xn + u

где Y — целевая переменная, X1…Xn — признаки, b1…bn — коэффициенты, а u — ошибка. Коэффициенты говорят нам, что если характеристики увеличиваются на 1 единицу, то каково будет предельное (при сохранении всех остальных характеристик фиксированным) влияние на целевую переменную. Чтобы глубже погрузиться в регрессионную модель (например, предположения, диагностические проверки и т. д.), я бы предложил выполнить следующее:

  1. Повторный курс регрессионного анализа
  2. Предположения линейной регрессии
  3. Введение в многомерный регрессионный анализ
  4. Основы эконометрики (главы 2–13) (глубоко охватывает все темы, связанные с регрессией)

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

  1. Вычислить среднее (среднее) признака
  2. Рассчитать стандартное отклонение функции
  3. Для каждого наблюдения вычтите среднее значение, а затем разделите на стандартное отклонение

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

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

ln(pi/(1-pi)) = b0 + b1*X1 + b2*X2 + b3*X3 + …. bn*Xn + u

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

Например, давайте предположим, что наша цель состоит в том, собирается ли правительство объявить дефолт, а характеристиками являются дефицит бюджета в миллионах рупий и ставка репо центрального банка в %. Коэффициент бюджетного дефицита говорит нам, если дефицит увеличится на 1 миллион рупий, каково будет предельное влияние на логарифм вероятности дефолта правительства, т.е. log (вероятность дефолта/вероятность недефолта).

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

  1. Что такое логистическая регрессия?
  2. Оценка максимального правдоподобия логистической регрессии
  3. Подробный обзор
  4. Основы эконометрики (Глава 15)
  5. Бета-коэффициенты для Логистики

Функция Python для расчета бета-коэффициентов для логистической регрессии:

Для расчета бета-коэффициентов с использованием логистической регрессии мы сначала используем функцию StandardScaler для стандартизации набора данных, а затем используем функцию LogisticRegression из пакета scikit-learn для подбора логистической регрессии без штрафного члена и перехвата. Функция beta_coeffвычисляет бета-коэффициенты для каждой функции, а также выбирает первые n (n, предоставленные пользователем в качестве параметра beta_threshold ) функций на основе абсолютного значения бета-коэффициента. Затем он сопоставляет другую регрессию лассо с выбранными функциями, чтобы позволить разработчикам увидеть, как регрессия ведет себя с выбранными функциями (такими как знак и значимость функций).

#3. Select  the top n features based on absolute value of beta coefficient of features
# Beta Coefficients
beta_threshold = 10
################################ Functions #############################################################
def beta_coeff(data, train_target,beta_threshold):
    
    #Inputs
    # data - Input feature data 
    # train_target - Target variable training data
    # beta_threshold - select n features with highest absolute beta coeficient value
    
    # Standardise dataset
    scaler = StandardScaler()
    data_v2 = pd.DataFrame(scaler.fit_transform(data))
    data_v2.columns = data.columns
# Fit Logistic on Standardised dataset
    # Manual Change in Parameters - Logistic Regression
    # Link to function parameters - https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html       
    log = LogisticRegression(fit_intercept = False, penalty = 'none')
    log.fit(data_v2, train_target)
    coef_table = pd.DataFrame(list(data_v2.columns)).copy()
    coef_table.insert(len(coef_table.columns), "Coefs",    log.coef_.transpose())
    coef_table = coef_table.iloc[coef_table.Coefs.abs().argsort()]
    sr_data2 = coef_table.tail(beta_threshold)
    beta_top_features = sr_data2.iloc[:,0].tolist()
    print(beta_top_features)
    
    beta_top_features_df = pd.DataFrame(beta_top_features,columns = ['Feature'])
    beta_top_features_df['Method'] = 'Beta_coefficients'
    log_v2 = sm.Logit(train_target,\
                     sm.add_constant(data[beta_top_features])).fit()
    print('Logistic Regression with selected features')
    print(log_v2.summary())
    
    return log,log_v2,beta_top_features_df
################################ Calculate Beta Coeff ################################################
standardised_logistic,logistic_beta_features,beta_top_features_df = beta_coeff(train_features_v2,train_target,beta_threshold)
beta_top_features_df.head(n=20)

Код для расчета бета-коэффициентов для линейной регрессии можно найти здесь.

Б) Регрессия Лассо

Лассо-регрессия — один из немногих встроенных методов, доступных для выбора признаков. Это естественное расширение линейной/логистической регрессии, где для выбора признаков используется штрафной термин. Функция стоимости (функция, которую необходимо минимизировать для получения оптимальных значений коэффициентов) лассо-регрессии может быть представлена ​​как:

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

Установка параметра настройки
При использовании регуляризации L1 главное учитывать значение параметра настройки λ, так как он определяет силу штрафа. Как видно из уравнения, установка его на 0 эквивалентна линейной регрессии. Один из способов настроить параметр настройки — попробовать диапазон значений, построить регрессию для каждого и выбрать значение с наименьшим показателем AIC. Можно начать с тестирования значений от 0,01 до 1,0 с шагом сетки 0,01.

Для получения более подробной информации о регрессии лассо можно просмотреть следующие слайды лекции.

Функция Python для добавления регуляризации L1 в логистическую регрессию (лассо с логистической регрессией):

Функция lassoсоответствует логистической регрессии со штрафным членом l1 со значением параметра настройки, предоставленным пользователем в качестве параметра lasso_param. Подобно предыдущей функции, затем она соответствует другой регрессии лассо с выбранными функциями.

#4. Select the features identified by Lasso regression
# Lasso
lasso_param = .01
################################ Functions #############################################################
def lasso(data, train_target,lasso_param):
    
    #Inputs
    # data - Input feature data 
    # train_target - Target variable training data
    # lasso_param - Lasso l1 penalty term
    
    #Fit Logistic
    # Manual Change in Parameters - Logistic Regression
    # Link to function parameters - https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html       
    log = LogisticRegression(penalty ='l1', solver = 'liblinear',\
                             C = lasso_param)
    log.fit(data, train_target)
    
    #Select Features
    lasso_df = pd.DataFrame(columns = ['Feature', 'Lasso_Coef'])
    lasso_df['Feature'] = data.columns
    lasso_df['Lasso_Coef'] = log.coef_.squeeze().tolist()
    lasso_df_v2 = lasso_df[lasso_df['Lasso_Coef'] !=0]
    lasso_top_features = lasso_df_v2['Feature'].tolist()
    
    lasso_top_features_df = pd.DataFrame(lasso_top_features,\
                                         columns = ['Feature'])
    lasso_top_features_df['Method'] = 'Lasso'
# Logistic Regression with selected features
    log_v2 = sm.Logit(train_target,\
                   sm.add_constant(data[lasso_top_features])).fit()    
    print('Logistic Regression with selected features')
    print(log_v2.summary())
    
    return log_v2,lasso_top_features_df
################################ Calculate Lasso ################################################
logistic_lasso_features,lasso_top_features_df = lasso(train_features_v2,train_target,lasso_param)
lasso_top_features_df.head(n=20)

Эту же функцию можно легко использовать для линейной регрессии, заменив функцию LogicticRegression на LinearRegression и Logit на OLS.

C) Рекурсивное устранение признаков (RFE)

Это один из двух популярных методов выбора функций, предоставляемых пакетом Scikit-learnpython для выбора функций. Хотя RFE технически является методом-оболочкой, внутри он основан на процессе, используемом методами на основе фильтров. Посмотрим, как.

Как работает RFE?

  1. Сначала RFE обучает определяемую пользователем модель всему набору функций. Определяемая пользователем модель может быть любой оценкой обучения с учителем с методом fit, который предоставляет информацию о важности функции.
  2. Затем он вычисляет важность каждой функции из обученной модели. Важность можно получить либо с помощью любого атрибута модели (например, coef_, feature_importances_), либо с помощью определяемой пользователем метрики, которая может быть рассчитана для каждой функции.
  3. Затем он отбрасывает наименее важную функцию, а затем повторяет шаги 1 и 2 с уменьшенным количеством функций.
  4. Шаг 3 повторяется до тех пор, пока не останется заданное пользователем количество функций.

RFE считается методом-оболочкой, потому что он «обернут» вокруг внешней оценки. Но он также основан на принципах метода на основе фильтров благодаря ранжированию признаков на основе меры важности.

Как автоматически выбрать количество функций с помощью RFE?
Выбрать количество функций непросто, и, к счастью,Scikit-learnpackage имеет новую функцию под названиемRFECV (рекурсивное исключение функций с перекрестной проверкой), которая освобождает нас от этой нагрузки. Перекрестная проверка — это стратегия тестирования производительности модели, и самая популярная версия — перекрестная проверка в k-кратном размере. Сначала мы разделяем данные на k случайных частей, затем обучаем модель на всех частях, кроме одной (k-1), и, наконец, оцениваем модель на той части, которая не использовалась для обучения. Это повторяется k раз, каждый раз для оценки резервируется другая часть.

Если у нас есть n функций, RFECV по существу выполняет RFE вместе с перекрестной проверкой n-1 раз (отбрасывая наименее важную функцию на каждой итерации). Затем он выбирает количество функций, для которых оценка перекрестной проверки максимальна.

Функция Python для реализацииRFECV:

Здесь мы используем функцию RFECV из scikit-learn, которая настроена так же, как класс RFE в отношении выбора алгоритма. Функция rfecv_feature_selection позволяет пользователям выбирать из 5 популярных древовидных алгоритмов: XG Boost, Random Forest, Catboost, Light GBM и Decision Tree. Я буду писать новую серию блогов по каждому из методов в ближайшее время. Функция устанавливает любой оценщик из списка, заданного пользователем с помощью параметра rfe_estimator. Если ничего не указано, дерево решений подходит по умолчанию. Они также могут изменить ряд других функций, таких как метрики оценки, чтобы выбрать оптимальное количество функций (см. раздел входных данных функции в коде ниже).

#5. Select features based on Recursive Feature Selection method
# RFECV
rfe_estimator = "XGBoost"
rfe_step = 2
rfe_cv = 5
rfe_scoring = 'f1'
################################ Functions #############################################################
def rfecv_feature_selection(data, train_target,rfe_estimator,rfe_step,rfe_cv,rfe_scoring):
    
    #Inputs
    # data - Input feature data 
    # train_target - Target variable training data
    # rfe_estimator - base model (default: Decision Tree)
    # rfe_step -  number of features to remove at each iteration
    # rfe_cv - cross-validation splitting strategy
    # rfe_scoring - CV performance scoring metric
## Initialize RFE
    if rfe_estimator == "XGBoost":
        # Manual Change in Parameters - XGBoost
        # Link to function parameters - https://xgboost.readthedocs.io/en/stable/parameter.html       
        estimator_rfe = XGBClassifier(n_jobs = -1, random_state=101)
    elif rfe_estimator == "RandomForest":
        # Manual Change in Parameters - RandomForest
        # Link to function parameters - https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html
        estimator_rfe = RandomForestClassifier(n_jobs = -1, random_state=101)
    elif rfe_estimator == "CatBoost":
        # Manual Change in Parameters - CatBoost
        # Link to function parameters - https://catboost.ai/en/docs/concepts/python-reference_catboostclassifier
        estimator_rfe = CatBoostClassifier(iterations=50,verbose=0,random_state=101)
    elif rfe_estimator == "LightGBM":
        # Manual Change in Parameters - LightGBM
        # Link to function parameters - https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMClassifier.html
        estimator_rfe = lgb.LGBMClassifier(n_jobs = -1, random_state=101)
    else:
        # Manual Change in Parameters - DecisionTree
        # Link to function parameters - https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html
        estimator_rfe = DecisionTreeClassifier(random_state=101)
# Fit RFECV
    # Manual Change in Parameters - RFECV
    # Link to function parameters - https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.RFECV.html
    # Scoring metrics - https://scikit-learn.org/stable/modules/model_evaluation.html
    rfecv = RFECV(estimator = estimator_rfe, step = rfe_step, cv = rfe_cv, scoring = rfe_scoring)
    rfecv.fit(data, train_target)
# Select feature based on RFE
    print('Optimal number of features: {}'.format(rfecv.n_features_))
    rfe_df = pd.DataFrame(columns = ['Feature', 'rfe_filter'])
    rfe_df['Feature'] = data.columns
    rfe_df['rfe_filter'] = rfecv.support_.tolist()
    rfe_df_v2 = rfe_df[rfe_df['rfe_filter']==True]
    rfe_top_features = rfe_df_v2['Feature'].tolist()
    print(rfe_top_features)
    
    rfe_top_features_df = pd.DataFrame(rfe_top_features,columns = ['Feature'])
    rfe_top_features_df['Method'] = 'RFECV'
# Plot CV results
    %matplotlib inline
    plt.figure(figsize=(16, 9))
    plt.title('Recursive Feature Elimination with Cross-Validation', fontsize=18, fontweight='bold', pad=20)
    plt.xlabel('Number of features selected', fontsize=14, labelpad=20)
    plt.ylabel('f1 acore', fontsize=14, labelpad=20)
    plt.plot(range(1, len(rfecv.grid_scores_) + 1), rfecv.grid_scores_, color='#303F9F', linewidth=3)
    plt.show()
    
    return rfe_top_features_df,rfecv
################################ Calculate RFECV #############################################################
rfe_top_features_df,rfecv = rfecv_feature_selection(train_features_v2,train_target,rfe_estimator,rfe_step,rfe_cv,rfe_scoring)
rfe_top_features_df.head(n=20)

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

D) Последовательный выбор функций (SFS)

Последовательный выбор функций (SFS) — это еще один метод выбора функций типа оболочки, предоставляемый Scikit-learnpackage. Разница между RFE и SFS заключается в том, что базовая модель не требует расчета показателя важности функции. Он также может выполнять как прямой (начиная с 1 функции и последующее добавление функций в модель), так и обратный (начиная со всех функций и последовательно удаляя функции из модели) выбор функций, в то время как RFE может выполнять только обратный выбор.

Кроме того, SFS обычно медленнее, чем RFECV. Например, при обратном выборе итерация перехода от n объектов к n-1 объектам с использованием k-кратной перекрестной проверки требует подбора n*k моделей, в то время как для RFECV потребуется только k подборов.

Как работает SFS?

Форвард-SFS:

  1. SFS изначально запускается без функций и находит функцию, которая максимизирует оценку перекрестной проверки.
  2. Как только первая функция выбрана, SFS повторяет процесс, добавляя новую функцию к существующей выбранной функции.
  3. Процедура продолжается до тех пор, пока не будет достигнуто желаемое количество выбранных признаков, определяемое параметром n_features_to_select. Если пользователь не указывает точное количество функций для выбора или порог повышения производительности, алгоритм автоматически выбирает половину существующего списка функций.

Назад-SFS:

Он имеет тот же процесс, но работает в противоположном направлении: он начинает со всех объектов, а затем начинает удалять объекты из набора.

Как выбрать направление (назад или вперед)?

Параметр direction определяет, используется ли SFS вперед или назад. Также важно отметить, что прямой и обратный выбор обычно не дают одинаковых результатов. Мы должны выбрать направление, исходя из того, какой % функций мы хотим сохранить в модели. Если мы хотим сохранить большинство функций, мы должны выбрать «Назад» и наоборот.

Функция Python для реализацииSequentialFeatureSelector:

Здесь мы используем функцию SequentialFeatureSelector из scikit-learn. Функция sfs_feature_selection соответствует логистической регрессии. Здесь я использовал логистическую регрессию, поскольку мы можем выбирать признаки на основе их влияния на r-квадрат, и мы уже подгоняем древовидные модели в предыдущем методе. Пользователь также может изменить ряд функций, таких как количество сохраняемых функций (см. раздел входных данных функции в приведенном ниже коде).

#6. Select features based on Sequential Feature Selector
# Sequential Feature Selector
sfs_feature = 10
sfs_direction = 'backward'
sfs_cv = 2
sfs_scoring = 'r2'
################################ Functions #############################################################
def sfs_feature_selection(data, train_target,sfs_feature,sfs_direction,sfs_cv,sfs_scoring):
    
    #Inputs
    # data - Input feature data 
    # train_target - Target variable training data
    # sfs_feature - no. of features to select
    # sfs_direction -  forward and backward selection
    # sfs_cv - cross-validation splitting strategy
    # sfs_scoring - CV performance scoring metric
    logistic = LogisticRegression(penalty = None)
    sfs=SequentialFeatureSelector(estimator = logistic,
                                  n_features_to_select=sfs_feature,   
                                  direction = sfs_direction,
                                  cv = sfs_cv,
                                  scoring = sfs_scoring)
    sfs.fit(train_features_v2, train_target)
    sfs.get_support()
    sfs_df = pd.DataFrame(columns = ['Feature', 'SFS_filter'])
    sfs_df['Feature'] = train_features_v2.columns
    sfs_df['SFS_filter'] = sfs.get_support().tolist()
    sfs_df_v2 = sfs_df[sfs_df['SFS_filter']==True]
    sfs_top_features = sfs_df_v2['Feature'].tolist()
    print(sfs_top_features)

    x_temp = sm.add_constant(train_features_v2[sfs_top_features])
    log_v2=sm.Logit(train_target,x_temp).fit()
    print(log_v2.summary())
    
    sfs_top_features_df=pd.DataFrame(sfs_top_features\
                                     ,columns = ['Feature'])
    sfs_top_features_df['Method']='Sequential_feature_selector'
    return sfs_top_features_df,sfs
################################ Calculate RFECV #############################################################
sfs_top_features_df,sfs = sfs_feature_selection(train_features_v2,train_target,sfs_feature,sfs_direction,sfs_cv,sfs_scoring)
sfs_top_features_df.head(n=20)

Как упоминалось ранее, пользователь может использовать здесь любой другой метод, внеся изменения в этот участок кода:

sfs=SequentialFeatureSelector(estimator = #add model here#
                                  ,n_features_to_select=sfs_feature,   
                                  direction = sfs_direction,
                                  cv = sfs_cv,
                                  scoring = sfs_scoring)

Заключительные слова

Вот мы и подошли к концу второй части серии блогов, состоящей из трех частей. Теперь читатели должны быть знакомы с 6 различными методами выбора признаков. Они также должны знать о лучших практиках, связанных с ними, а также о их реализации на Python. Я хотел бы подчеркнуть здесь, что отбор признаков — это сочетание искусства и науки. Хотя мы подробно обсудили науку, стоящую за этим, с опытом становится лучше.

Обязательно прочитайте последнюю часть этой серии, где мы обсуждаем самые передовые техники, имеющиеся в нашем распоряжении (Borutapy, Borutashap), и обсуждаем, как комбинировать все эти методы. Наконец, весь код для анализа можно найти здесь.

У вас есть вопросы или предложения по поводу этого блога? Пожалуйста, не стесняйтесь оставить записку.

Справочный материал

  1. Повторный курс регрессионного анализа
  2. Предположения линейной регрессии
  3. Введение в многомерный регрессионный анализ
  4. Основы эконометрики (главы 2–13) (глубоко охватывает все темы, связанные с регрессией)
  5. Что такое логистическая регрессия?
  6. Оценка максимального правдоподобия логистической регрессии
  7. Подробный обзор
  8. Основы эконометрики (Глава 15)
  9. Бета-коэффициенты для Логистики

Подключаемся!

Если вы, как и я, увлечены искусственным интеллектом, наукой о данных или экономикой, не стесняйтесь добавлять/подписываться на меня в LinkedIn, Github и Medium.