Ważność funkcji w przypadku zmiennych zastępczych

18

Próbuję zrozumieć, w jaki sposób mogę uzyskać znaczenie funkcji zmiennej jakościowej, która została podzielona na zmienne fikcyjne. Używam scikit-learn, który nie obsługuje zmiennych kategorialnych tak jak R lub H2O.

Jeśli podzielę zmienną kategorialną na zmienne pozorne, otrzymam osobne importy cech dla każdej klasy w tej zmiennej.

Moje pytanie brzmi: czy sensowne jest zrekompensowanie tych fikcyjnych wartości zmiennych w wartość istotności dla zmiennej jakościowej, po prostu sumując je?

Od strony 368 elementów uczenia statystycznego:

Względne znaczenie kwadratu zmiennej X jest sumą takich poprawek do kwadratu we wszystkich wewnętrznych węzłach, dla których wybrano ją jako zmienną dzielącą

To sprawia, że ​​myślę, że ponieważ wartość ważności jest już tworzona przez zsumowanie metryki w każdym węźle, zmienna jest wybrana, powinienem być w stanie połączyć wartości zmiennych zmiennych w zmiennych zastępczych, aby „odzyskać” znaczenie dla zmiennej jakościowej. Oczywiście nie oczekuję, że będzie to dokładnie poprawne, ale te wartości i tak są naprawdę dokładnymi wartościami, ponieważ są znalezione w wyniku losowego procesu.

Jako dochodzenie napisałem następujący kod python (w 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())

Oto niektóre wyniki:

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

Możemy zauważyć, że zmienne znaczenie zależy głównie od liczby kategorii, co prowadzi mnie do pytania o użyteczność tych wykresów w ogóle. Szczególnie znaczenie age osiągania znacznie wyższych wartości niż ciągły odpowiednik.

I na koniec przykład, jeśli zostawię je jako zmienne obojętne (tylko 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")

wprowadź opis zdjęcia tutaj

Dan
źródło

Odpowiedzi:

8

Podczas pracy nad „istotnością funkcji” ogólnie warto pamiętać, że w większości przypadków podejście do regularyzacji jest często dobrą alternatywą. Automatycznie „wybierze najważniejsze funkcje” dla danego problemu. Otóż, jeśli nie chcemy stosować się do pojęcia regularyzacji (zwykle w kontekście regresji), losowe klasyfikatory lasu i pojęcie testów permutacyjnych w naturalny sposób stanowią rozwiązanie, które uwypukla znaczenie grupy zmiennych. To pytanie zostało już wcześniej zadane: „ Względne znaczenie zestawu predyktorów w losowej klasyfikacji lasów w R ” kilka lat temu. Bardziej rygorystyczne podejścia, takie jak Gregorutti i in.: „ Pogrupowane zmienne znaczenie z losowymi lasami i aplikacją do analizy danych funkcjonalnych na wielu odmianach". Chakraborty i Pal's, wybierając przydatne grupy funkcji w ramach Connectionist Framework, analizują to zadanie w kontekście wielowarstwowego perceptronu. Wracając do artykułu Gregorutti i in., Ich metodologia ma bezpośrednie zastosowanie do każdego rodzaju algorytmu klasyfikacji / regresji Krótko mówiąc, używamy losowo permutowanej wersji w każdej próbce wyjętej z torby, która jest używana podczas treningu.

Biorąc powyższe pod uwagę, podczas gdy testy permutacyjne są ostatecznie heurystyczne, w przeszłości dokładnie rozwiązano karanie zmiennych pozornych w kontekście regresji regularyzowanej. Odpowiedź na to pytanie brzmi Group-LASSO , Group-LARS i Group-Garotte . Prace drugorzędne w tej pracy to Yuan i Lin's: „ Wybór modelu i oszacowanie w regresji ze zmiennymi pogrupowanymi ” (2006) i Meier i wsp.: „ The lasso grupowe dla regresji logistycznej ” (2008). Metodologia ta pozwala nam pracować w sytuacji, w której: „ każdy czynnik może mieć kilka poziomów i może być wyrażony przez grupę zmiennych obojętnych ” (Y&L 2006). Efekt jest taki, że „l1K.jotjot={1,,jot}jotpyglmnetzgrupowane regularyzacje lasso .]

Podsumowując, in nie ma sensu po prostu „sumować” znaczenie zmiennych z poszczególnych zmiennych zastępczych, ponieważ nie wychwytuje powiązania między nimi, a także prowadzi do potencjalnie bezsensownych wyników. To powiedziawszy, zarówno metody karane grupowo, jak i metody o zmiennym znaczeniu permutacji dają spójne i (zwłaszcza w przypadku procedur ważności permutacji) ramy do tego celu.

Na koniec stwierdzam oczywiste: nie zbijaj ciągłych danych . To jest złe praktyki, nie jest doskonały wątek na ten temat tutaj (i tutaj ). Fakt, że obserwujemy fałszywe wyniki po dyskretyzacji zmiennej ciągłej, jak age, nie jest zaskakujący. Frank Harrell napisał także obszerny opis problemów spowodowanych kategoryzacją zmiennych ciągłych .

usεr11852 mówi Reinstate Monic
źródło
Link Względne znaczenie zestawu predyktorów w losowej klasyfikacji lasów w R odpowiada na pytanie bezpośrednio. Z przyjemnością przyjmę, jeśli przeniesiesz odniesienie do tego linku na początek, ponieważ nie sądzę, aby reszta była tak bezpośrednio istotna, a link może łatwo zgubić się w odpowiedzi.
Dan
Nie ma problemu. Wprowadziłem kilka odpowiednich zmian. Nie odrzucaj koncepcji regresji regularyzowanej, jak już wspomniałem w tekście, podejścia regularyzacyjne oferują całkowicie prawidłową alternatywę dla ważności / rankingu cech.
usεr11852 mówi: Przywróć Monic
Regaryzowana regresja nie jest odpowiedzią na to pytanie, może odpowiedzieć na inne pytanie, tj. Alternatywy dla ważności cech, ale to pytanie dotyczy agregacji wszystkich cech w jedną cechę kategorialną w obrębie wykresu ważności cechy. Naprawdę uważam, że powinieneś przenieść link, który faktycznie odpowiada na pytanie do samego początku.
Dan
2

Pytanie brzmi:

czy sensowne jest ponowne połączenie tych ważniejszych zmiennych zmiennych w wartość ważności dla zmiennej jakościowej poprzez ich sumowanie?

Krótka odpowiedź:

jamportzandomi(Xl)=ja
(ja)2)=t=1jot-1ja2)ja(v(t)=)
ja=t=1jot-1ja2)ja(v(t)=)
Podsumowując, najpierw musisz wziąć pierwiastek kwadratowy.

