Важность функции с фиктивными переменными

17

Я пытаюсь понять, как я могу получить важность функции категориальной переменной, которая была разбита на фиктивные переменные. Я использую Scikit-Learn, который не обрабатывает категориальные переменные для вас, как R или H2O.

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

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

Со страницы 368 «Элементы статистического обучения»:

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

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

Я написал следующий код Python (в jupyter) в качестве расследования:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import animation, rc
from sklearn.datasets import load_diabetes
from sklearn.ensemble import RandomForestClassifier
import re

#%matplotlib inline
from IPython.display import HTML
from IPython.display import set_matplotlib_formats

plt.rcParams['figure.autolayout'] = False
plt.rcParams['figure.figsize'] = 10, 6
plt.rcParams['axes.labelsize'] = 18
plt.rcParams['axes.titlesize'] = 20
plt.rcParams['font.size'] = 14
plt.rcParams['lines.linewidth'] = 2.0
plt.rcParams['lines.markersize'] = 8
plt.rcParams['legend.fontsize'] = 14

# Get some data, I could not easily find a free data set with actual categorical variables, so I just created some from continuous variables
data = load_diabetes()
df = pd.DataFrame(data.data, columns=[data.feature_names])
df = df.assign(target=pd.Series(data.target))

# Functions to plot the variable importances
def autolabel(rects, ax):
    """
    Attach a text label above each bar displaying its height
    """
    for rect in rects:
        height = rect.get_height()
        ax.text(rect.get_x() + rect.get_width()/2.,
                1.05*height,
                f'{round(height,3)}',
                ha='center',
                va='bottom')

def plot_feature_importance(X,y,dummy_prefixes=None, ax=None, feats_to_highlight=None):

    # Find the feature importances by fitting a random forest
    forest = RandomForestClassifier(n_estimators=100)
    forest.fit(X,y)
    importances_dummy = forest.feature_importances_

    # If there are specified dummy variables, combing them into a single categorical 
    # variable by summing the importances. This code assumes the dummy variables were
    # created using pandas get_dummies() method names the dummy variables as
    # featurename_categoryvalue
    if dummy_prefixes is None:
        importances_categorical = importances_dummy
        labels = X.columns
    else:
        dummy_idx = np.repeat(False,len(X.columns))
        importances_categorical = []
        labels = []

        for feat in dummy_prefixes:
            feat_idx = np.array([re.match(f'^{feat}_', col) is not None for col in X.columns])
            importances_categorical = np.append(importances_categorical,
                                                sum(importances_dummy[feat_idx]))
            labels = np.append(labels,feat)
            dummy_idx = dummy_idx | feat_idx
        importances_categorical = np.concatenate((importances_dummy[~dummy_idx],
                                                  importances_categorical))
        labels = np.concatenate((X.columns[~dummy_idx], labels))

    importances_categorical /= max(importances_categorical)
    indices = np.argsort(importances_categorical)[::-1]

    # Plotting

    if ax is None:
        fig, ax = plt.subplots()

    plt.title("Feature importances")
    rects = ax.bar(range(len(importances_categorical)),
                   importances_categorical[indices],
                   tick_label=labels[indices],
                   align="center")
    autolabel(rects, ax)

    if feats_to_highlight is not None:
        highlight = [feat in feats_to_highlight for feat in labels[indices]]
        rects2 = ax.bar(range(len(importances_categorical)),
                       importances_categorical[indices]*highlight,
                       tick_label=labels[indices],
                       color='r',
                       align="center")
        rects = [rects,rects2]
    plt.xlim([-0.6, len(importances_categorical)-0.4])
    ax.set_ylim((0, 1.125))
    return rects

# Create importance plots leaving everything as categorical variables. I'm highlighting bmi and age as I will convert those into categorical variables later
X = df.drop('target',axis=1)
y = df['target'] > 140.5

plot_feature_importance(X,y, feats_to_highlight=['bmi', 'age'])
plt.title('Feature importance with bmi and age left as continuous variables')

