35 votos

Ensamble de diferentes tipos de regresores utilizando scikit-learn (o cualquier otro framework de python)

Estoy tratando de resolver la tarea de regresión. He descubierto que hay 3 modelos que funcionan bien para diferentes subconjuntos de datos: LassoLARS, SVR y Gradient Tree Boosting. Me he dado cuenta de que cuando hago predicciones utilizando estos 3 modelos y luego hago una tabla de 'salida verdadera' y salidas de mis 3 modelos veo que cada vez al menos uno de los modelos está realmente cerca de la salida verdadera, aunque otros 2 podrían estar relativamente lejos.

Cuando calculo el error mínimo posible (si tomo la predicción del "mejor" predictor para cada ejemplo de prueba) obtengo un error que es mucho menor que el error de cualquier modelo por sí solo. Así que pensé en intentar combinar las predicciones de estos 3 modelos diferentes en una especie de conjunto. La pregunta es, ¿cómo hacer esto correctamente? Todos mis 3 modelos están construidos y ajustados usando scikit-learn, ¿proporciona algún tipo de método que pueda ser utilizado para empaquetar los modelos en el conjunto? El problema aquí es que no quiero simplemente promediar las predicciones de los tres modelos, quiero hacer esto con la ponderación, donde la ponderación debe ser determinada sobre la base de las propiedades de un ejemplo específico.

Incluso si scikit-learn no proporciona tal funcionalidad, sería bueno si alguien sabe cómo propiedad abordar esta tarea - de averiguar la ponderación de cada modelo para cada ejemplo en los datos. Creo que podría ser hecho por un regresor separado construido en la parte superior de todos estos 3 modelos, que tratará de salida pesos óptimos para cada uno de los 3 modelos, pero no estoy seguro de si esta es la mejor manera de hacer esto.

39voto

Tim Swast Puntos 3697

En realidad, scikit-learn proporciona esta funcionalidad, aunque puede ser un poco difícil de implementar. Aquí tenemos un ejemplo completo de un regresor promedio construido sobre tres modelos. En primer lugar, vamos a importar todos los paquetes necesarios:

from sklearn.base import TransformerMixin
from sklearn.datasets import make_regression
from sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.neighbors import KNeighborsRegressor
from sklearn.preprocessing import StandardScaler, PolynomialFeatures
from sklearn.linear_model import LinearRegression, Ridge

A continuación, tenemos que convertir nuestros tres modelos de regresores en transformadores. Esto nos permitirá fusionar sus predicciones en un único vector de características utilizando FeatureUnion :

class RidgeTransformer(Ridge, TransformerMixin):

    def transform(self, X, *_):
        return self.predict(X).reshape(len(X), -1)

class RandomForestTransformer(RandomForestRegressor, TransformerMixin):

    def transform(self, X, *_):
        return self.predict(X).reshape(len(X), -1)

class KNeighborsTransformer(KNeighborsRegressor, TransformerMixin):

    def transform(self, X, *_):
        return self.predict(X).reshape(len(X), -1)

Ahora, vamos a definir una función constructora para nuestro modelo frankenstein:

def build_model():
    ridge_transformer = Pipeline(steps=[
        ('scaler', StandardScaler()),
        ('poly_feats', PolynomialFeatures()),
        ('ridge', RidgeTransformer())
    ])

    pred_union = FeatureUnion(
        transformer_list=[
            ('ridge', ridge_transformer),
            ('rand_forest', RandomForestTransformer()),
            ('knn', KNeighborsTransformer())
        ],
        n_jobs=2
    )

    model = Pipeline(steps=[
        ('pred_union', pred_union),
        ('lin_regr', LinearRegression())
    ])

    return model

Por último, vamos a ajustar el modelo:

print('Build and fit a model...')

model = build_model()

X, y = make_regression(n_features=10)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

model.fit(X_train, y_train)
score = model.score(X_test, y_test)

print('Done. Score:', score)