Dłuższa, bardziej praktyczna odpowiedź ..

Nie możesz po prostu zsumować poszczególnych wartości ważności zmiennych dla zmiennych zastępczych, ponieważ ryzykujesz

maskowanie ważnych zmiennych przez inne, z którymi są one wysoce skorelowane. (strona 368)

Problemy takie jak możliwa wielokoliniowość mogą zniekształcać zmienne wartości ważności i rankingi.

To naprawdę bardzo interesujący problem, aby zrozumieć, jak zmienne znaczenie zależy od takich kwestii, jak wielokoliniowość. W artykule Określanie znaczenia predyktora w regresji wielorakiej w różnych warunkach korelacyjnych i dystrybucyjnych omówiono różne metody obliczania istotnej zmienności i porównano wydajność dla danych naruszających typowe założenia statystyczne. Autorzy to stwierdzili

Chociaż wielokoliniowość wpłynęła na wydajność metod względnego znaczenia, nietypowość wielowymiarowa nie. (WHITTAKER p366)

ecedavis
źródło
Nie sądzę, aby twój drugi cytat był istotny. Nie są to zmienne wysoce skorelowane, są to te same zmienne, a dobra implementacja drzewa decyzyjnego nie wymagałaby OHE, ale traktowałaby je jako jedną zmienną. Jeśli już, wielokolaryzacja jest sztucznie wprowadzana przez OHE.
Dan
Jeśli chodzi o twój pierwszy punkt, rani mnie to, podobnie jak względna liczba ważności zaproponowana przez Breimana to wartość kwadratowa. Nie jestem więc przekonany, że sklearn najpierw bierze pierwiastki kwadratowe, jak sugerowałeś. A jeśli tak, to czy nie powinienem najpierw wyrównywać wartości, dodawać je, a następnie wyrównywać sumę? Nie jestem pewien, czy zrozumiałem twoją sugestię, aby najpierw wyjąć pierwiastek kwadratowy.
Dan
@ecedavis Co masz na myśli przez ten podręcznik? Czy możesz podać link lub pełniejsze cytowanie, proszę.
patrz 24
Cześć, dziękuję za krytykę i za moją pierwszą opinię jako nowy członek. Wasze komentarze wskazują konkretne szczegóły, które omówię w mojej wersji, ale czy mogę również wyrazić opinię na temat ogólnej jakości mojej odpowiedzi? To jest mój pierwszy post i planuję zostać stałym współpracownikiem. Mam przynajmniej nadzieję, że moja odpowiedź jest ogólnie pomocna i ma dobry styl. Jakie są Twoje myśli?
ecedavis
Styl twojej odpowiedzi jest dobry, ale niektóre informacje i treści nie wydają się całkowicie poprawne. Artykuł, do którego linkujesz, dotyczy ważności predyktora w regresji wielorakiej, podczas gdy pytanie dotyczy ważności w losowym lesie. Uważam również, że wyodrębnienie cytatu jest problematyczne, ponieważ pełne zdanie brzmi: „Również z powodu skurczu (Rozdział 10.12.1) maskowanie ważnych zmiennych przez inne, z którymi są one silnie skorelowane, jest znacznie mniejszym problemem”. co ma zupełnie inne znaczenie.
patrz 24