Importancia de la característica con variables ficticias

17

Estoy tratando de entender cómo puedo obtener la importancia de una variable categórica que se ha desglosado en variables ficticias. Estoy usando scikit-learn que no maneja variables categóricas para usted como R o h2o.

Si divido una variable categórica en variables ficticias, obtengo características de entidad separadas por clase en esa variable.

Mi pregunta es, ¿tiene sentido recombinar esas importancias de variables ficticias en un valor de importancia para una variable categórica simplemente sumándolas?

De la página 368 de Los elementos del aprendizaje estadístico:

La importancia relativa al cuadrado de la variable X es la suma de tales mejoras al cuadrado sobre todos los nodos internos para los que se eligió como la variable de división

Esto me hace pensar que dado que el valor de importancia ya se creó al sumar una métrica en cada nodo que se selecciona la variable, debería poder combinar los valores de importancia de las variables ficticias para "recuperar" la importancia de la variable categórica. Por supuesto, no espero que sea exactamente correcto, pero estos valores son valores realmente exactos, ya que se encuentran a través de un proceso aleatorio.

He escrito el siguiente código de Python (en jupyter) como investigación:

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

Aquí están algunos de los resultados:

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Podemos observar que la importancia variable depende principalmente del número de categorías, lo que me lleva a cuestionar la utilidad de estos gráficos en general. Especialmente la importancia de age alcanzar valores mucho más altos que su contraparte continua.

