Ансамбль різних видів регресорів, що використовують scikit-learn (або будь-який інший фреймворк пітона)


27

Я намагаюся вирішити регресійну задачу. Я з’ясував, що 3 моделі чудово працюють для різних підмножини даних: LassoLARS, SVR та Gradient Tree Boosting. Я помітив, що коли я роблю прогнози, використовуючи всі ці 3 моделі, а потім складаю таблицю «справжнього виходу» та результатів 3 моїх моделей, я бачу, що щоразу принаймні одна з моделей дійсно близька до справжнього результату, хоча 2 інші може бути відносно далеко.

Коли я обчислюю мінімально можливу помилку (якщо я беру прогнозування від «найкращого» прогноктора для кожного тестового прикладу), я отримую помилку, значно меншу, ніж помилка будь-якої моделі. Тож я подумав про те, щоб спробувати поєднати передбачення з цих 3 різних моделей у якийсь ансамбль. Питання в тому, як це зробити правильно? Всі мої 3 моделі будуються та налаштовуються за допомогою scikit-learn, чи передбачений якийсь метод, який можна використовувати для упаковки моделей в ансамбль? Проблема тут полягає в тому, що я не хочу просто середні прогнози для всіх трьох моделей, я хочу це зробити з зважуванням, де зважування слід визначати на основі властивостей конкретного прикладу.

Навіть якщо scikit-learn не забезпечує такої функціональності, було б добре, якщо хтось знає, як вирішити цю задачу - з'ясувати зважування кожної моделі для кожного прикладу в даних. Я думаю, що це може зробити окремий регресор, побудований на вершині всіх цих трьох моделей, який спробує вивести оптимальні ваги для кожної з 3 моделей, але я не впевнений, чи це найкращий спосіб зробити це.

Відповіді:


32

Насправді, scikit-learnця функція надає, хоча це може бути дещо складним. Ось повний робочий приклад такого середнього регресора, побудованого на трьох моделях. Перш за все, давайте імпортуємо всі необхідні пакети:

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

Потім нам потрібно перетворити наші три регресорні моделі в трансформатори. Це дозволить нам об'єднати їхні прогнози в один векторний вектор, використовуючи 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)

Тепер давайте визначимо функцію конструктора для нашої моделі франкенштейна:

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

Нарешті, давайте підходимо до моделі:

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)

Вихід:

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

Навіщо турбуватися ускладнювати речі таким чином? Ну, такий підхід дозволяє нам оптимізувати гіперпараметри моделі за допомогою стандартних scikit-learnмодулів, таких як GridSearchCVабо RandomizedSearchCV. Також тепер можна легко зберегти і завантажити з диска заздалегідь підготовлену модель.


Використовуючи такий підхід, чи існує простий спосіб вилучити, який альго використовується, коли / яка частка кожного альго?
Девід Хаган

Можливо, перегляд коефіцієнтів лінійної моделі ( model.named_steps['lin_regr'].coef_) дасть вам деяке уявлення про те, наскільки кожна модель в ансамблі сприяє остаточному вирішенню.
constt

@constt Чи не потрібно вам використовувати cross_val_predict у базових моделях? Схоже, ваша модель вищого рівня отримає надмірно оптимістичний сигнал від базових моделей, оскільки це зараз реалізовано.
Брайан Біен

1
Це лише якийсь приклад підтвердження концепції, я тут не звертався до вибору моделі. Я думаю, що такі моделі повинні бути оптимізовані в цілому, тобто оптимізуючи гіперпараметри всіх вбудованих моделей одночасно за допомогою крос-валідаційного підходу.
constt

якщо ми ставимо n_targets = 1, X, y = make_regression(n_features=10, n_targets=1)це дає помилку розмірів. хто-небудь може пояснити, що робити?
Мохіт Ядав

9

Гаразд, витративши деякий час на гуглінг, я дізнався, як я можу робити зважування в пітоні навіть із науками-науками. Розглянемо нижче:

