Zespół różnych rodzajów regresorów wykorzystujących scikit-learn (lub dowolną inną platformę python)

27

Próbuję rozwiązać zadanie regresji. Dowiedziałem się, że 3 modele działają dobrze dla różnych podzbiorów danych: LassoLARS, SVR i Gradient Tree Boosting. Zauważyłem, że kiedy robię prognozy na podstawie tych wszystkich 3 modeli, a następnie tworzę tabelę „rzeczywistych wyników” i wyników moich 3 modeli, widzę, że za każdym razem przynajmniej jeden z modeli jest naprawdę bliski rzeczywistej mocy wyjściowej, chociaż 2 inne może być stosunkowo daleko.

Kiedy obliczam minimalny możliwy błąd (jeśli we wszystkich przykładach testowych przewiduję „najlepszy” predyktor), otrzymuję błąd, który jest znacznie mniejszy niż błąd dowolnego modelu. Pomyślałem więc o próbie połączenia prognoz z tych 3 różnych modeli w coś w rodzaju zestawu. Pytanie brzmi, jak to zrobić poprawnie? Wszystkie moje 3 modele są budowane i dostrajane przy użyciu scikit-learn. Czy zapewnia to jakąś metodę, która mogłaby zostać użyta do spakowania modeli w zespół? Problem polega na tym, że nie chcę tylko uśredniać prognoz ze wszystkich trzech modeli, chcę to zrobić z ważeniem, gdzie ważenie powinno być określane na podstawie właściwości konkretnego przykładu.

Nawet jeśli scikit-learn nie zapewnia takiej funkcjonalności, byłoby miło, gdyby ktoś wiedział, jak rozwiązać ten problem - obliczyć wagę każdego modelu dla każdego przykładu w danych. Myślę, że może to być zrobione przez osobny regresor zbudowany na wszystkich tych 3 modelach, który spróbuje uzyskać optymalne wagi dla każdego z 3 modeli, ale nie jestem pewien, czy jest to najlepszy sposób na zrobienie tego.

Maksim Chajowicz
źródło

Odpowiedzi:

32

W rzeczywistości scikit-learnzapewnia taką funkcjonalność, choć jej wdrożenie może być nieco trudne. Oto kompletny przykład działania takiego przeciętnego regresora zbudowanego na trzech modelach. Najpierw zaimportujmy wszystkie wymagane pakiety:

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

Następnie musimy przekształcić nasze trzy modele regresorów w transformatory. Pozwoli nam to scalić swoje predykcje w jeden wektor cech za pomocą FeatureUnion:

class RidgeTransformer(Ridge, TransformerMixin):

    def transform(self, X, *_):
        return self.predict(X)


class RandomForestTransformer(RandomForestRegressor, TransformerMixin):

    def transform(self, X, *_):
        return self.predict(X)


class KNeighborsTransformer(KNeighborsRegressor, TransformerMixin):

    def transform(self, X, *_):
        return self.predict(X)

Teraz zdefiniujmy funkcję konstruktora dla naszego modelu 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

Na koniec dopasujmy model:

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

model = build_model()

X, y = make_regression(n_features=10, n_targets=2)
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)

Wydajność:

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

Po co męczyć się w taki sposób? To podejście pozwala nam zoptymalizować hiperparametry modelu przy użyciu standardowych scikit-learnmodułów, takich jak GridSearchCVlub RandomizedSearchCV. Ponadto teraz można łatwo zapisać i załadować z dysku wstępnie wyszkolony model.

constt
źródło
Czy stosując ten sposób, istnieje prosty sposób na wyodrębnienie, które algo jest używane, kiedy / jaka część każdego z algo?
David Hagan,
Być może patrząc na współczynniki wynikowego modelu liniowego (model.named_steps['lin_regr'].coef_ ) da ci pewien wgląd w to, jak bardzo każdy model w zespole przyczynia się do ostatecznego rozwiązania.
constt
@constt Czy nie musisz używać cross_val_predict w swoich modelach podstawowych? Wygląda na to, że Twój model najwyższego poziomu otrzymałby zbyt optymistyczny sygnał z twoich modeli podstawowych, ponieważ jest to obecnie realizowane.
Brian Bien
1
To tylko przykład dowodu koncepcji, nie omawiałem tutaj wyboru modelu. Myślę, że takie modele powinny być optymalizowane jako całość, tj. Optymalizując hiperparametry wszystkich modeli wbudowanych jednocześnie, stosując metodę walidacji krzyżowej.
constt
jeśli wstawimy n_targets = 1 X, y = make_regression(n_features=10, n_targets=1) , daje to błąd wymiaru. czy ktoś może wyjaśnić, co robić?
Mohit Yadav
9