Y finalmente, un ejemplo si los dejo como variables ficticias (solo 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")

ingrese la descripción de la imagen aquí

Dan
fuente

Respuestas:

8

Cuando se trabaja en la "importancia de las características" en general, es útil recordar que, en la mayoría de los casos, un enfoque de regularización suele ser una buena alternativa. Automáticamente "seleccionará las características más importantes" para el problema en cuestión. Ahora, si no queremos seguir la noción de regularización (generalmente dentro del contexto de regresión), los clasificadores de bosque aleatorios y la noción de pruebas de permutación naturalmente brindan una solución para destacar la importancia del grupo de variables. Esto se ha preguntado antes aquí: " Importancia relativa de un conjunto de predictores en una clasificación aleatoria de bosques en R " hace unos años. Enfoques más rigurosos como los de Gregorutti et al.: " Importancia variable agrupada con bosques aleatorios y aplicación al análisis de datos funcionales multivariados ". Chakraborty y Pal 'analiza esta tarea dentro del contexto de un perceptrón multicapa. Volviendo a Gregorutti et al. En papel, su metodología es directamente aplicable a cualquier tipo de algoritmo de clasificación / regresión. En resumen, usamos una versión permutada aleatoriamente en cada muestra que se usa durante el entrenamiento.

Una vez dicho lo anterior, si bien las pruebas de permutación son en última instancia heurísticas, lo que se ha resuelto con precisión en el pasado es la penalización de las variables ficticias dentro del contexto de la regresión regularizada. La respuesta a esa pregunta es Group-LASSO , Group-LARS y Group-Garotte . Los documentos fundamentales en ese trabajo son Yuan y Lin: " Selección y estimación del modelo en regresión con variables agrupadas " (2006) y Meier et al.: " El lazo grupal para la regresión logística " (2008). Esta metodología nos permite trabajar en situaciones en las que: " cada factor puede tener varios niveles y puede expresarse a través de un grupo de variables ficticias " (Y&L 2006). El efecto es tal que " el lazo grupal fomenta la escasez a nivel de factor " (Y&L 2006).l1Kjj={1,...,J}J si desea continuar con esto. [Porque mencionamos Python específicamente: no he usado el pyglmnetpaquete de Python pero parece incluir

En general, no tiene sentido simplemente "sumar" la importancia variable de las variables ficticias individuales porque no capturaría la asociación entre ellas y no conduciría a resultados potencialmente sin sentido. Dicho esto, tanto los métodos penalizados por grupo como los métodos de importancia variable de permutación proporcionan un marco coherente y (especialmente en el caso de los procedimientos de importancia de permutación) generalmente aplicable para hacerlo.

Finalmente para decir lo obvio: no bin datos continuos . Es una mala práctica, hay un excelente hilo sobre este asunto aquí (y aquí ). El hecho de que observemos resultados espurios después de la discretización de la variable continua, como age, no es sorprendente. Frank Harrell también ha escrito mucho sobre problemas causados ​​por categorizar variables continuas .

usεr11852 dice Reinstate Monic
fuente
Vincular La importancia relativa de un conjunto de predictores en una clasificación aleatoria de bosques en R responde la pregunta directamente. Me encantaría aceptar si mueve la referencia a ese enlace al principio, ya que no creo que el resto sea tan directamente relevante y el enlace se puede perder fácilmente en la respuesta.
Dan
No hay problema. Hice algunas ediciones relevantes. No descarte el concepto de regresión regularizada, como menciono en el texto, los enfoques de regularización ofrecen una alternativa perfectamente válida para destacar la importancia / clasificación.
usεr11852 dice Reinstate Monic el
La regresión regularizada no es una respuesta a esta pregunta, puede responder una pregunta diferente, es decir, alternativas a la importancia de las características, pero esta pregunta se trata de agregar las características en una sola característica categórica dentro de un gráfico de importancia de la característica. Realmente creo que deberías mover el enlace que realmente responde la pregunta al principio.
Dan
2

La pregunta es:

¿Tiene sentido recombinar esas importancias de variables ficticias en un valor de importancia para una variable categórica simplemente sumándolas?

La respuesta corta:

yometropagortunnorteCmi(Xl)=yo
(yo)2=t=1J-1yo2yo(v(t)=)
yo=t=1J-1yo2yo(v(t)=)

La respuesta más larga y práctica.

No puede simplemente sumar valores de importancia de variables individuales para variables ficticias porque corre el riesgo

el enmascaramiento de variables importantes por otros con los cuales están altamente correlacionados. (página 368)

Problemas como la posible multicolinealidad pueden distorsionar los valores de importancia variable y las clasificaciones.

En realidad, es un problema muy interesante comprender cómo la importancia variable se ve afectada por problemas como la multicolinealidad. El documento Determinación de la importancia del predictor en la regresión múltiple en condiciones correlacionales y distributivas variadas analiza varios métodos para calcular la importancia variable y compara el rendimiento de los datos que violan los supuestos estadísticos típicos. Los autores encontraron que

Aunque la multicolinealidad afectó el desempeño de los métodos de importancia relativa, la no normalidad multivariante no lo hizo. (WHITTAKER p366)

ecedavis
fuente
No creo que tu segunda cita sea relevante. Estas no son variables altamente correlacionadas, son la misma variable y una buena implementación de un árbol de decisión no requeriría OHE pero las trataría como una sola variable. En todo caso, OHE introduce artificialmente la multicolinealidad.
Dan
Con respecto a su primer punto, me duele que el número de importancia relativa propuesto por Breiman sea el valor al cuadrado. Así que no estoy convencido de que sklearn tome raíces cuadradas primero, como has sugerido. Además, si lo hacen, ¿no debería primero cuadrar los valores, agregarlos y luego enraizar la suma? No estoy seguro de haber entendido su sugerencia de tomar la raíz cuadrada primero.
Dan
@ecedavis ¿Qué quieres decir con el libro de texto? ¿Puede proporcionar un enlace o una cita más completa por favor?
see24
Hola, gracias por las críticas y por mi primer voto como nuevo miembro. Sus comentarios señalan detalles específicos que abordaré en mi revisión, pero ¿puedo tener también su opinión sobre la calidad general de mi respuesta? Esta es mi primera publicación y planeo convertirme en un colaborador habitual. Como mínimo, espero que mi respuesta sea generalmente útil y de buen estilo. ¿Cuáles son tus pensamientos?
ecedavis el
El estilo de su respuesta es bueno, pero parte de la información y el contenido no parecen completamente correctos. El documento al que se vincula es sobre la importancia del predictor en regresión múltiple, mientras que la pregunta es sobre la importancia en el bosque aleatorio. También encuentro que su extracción de la cita es problemática ya que la oración completa es "Además, debido a la contracción (Sección 10.12.1), el enmascaramiento de variables importantes por otros con los que están altamente correlacionados es mucho menos un problema". que tiene un significado muy diferente.
ver24