43 votos

Importancia variable relativa para impulsar

Estoy buscando una explicación de cómo relativa de importancia variable se calcula en Gradiente Impulsado Árboles que no es demasiado general y simplista como:

Las medidas se basan en el número de veces que una variable es seleccionado para la división, ponderado por el cuadrado de la mejora del modelo como resultado de cada división, y promediado sobre todos los árboles. [Elith et al. 2008]

Y que es menos abstracto que:

$\hat{I_{j}^2}(T)=\sum\limits_{t=1}^{J-1} \hat{i_{t}^2} 1(v_{t}=j)$

Donde la suma es sobre el no terminal nodos $t$ de la $J$-terminal de nodo árbol $T$, $v_{t}$ es la distribución de la variable asociada con el nodo $t$, e $\hat{i_{t}^2}$ es el correspondiente empírica mejora en el error cuadrado como resultado de la división, que se define como $i^2(R_{l},R_{r})=\frac{w_{l}w_{r}}{w_{l}+w_{r}}(\bar{y_{l}}-\bar{y_{r}})^2$ donde $\bar{y_{l}}, \bar{y_{r}}$ son la izquierda y la derecha hija de respuesta, respectivamente, y $w_{l}, w_{r}$ son las correspondientes sumas de los pesos. [Friedman 2001]

Finalmente, no he podido encontrar la Hastie a ser muy provechoso leer aquí, como en la sección correspondiente (10.13.1 página 367) gustos muy similares a los de la segunda referencia anteriormente (lo cual puede ser explicado por el hecho de que Friedman es un co-autor del libro).

PS: sé relativa de la variable importancia de las medidas están dadas por el resumen.gbm en el gbm paquete de R. Traté de explorar el código fuente, pero me parece que no puede encontrar en donde el cálculo se lleva a cabo.

Puntos Brownie: me estoy preguntando cómo conseguir estas parcelas en R.

68voto

eldering Puntos 3814

Voy a utilizar el sklearn código, como generalmente es mucho más limpio que el de R código.

Aquí está la aplicación de la feature_importances propiedad de la GradientBoostingClassifier (he quitado algunas líneas de código que se interponga en el camino de la conceptual cosas)

def feature_importances_(self):
    total_sum = np.zeros((self.n_features, ), dtype=np.float64)
    for stage in self.estimators_:
        stage_sum = sum(tree.feature_importances_
                        for tree in stage) / len(stage)
        total_sum += stage_sum

    importances = total_sum / len(self.estimators_)
    return importances

Esto es bastante fácil de entender. self.estimators_ es una matriz que contiene los árboles individuales en el refuerzo, por lo que el bucle se itera sobre los árboles individuales. Hay una hickup con el

stage_sum = sum(tree.feature_importances_
                for tree in stage) / len(stage)

este es cuidar de la no-respuesta binaria caso. Aquí se ajuste a varios árboles en cada etapa en un one-vs-todo el camino. Su forma más simple conceptualmente a centrarse en el binario caso, donde la suma tiene un sumando, y esto es sólo tree.feature_importances_. Así, en el binario caso, podemos reescribir esto como todos

def feature_importances_(self):
    total_sum = np.zeros((self.n_features, ), dtype=np.float64)
    for tree in self.estimators_:
        total_sum += tree.feature_importances_ 
    importances = total_sum / len(self.estimators_)
    return importances

Así, en las palabras, en suma, la función de las importancias de los árboles individuales, luego se divide por el número total de árboles. Queda por ver cómo calcular la función de importancias de un solo árbol.

La importancia de cálculo de un árbol que se implementa en el cython nivel, pero sigue siendo aplicables. He aquí un limpiado de la versión del código

cpdef compute_feature_importances(self, normalize=True):
    """Computes the importance of each feature (aka variable)."""

    while node != end_node:
        if node.left_child != _TREE_LEAF:
            # ... and node.right_child != _TREE_LEAF:
            left = &nodes[node.left_child]
            right = &nodes[node.right_child]

            importance_data[node.feature] += (
                node.weighted_n_node_samples * node.impurity -
                left.weighted_n_node_samples * left.impurity -
                right.weighted_n_node_samples * right.impurity)
        node += 1

    importances /= nodes[0].weighted_n_node_samples

    return importances

Esto es bastante simple. Iterar a través de los nodos del árbol. Mientras usted no está en un nodo hoja, calcular el promedio ponderado de reducción en el nodo de la pureza de la división en este nodo, y se lo atribuyen a la característica que se dividen en

importance_data[node.feature] += (
    node.weighted_n_node_samples * node.impurity -
    left.weighted_n_node_samples * left.impurity -
    right.weighted_n_node_samples * right.impurity)

Entonces, cuando se hace, se divide todo por el peso total de los datos (en la mayoría de los casos, el número de observaciones)

importances /= nodes[0].weighted_n_node_samples

Vale la pena recordar que la impureza es una métrica común para el uso al determinar qué dividir a hacer cuando el crecimiento de un árbol. En vista de eso, simplemente estamos resumiendo cuánto dividir cada característica nos ha permitido reducir la impureza a través de todas las divisiones en el árbol.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X