La salida:

Build and fit a model...
Done. Score: 0.9600413867438636

¿Por qué molestarse en complicar las cosas de esa manera? Pues bien, este enfoque nos permite optimizar los hiperparámetros del modelo utilizando la scikit-learn módulos como GridSearchCV o RandomizedSearchCV . Además, ahora es posible guardar y cargar fácilmente desde el disco un modelo preentrenado.

11voto

benzen Puntos 153

Ok, después de pasar algún tiempo en google encontré cómo podía hacer la ponderación en python incluso con scikit-learn. Tenga en cuenta lo siguiente:

Entreno un conjunto de mis modelos de regresión (como los mencionados SVR, LassoLars y GradientBoostingRegressor). Luego ejecuto todos ellos en los datos de entrenamiento (los mismos datos que se utilizaron para el entrenamiento de cada uno de estos 3 regresores). Obtengo las predicciones de los ejemplos con cada uno de mis algoritmos y guardo estos 3 resultados en un marco de datos pandas con las columnas 'predictedSVR', 'predictedLASSO' y 'predictedGBR'. Y añado la columna final en este datafrane que llamo 'predicted' que es un valor de predicción real.

Entonces simplemente entreno una regresión lineal en este nuevo marco de datos:

 #df - dataframe with results of 3 regressors and true output

 from sklearn linear_model
 stacker= linear_model.LinearRegression()
 stacker.fit(df[['predictedSVR', 'predictedLASSO', 'predictedGBR']], df['predicted'])

Así que cuando quiero hacer una predicción para el nuevo ejemplo sólo ejecuto cada uno de mis 3 regresores por separado y luego lo hago:

 stacker.predict() 

en las salidas de mis 3 regresores. Y obtener un resultado.

El problema aquí es que estoy encontrando pesos óptimos para los regresores 'en promedio, los pesos serán los mismos para cada ejemplo en el que voy a tratar de hacer la predicción.

Si alguien tiene alguna idea sobre cómo hacer el apilamiento (ponderación) utilizando las características del ejemplo actual sería bueno escucharla.

7voto

Łukasz Lew Puntos 10907

Si sus datos tienen subconjuntos obvios, podría ejecutar un algoritmo de agrupación como k-means y luego asociar cada clasificador con los clústeres en los que funciona bien. Cuando llegue un nuevo punto de datos, determine en qué clúster se encuentra y ejecute el clasificador asociado.

También podría utilizar las distancias inversas de los centroides para obtener un conjunto de pesos para cada clasificador y predecir utilizando una combinación lineal de todos los clasificadores.

2voto

Ying Xiao Puntos 1019

Logro un tipo de ponderación haciendo lo siguiente, una vez que todos sus modelos están completamente entrenados y funcionando bien:

  1. Ejecute todos sus modelos en un gran conjunto de datos de prueba no vistos
  2. Almacenar las puntuaciones f1 en el conjunto de pruebas para cada clase, para cada modelo
  3. Cuando predices con el conjunto, cada modelo te dará la clase más probable, así que pondera la confianza o la probabilidad por la puntuación f1 de ese modelo en esa clase. Si está tratando con la distancia (como en SVM, por ejemplo), simplemente normalice las distancias para obtener una confianza general, y luego proceda con la ponderación f1 por clase.

Puede afinar aún más su conjunto midiendo el porcentaje de aciertos a lo largo del tiempo. Una vez que tenga un nuevo conjunto de datos significativamente grande y puntuado, puede trazar el umbral en pasos de 0,1, por ejemplo, contra el porcentaje de corrección si utiliza ese umbral para puntuar, para tener una idea de qué umbral le dará, digamos, un 95% de corrección para la clase 1, y así sucesivamente. Puede seguir actualizando el conjunto de pruebas y las puntuaciones de f1 a medida que llegan nuevos datos y hacer un seguimiento de la deriva, reconstruyendo los modelos cuando los umbrales o la precisión caen.

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