Я готую набір моїх регресійних моделей (як згадували SVR, LassoLars та GradientBoostingRegressor). Потім я запускаю їх усіх на дані тренувань (ті самі дані, які використовувались для тренувань кожного з цих 3 регресорів). Я отримую прогнози для прикладів з кожним із моїх алгоритмів і зберігаю ці 3 результати в паді даних фрейму зі стовпцями «передбачуваний VRR», «передбачуваний LASSO» та «передбачуваний GBR». І я додаю остаточний стовпець до цього файлу даних, який я називаю «передбачуваним», що є реальним значенням прогнозування.

Тоді я просто треную лінійну регресію на цьому новому фреймі:

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

Отже, коли я хочу зробити прогноз на новий приклад, я просто запускаю кожен з моїх 3 регресорів окремо, і тоді роблю:

 stacker.predict() 

на виходах моїх 3 регресорів. І отримати результат.

Проблема тут полягає в тому, що я знаходжу оптимальні ваги для регресорів в середньому, ваги будуть однаковими для кожного прикладу, на якому я спробую зробити передбачення.

Якщо у когось є ідеї, як зробити укладання (зважування), використовуючи функції поточного прикладу, було б непогано почути їх.


Нічого собі, мені дуже подобається такий підхід! Але чому ти використовував LinearRegression()замість LogisticRegression()моделі?
harrison4

1
@ harrison4, тому що я займався регресією, а не завданням класифікації? Тому я хотів отримати «ваговий» результат від кожної моделі. У всякому разі, це поганий підхід, хороший описаний тут: stackoverflow.com/a/35170149/3633250
Максим Khaitovich

Так, вибачте, що ви праві! дякую за те, що поділилися посиланням!
harrison4

5

Якщо у ваших даних є очевидні підмножини, ви можете запустити алгоритм кластеризації, як k-засоби, а потім пов’язати кожен класифікатор з кластерами, на яких він добре працює. Коли прийде нова точка даних, то визначте, в якому кластері знаходиться, і запустіть пов'язаний класифікатор.

Ви також можете використовувати зворотні відстані від центроїдів, щоб отримати набір ваг для кожного класифікатора і передбачити, використовуючи лінійну комбінацію всіх класифікаторів.


Я виявив тестування цієї статті (разом із порівнянням деяких подібних ідей): paper
anthonybell

Цікава ідея, хоча потребує багато роботи, щоб її застосувати. Дякую за папір!
Максим Хайтович

1

Я здійснюю тип зважування, виконуючи наступні дії, як тільки всі ваші моделі будуть повністю навчені та працюють добре:

  1. Запустіть усі свої моделі на великому наборі небачених даних тестування
  2. Зберігайте бали f1 у тестовому наборі для кожного класу, для кожної моделі
  3. Коли ви прогнозуєте з ансамблем, кожна модель дасть вам найбільш вірогідний клас, тому оцініть впевненість або ймовірність на базі f1 для цієї моделі в цьому класі. Якщо ви маєте справу з дистанцією (як, наприклад, у SVM), просто нормалізуйте відстані, щоб отримати загальну впевненість, а потім приступайте до зважування кожного класу f1.

Ви можете додатково налаштувати свій ансамбль, відміряючи певний відсоток правильності протягом певного часу. Коли ви отримаєте значно великий новий набір даних, ви зможете побудувати поріг з кроком 0,1, наприклад, проти відсотків правильних, якщо використовувати цей поріг для оцінки, щоб зрозуміти, який поріг дасть вам, скажімо, 95% правильність для 1 класу тощо. Ви можете продовжувати оновлення тестового набору та результатів f1 у міру надходження нових даних і відстежувати дрейф, перебудовуючи моделі, коли пороги або точність падають.


1
Це цікаво, але наскільки я бачу, воно працює лише для класифікаційних завдань, я намагаюся вирішити регресійну задачу. Таким чином, я не можу обчислити F1 бал.
Максим Хайтович
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.