Merkmalsbedeutung bei Dummy-Variablen

17

Ich versuche zu verstehen, wie ich die Feature-Wichtigkeit einer kategorialen Variablen ermitteln kann, die in Dummy-Variablen zerlegt wurde. Ich benutze scikit-learn, das kategoriale Variablen für Sie nicht so behandelt, wie es R oder H2O tun.

Wenn ich eine kategoriale Variable in Dummy-Variablen zerlege, erhalte ich separate Feature-Wichtigkeiten pro Klasse in dieser Variablen.

Meine Frage ist, ob es Sinn macht, diese Dummy-Variablen-Wichtigkeiten zu einem Wichtigkeitswert für eine kategoriale Variable zu rekombinieren, indem man sie einfach summiert.

Ab Seite 368 der Elemente des statistischen Lernens:

Die quadratische relative Wichtigkeit der Variablen X ist die Summe solcher quadratischen Verbesserungen über alle internen Knoten, für die sie als Aufteilungsvariable ausgewählt wurde

Da der Wichtigkeitswert bereits durch Summieren einer Metrik an jedem Knoten erstellt wurde, sollte es mir möglich sein, die Wichtigkeitswerte der Dummy-Variablen zu kombinieren, um die Wichtigkeit für die kategoriale Variable "wiederherzustellen". Natürlich erwarte ich nicht, dass es genau richtig ist, aber diese Werte sind sowieso wirklich genaue Werte, da sie durch einen zufälligen Prozess gefunden werden.

Ich habe den folgenden Python-Code (in Jupyter) als Untersuchung geschrieben:

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())

Hier sind einige der Ergebnisse:

Bildbeschreibung hier eingeben

Bildbeschreibung hier eingeben

Wir können beobachten, dass die variable Wichtigkeit hauptsächlich von der Anzahl der Kategorien abhängt, was mich dazu bringt, die Nützlichkeit dieser Diagramme im Allgemeinen in Frage zu stellen. Besonders die Wichtigkeit age , viel höhere Werte als das kontinuierliche Gegenstück zu erreichen.