#Create an animation of what happens to variable importance when I split bmi and age into n (n equals 2 - 25) different classes
# %%capture

fig, ax = plt.subplots()

def animate(i):
    ax.clear()

    # Split one of the continuous variables up into a categorical variable with i balanced classes
    X_test = X.copy()
    n_categories = i+2
    X_test['bmi'] = pd.cut(X_test['bmi'],
                           np.percentile(X['bmi'], np.linspace(0,100,n_categories+1)),
                           labels=[chr(num+65) for num in range(n_categories)])
    X_test['age'] = pd.cut(X_test['age'],
                           np.percentile(X['age'], np.linspace(0,100,n_categories+1)),
                           labels=[chr(num+65) for num in range(n_categories)])
    X_test = pd.get_dummies(X_test, drop_first=True)

    # Plot the feature importances
    rects = plot_feature_importance(X_test,y,dummy_prefixes=['bmi', 'age'],ax=ax, feats_to_highlight=['bmi', 'age'])
    plt.title(f'Feature importances for {n_categories} bmi and age categories')
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.spines['bottom'].set_visible(False)
    ax.spines['left'].set_visible(False)

    return [rects,]

anim = animation.FuncAnimation(fig, animate, frames=24, interval=1000)

HTML(anim.to_html5_video())

Вот некоторые из результатов:

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

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

Мы можем заметить, что значение переменной в основном зависит от количества категорий, что заставляет меня усомниться в полезности этих диаграмм в целом. Особенно важно age достичь гораздо более высоких значений, чем его непрерывный аналог.

И, наконец, пример, если я оставлю их как фиктивные переменные (только bmi):

# Split one of the continuous variables up into a categorical variable with i balanced classes
X_test = X.copy()
n_categories = 5
X_test['bmi'] = pd.cut(X_test['bmi'],
                       np.percentile(X['bmi'], np.linspace(0,100,n_categories+1)),
                       labels=[chr(num+65) for num in range(n_categories)])
X_test = pd.get_dummies(X_test, drop_first=True)

# Plot the feature importances
rects = plot_feature_importance(X_test,y, feats_to_highlight=['bmi_B','bmi_C','bmi_D', 'bmi_E'])
plt.title(f"Feature importances for {n_categories} bmi categories")

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

Дэн
источник

Ответы:

8

При работе над «важностью функций», как правило, полезно помнить, что в большинстве случаев подход к регуляризации часто является хорошей альтернативой. Он автоматически «выберет наиболее важные функции» для рассматриваемой проблемы. Теперь, если мы не хотим следовать понятию регуляризации (обычно в контексте регрессии), классификаторы случайных лесов и понятие перестановочных тестов, естественно, дают решение для характеристики важности группы переменных. Это на самом деле было задано ранее здесь: « Относительная важность набора предикторов в классификации случайных лесов в R » несколько лет назад. Более строгие подходы, такие как Gregorutti и др.: « Группировка переменной важности со случайными лесами и применение для многомерного функционального анализа данных". Chakraborty & Pal's Выбор полезных групп функций в Connectionist Framework рассматривает эту задачу в контексте многоуровневого персептрона. Возвращаясь к статье Грегорутти и др., Их методология напрямую применима к любому типу алгоритма классификации / регрессии. Короче говоря, мы используем случайно переставленную версию в каждой выборке из пакета, которая используется во время обучения.

С учетом вышесказанного, в то время как тесты перестановок в конечном счете являются эвристическими, в прошлом точно решалась проблема наказания фиктивных переменных в контексте регуляризованной регрессии. Ответ на этот вопрос - Group-LASSO , Group-LARS и Group-Garotte . Основными документами в этой работе являются "Юань и Линь": " Выбор модели и оценка в регрессии с сгруппированными переменными " (2006) и "Мейер и др.": " Групповое лассо для логистической регрессии " (2008). Эта методология позволяет нам работать в ситуации, когда: « каждый фактор может иметь несколько уровней и может быть выражен через группу фиктивных переменных » (Y & L 2006). Эффект такой, что "L1КJJзнак равно{1,...,J}Jpyglmnetсгруппированная лассо регуляризация .]

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