Ok, po spędzeniu czasu na googlowaniu dowiedziałem się, jak mogę wyważać w pythonie, nawet przy scikit-learn. Rozważ poniższe:

Trenuję zestaw moich modeli regresji (jak wspomniano SVR, LassoLars i GradientBoostingRegressor). Następnie uruchamiam je wszystkie na danych treningowych (te same dane, które zostały wykorzystane do szkolenia każdego z tych 3 regresorów). Otrzymuję prognozy dla przykładów z każdym z moich algorytmów i zapisuję te 3 wyniki w ramce danych pandy z kolumnami „przewidywana SVR”, „przewidywana LASSO” i „przewidywana GBR”. I dodaję ostatnią kolumnę do tego analizatora danych, który nazywam „przewidywanym”, który jest prawdziwą wartością predykcyjną.

Następnie trenuję regresję liniową na tej nowej ramce danych:

 #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'])

Więc kiedy chcę przewidzieć nowy przykład, po prostu uruchamiam każdy z moich 3 regresorów osobno, a następnie:

 stacker.predict() 

na wyjściach moich 3 regresorów. I uzyskaj wynik.

Problem polega na tym, że znajduję optymalne wagi dla regresorów średnio, wagi będą takie same dla każdego przykładu, na którym spróbuję dokonać prognozy.

Jeśli ktoś ma jakieś pomysły na temat układania w stosy (ważenia) przy użyciu funkcji z obecnego przykładu, dobrze byłoby je usłyszeć.

Maksim Chajowicz
źródło
Wow, bardzo podoba mi się to podejście! Ale dlaczego użyłeś LinearRegression()zamiast LogisticRegression()modelu?
harrison4
1
@ harrison4, ponieważ robiłem regresję, a nie klasyfikację? Chciałem więc „wyważyć” dane wyjściowe z każdego modelu. W każdym razie jest to złe podejście, dobre jest opisane tutaj: stackoverflow.com/a/35170149/3633250
Maksim Chajowicz
Tak, przepraszam, masz rację! Dziękujemy za podzielenie się linkiem!
harrison4
5

Jeśli twoje dane mają oczywiste podzbiory, możesz uruchomić algorytm klastrowania, taki jak k-średnich, a następnie powiązać każdy klasyfikator z klastrami, na których działa on dobrze. Kiedy pojawi się nowy punkt danych, określ, w którym klastrze się znajduje, i uruchom powiązany klasyfikator.

Możesz również użyć odwrotnych odległości od centroidów, aby uzyskać zestaw wag dla każdego klasyfikatora i przewidzieć za pomocą liniowej kombinacji wszystkich klasyfikatorów.

anthonybell
źródło
Znalazłem gazetę testującą tę strategię (wraz z porównaniem niektórych podobnych pomysłów): papier
Anthonybell
Ciekawy pomysł, ale wymaga dużo pracy, aby go zastosować. Dzięki za papier!
Maksim Chajowicz
1

Dokonuję pewnego rodzaju ważenia, wykonując następujące czynności, gdy wszystkie modele zostaną w pełni wyszkolone i osiągną dobre wyniki:

  1. Uruchom wszystkie modele na dużym zestawie niewidzialnych danych testowych
  2. Zapisz wyniki F1 w zestawie testowym dla każdej klasy, dla każdego modelu
  3. Kiedy przewidujesz z zespołem, każdy model da ci najbardziej prawdopodobną klasę, więc waż pewność i prawdopodobieństwo według oceny f1 dla tego modelu w tej klasie. Jeśli masz do czynienia z odległością (jak na przykład w SVM), po prostu normalizuj odległości, aby uzyskać ogólną pewność, a następnie przejdź do ważenia według klasy f1.

Możesz dalej dostroić swój zespół, mierząc procent poprawności przez pewien czas. Po uzyskaniu znacznie dużego, nowego zestawu danych można wykreślić próg w krokach co 0,1, w porównaniu z procentem poprawnym, jeśli użyjesz tego progu do oceny, aby zorientować się, jaki próg da ci, powiedzmy, 95% poprawność dla klasy 1 i tak dalej. Możesz aktualizować zestaw testowy i wyniki F1 w miarę pojawiania się nowych danych i śledzić dryf, odbudowując modele, gdy spadną progi lub dokładność.

wwwslinger
źródło
1
To ciekawe, ale o ile wiem, działa tylko w przypadku zadań klasyfikacyjnych, podczas gdy próbuję rozwiązać zadanie regresji. Dlatego nie mogę obliczyć wyniku F1.
Maksim Chajowicz