Und zum Schluss ein Beispiel, wenn ich sie als Dummy-Variablen belasse (nur 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")

Bildbeschreibung hier eingeben

Dan
quelle

Antworten:

8

Bei der Arbeit an "Feature-Wichtigkeit" ist es im Allgemeinen hilfreich, sich daran zu erinnern, dass in den meisten Fällen ein Regularisierungsansatz oft eine gute Alternative ist. Es werden automatisch "die wichtigsten Funktionen" für das jeweilige Problem ausgewählt. Wenn wir dem Begriff der Regularisierung (normalerweise im Rahmen der Regression) nicht folgen möchten, bieten zufällige Waldklassifikatoren und der Begriff der Permutationstests natürlich eine Lösung für die Bedeutung von Variablengruppen. Dies wurde eigentlich schon mal hier gefragt: " Relative Bedeutung einer Reihe von Prädiktoren in einer zufälligen Waldklassifikation in R ". Strengere Ansätze wie Gregorutti et al .: " Gruppierte Variablenbedeutung mit zufälligen Wäldern und Anwendung zur multivariaten Analyse funktionaler Daten". Chakraborty & Pals Auswahl nützlicher Merkmalsgruppen in einem Connectionist-Framework untersucht diese Aufgabe im Kontext eines mehrschichtigen Perceptrons. Zurückgehend auf die Veröffentlichung von Gregorutti et al. Ist ihre Methodik direkt auf jede Art von Klassifizierungs- / Regressionsalgorithmus anwendbar Kurz gesagt, wir verwenden eine zufällig verteilte Version in jeder Out-of-Bags-Probe, die während des Trainings verwendet wird.

Nachdem oben ausgeführt wurde, dass Permutationstests letztendlich eine Heuristik sind, wurde in der Vergangenheit die Bestrafung von Dummy-Variablen im Kontext einer regulierten Regression genau gelöst. Die Antwort auf diese Frage lautet Group-LASSO , Group-LARS und Group-Garotte . Die wichtigsten Veröffentlichungen in dieser Arbeit sind Yuan und Lins: " Modellauswahl und -schätzung in Regression mit gruppierten Variablen " (2006) und Meier et al .: " Das Gruppenlasso für logistische Regression " (2008). Diese Methodik ermöglicht es uns, in Situationen zu arbeiten, in denen: " jeder Faktor mehrere Ebenen haben kann und durch eine Gruppe von Dummy-Variablen ausgedrückt werden kann " (Y & L 2006). Die Wirkung ist so, dass "l1Kjj={1,,J}J , wenn Sie diese weiter verfolgen wollen [Weil wir Python ausdrücklich erwähnt. ich habe nicht den Python verwendet pyglmnetPaket , aber es scheint zu schließen

Alles in allem macht es keinen Sinn, die Variablenbedeutung einfach aus einzelnen Dummy-Variablen "zusammenzurechnen", da dies die Assoziation zwischen ihnen nicht erfassen und zu potenziell bedeutungslosen Ergebnissen führen würde. Dies bedeutet, dass sowohl Methoden mit Gruppenstrafe als auch Methoden mit variabler Permutationsbedeutung einen kohärenten und (insbesondere bei Verfahren mit Permutationsbedeutungsbedeutung) allgemein anwendbaren Rahmen dafür bieten.

Schließlich, um das Offensichtliche festzuhalten: Bin nicht fortlaufend Daten . Es ist eine schlechte Praxis, hier (und hier ) gibt es einen ausgezeichneten Thread zu dieser Angelegenheit . Die Tatsache, dass wir nach der Diskretisierung von stetigen Variablen falsche Ergebnisse beobachten age, ist nicht überraschend. Frank Harrell hat auch ausführliche Informationen zu Problemen geschrieben, die durch die Kategorisierung kontinuierlicher Variablen verursacht werden .

usεr11852 sagt Reinstate Monic
quelle
Sie verknüpfen die relative Bedeutung einer Reihe von Prädiktoren in einer zufälligen Gesamtstrukturklassifizierung in R und beantworten die Frage direkt. Ich würde gerne annehmen, wenn Sie den Verweis auf diesen Link an den Anfang verschieben, da der Rest meiner Meinung nach nicht so direkt relevant ist und der Link in der Antwort leicht verloren gehen kann.
Dan
Kein Problem. Ich habe einige relevante Änderungen vorgenommen. Verwerfen Sie nicht das Konzept der regularisierten Regression, da Regularisierungsansätze, wie ich im Text erwähne, eine absolut gültige Alternative zur Wichtigkeit / Rangfolge von Merkmalen darstellen.
usεr11852 sagt Reinstate Monic
Regularisierte Regression ist keine Antwort auf diese Frage. Sie beantwortet möglicherweise eine andere Frage, dh Alternativen zur Merkmalsbedeutung. Bei dieser Frage geht es jedoch darum, die Merkmale zu einem einzigen kategorialen Merkmal in einem Merkmalsbedeutungsdiagramm zu aggregieren. Ich denke wirklich, Sie sollten den Link, der die Frage tatsächlich beantwortet, an den Anfang verschieben.
Dan
2

Die Frage ist:

Ist es sinnvoll, diese Dummy-Variablen-Wichtigkeiten zu einem Wichtigkeitswert für eine kategoriale Variable zu rekombinieren, indem man sie einfach summiert?

Die kurze Antwort:

Importance(Xl)=I
(I)2=t=1J1i2I(v(t)=)
I=t=1J1i2I(v(t)=)

Je länger, praktischer Antwort ..

Sie können nicht einfach einzelne Variablen-Wichtigkeitswerte für Dummy-Variablen zusammenfassen, da Sie das Risiko eingehen

die Maskierung wichtiger Variablen durch andere, mit denen sie stark korreliert sind. (Seite 368)

Probleme wie die mögliche Multikollinearität können die Werte und die Rangfolge der variablen Wichtigkeit verzerren.

Tatsächlich ist es ein sehr interessantes Problem zu verstehen, wie sich Probleme wie Multikollinearität auf die variable Bedeutung auswirken. In der Arbeit zur Bestimmung der Prädiktorbedeutung bei multipler Regression unter verschiedenen Korrelations- und Verteilungsbedingungen werden verschiedene Methoden zur Berechnung der Variablenbedeutung erörtert und die Leistung für Daten verglichen, die typische statistische Annahmen verletzen. Die Autoren fanden das

Obwohl Multikollinearität die Leistung von Methoden mit relativer Wichtigkeit beeinflusste, war dies bei multivariater Nichtnormalität nicht der Fall. (WHITTAKER S366)

ecedavis
quelle
Ich halte Ihr zweites Zitat nicht für relevant. Dies sind keine stark korrelierten Variablen, es handelt sich um dieselbe Variable, und eine gute Implementierung eines Entscheidungsbaums würde keine OHE erfordern, sondern diese als eine einzige Variable behandeln. Wenn überhaupt, wird die Multicolinearität von OHE künstlich eingeführt.
Dan
In Bezug auf Ihren ersten Punkt wundert es mich, als ob die von Breiman vorgeschlagene relative Wichtigkeitszahl der Quadratwert ist. Ich bin also nicht davon überzeugt, dass sklearn zuerst Quadratwurzeln zieht, wie Sie vorgeschlagen haben. Wenn ja, sollte ich dann nicht zuerst die Werte quadrieren, sie addieren und dann die Summe durch Quadratwurzeln berechnen? Ich bin mir nicht sicher, ob ich Ihren Vorschlag verstanden habe, zuerst die Quadratwurzel zu ziehen.
Dan
@ecedavis Was meinst du mit dem Lehrbuch? Können Sie bitte einen Link oder ein vollständigeres Zitat angeben?
see24
Hallo, danke für die Kritik und für meine erste positive Bewertung als neues Mitglied. In Ihren Kommentaren werden bestimmte Details aufgeführt, auf die ich in meiner Überarbeitung eingehen werde. Kann ich aber auch Ihre Meinung zur Gesamtqualität meiner Antwort abgeben? Dies ist mein erster Beitrag und ich plane, regelmäßig Beiträge zu schreiben. Zumindest hoffe ich, dass meine Antwort allgemein hilfreich und in gutem Stil ist. Was sind deine Gedanken?
Ecedavis
Der Stil Ihrer Antwort ist gut, aber einige der Informationen und Inhalte scheinen nicht ganz korrekt zu sein. In dem Artikel, auf den Sie verlinken, geht es um die Prädiktorbedeutung bei multipler Regression, während sich die Frage auf die Bedeutung bei zufälligen Gesamtstrukturen bezieht. Ich finde auch Ihre Extraktion des Zitats problematisch, da der ganze Satz lautet: "Auch wegen der Schrumpfung (Abschnitt 10.12.1) ist die Maskierung wichtiger Variablen durch andere, mit denen sie stark korreliert sind, weitaus weniger problematisch." Das hat eine ganz andere Bedeutung.
siehe 24.08.18