Напоследок констатирую очевидное: не складывайте непрерывные данные . Это плохая практика, есть отличная нить по этому вопросу здесьздесь ). То, что мы наблюдаем ложные результаты после дискретизации непрерывной переменной, вроде бы age, неудивительно. Фрэнк Харрелл также много писал о проблемах, вызванных категоризацией непрерывных переменных .

usεr11852 говорит восстановить Monic
источник
Вы связываете Относительная важность набора предикторов в классификации случайных лесов в R и дает прямой ответ на вопрос. Я был бы рад принять, если вы перенесете ссылку на эту ссылку в начало, поскольку я не думаю, что остальное так же важно, и ссылка может легко потеряться в ответе.
Дан
Нет проблем. Я сделал некоторые соответствующие изменения. Не отклоняйте концепцию регуляризованной регрессии, поскольку я упоминаю в тексте, подходы регуляризации предлагают совершенно обоснованную альтернативу важности / ранжированию функций.
usεr11852 говорит восстановить Monic
Регуляризованная регрессия не является ответом на этот вопрос, она может ответить на другой вопрос, то есть альтернативы важности признаков, но этот вопрос касается объединения всех элементов в единый категориальный элемент в пределах графика важности признаков. Я действительно думаю, что вы должны переместить ссылку, которая фактически отвечает на вопрос, к началу.
Дан
2

Вопрос в том:

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

Краткий ответ:

ямпорTaNсе(ИксL)знак равноя
(я)2знак равноΣTзнак равно1J-1я2я(v(T)знак равно)
язнак равноΣTзнак равно1J-1я2я(v(T)знак равно)

Чем дольше, тем практичнее ответ ..

Вы не можете просто суммировать отдельные значения важности переменных для фиктивных переменных, потому что вы рискуете

маскировка важных переменных другими людьми, с которыми они тесно связаны. (страница 368)

Такие вопросы, как возможная мультиколлинеарность, могут искажать значения и рейтинги переменных.

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

Хотя мультиколлинеарность действительно влияла на эффективность методов относительной важности, многомерная ненормальность не влияла. (УИТТЕЙКЕР, стр. 366)

ecedavis
источник
Я не думаю, что ваша вторая цитата актуальна. Это не сильно коррелированные переменные, это одна и та же переменная, и для хорошей реализации дерева решений не потребуется OHE, но они рассматриваются как одна переменная. Во всяком случае, мультиколлинеарность искусственно вводится ОНЭ.
Дан
Что касается вашей первой точки зрения, мне кажется, что число относительной важности, предложенное Брейманом, является квадратом. Так что я не уверен, что sklearn сначала берет квадратные корни, как вы и предлагали. Кроме того, если они, разве я не должен сначала возводить в квадрат значения, складывать их, а затем возводить в квадрат сумму? Я не уверен, что понял ваше предложение сначала взять квадратный корень.
Дан
@ecedavis Что вы подразумеваете под учебником? Можете ли вы предоставить ссылку или более полное цитирование, пожалуйста.
24
Привет, спасибо за критику и за мое первое выступление в качестве нового участника. В ваших комментариях указываются конкретные детали, которые я рассмотрю в моей редакции, но могу ли я также узнать ваше мнение об общем качестве моего ответа? Это мой первый пост, и я планирую стать постоянным автором. Как минимум, я надеюсь, что мой ответ, как правило, полезен и в хорошем стиле. о чем ты думаешь?
Эчедавис
Стиль вашего ответа хорош, но некоторая информация и содержание не совсем верны. В документе, на который вы ссылаетесь, речь идет о важности предиктора в множественной регрессии, а вопрос о важности в случайном Форесте. Я также считаю, что ваше извлечение цитаты проблематично, поскольку полное предложение звучит так: «Кроме того, из-за сжатия (раздел 10.12.1) маскирование важных переменных другими, с которыми они тесно связаны, представляет собой гораздо меньшую проблему». который имеет совсем другое значение.
смотри 24