Случайный лес с несбалансированным классом (положительный класс меньшинства), низкой точностью и странным распределением баллов - PullRequest
0 голосов
/ 07 февраля 2019

У меня очень несбалансированный набор данных (5000 положительных, 300000 отрицательных).Я использую sklearn RandomForestClassifier, чтобы попытаться предсказать вероятность положительного класса.У меня есть данные за несколько лет, и одна из функций, которые я разработал, - это класс в предыдущем году, поэтому я отказываюсь тестировать последний год набора данных в дополнение к своему тестовому набору в течение тех лет, когда я обучаюсь.на.

Вот что я попробовал (и результат):

Повышение дискретизации с SMOTE и SMOTEENN (странные распределения баллов, см. Первое изображение, предсказанные вероятности для положительного и отрицательного классов одинаковыт. е. модель предсказывает очень низкую вероятность для большинства положительного класса)

Понижение выборки до сбалансированного набора данных (вспомним ~ 0,80 для набора тестов, но 0,07 для набора тестов вне года изогромное количество общих негативов в наборе несбалансированных вне года, см. второе изображение)

Оставьте его несбалансированным (странное распределение баллов снова, точность возрастает до ~ 0,60, а отзыв падает до 0,05 и 0,10 для теста и выходанабор тестов за год)

XGBoost (чуть лучше вспомнить тестовый набор за год, 0,11)

Что мне попробовать дальше?Я хотел бы оптимизировать для F1, так как ложные срабатывания и ложные отрицания одинаково плохи в моем случае.Я хотел бы включить перекрестную проверку в k-кратном порядке и прочитал, что я должен сделать это перед повышением частоты, а) если я сделаю это / это может помочь, и б) как я могу включить это в конвейер, подобный следующему:

from imblearn.pipeline import make_pipeline, Pipeline

clf_rf = RandomForestClassifier(n_estimators=25, random_state=1)
smote_enn = SMOTEENN(smote = sm)
kf = StratifiedKFold(n_splits=5)

pipeline = make_pipeline(??)

pipeline.fit(X_train, ytrain)
ypred = pipeline.predict(Xtest)
ypredooy = pipeline.predict(Xtestooy)

score_distscore_dist

1 Ответ

0 голосов
/ 07 февраля 2019
  • Повышение частоты дискретизации с SMOTE и SMOTEENN: я далек от того, чтобы быть экспертом с ними, но с помощью повышения частоты дискретизации вашего набора данных вы можете усилить существующий шум, который вызывает переобучение.Это может объяснить тот факт, что ваш алгоритм не может правильно классифицировать, что дает результаты в первом графике.

Я нашел здесь немного больше информации и, возможно, как улучшить ваши результаты: https://sci2s.ugr.es/sites/default/files/ficherosPublicaciones/1773_ver14_ASOC_SMOTE_FRPS.pdf

  • Когда вы уменьшаете выборку, вы, похоже, сталкиваетесь с той же проблемой переоснащения, которую я понимаю (по крайней мере, для целевого результата предыдущего года).Трудно определить причину этого, не смотря на данные.

  • Ваша проблема с переоснащением может быть связана с количеством используемых вами функций, которые могут добавить ненужный шум.Вы можете попытаться уменьшить количество используемых вами функций и постепенно увеличивать их (используя модель RFE).Более подробная информация здесь:

https://machinelearningmastery.com/feature-selection-in-python-with-scikit-learn/

Для используемых вами моделей вы упомянули Random Forest и XGBoost, но не упомянули, что использовали более простую модель.Вы можете попробовать более простую модель и сосредоточиться на своей инженерии данных.Если вы еще не попробовали это, возможно, вы могли бы:

  • Уменьшить ваши данные
  • Нормализовать все ваши данные с помощью грубой силы StandardScaler
  • Test"настройка простых моделей, таких как Наивный Байес и Логистическая регрессия

    # Define steps of the pipeline
    steps = [('scaler', StandardScaler()),
             ('log_reg', LogisticRegression())]
    
    pipeline = Pipeline(steps)
    
    # Specify the hyperparameters
    parameters = {'C':[1, 10, 100],
                  'penalty':['l1', 'l2']}
    
    # Create train and test sets
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, 
    random_state=42)
    
    # Instantiate a GridSearchCV object: cv
    cv = GridSearchCV(pipeline, param_grid=parameters)
    
    # Fit to the training set
    cv.fit(X_train, y_train)
    

В любом случае, для вашего примера конвейер может быть (я сделал это с помощью Логистической регрессии, но вы можете изменить его с помощью другогоАлгоритм ML и соответственно изменить сетку параметров):

from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import GridSearchCV, StratifiedKFold, cross_val_score

from imblearn.combine import SMOTEENN
from imblearn.over_sampling import SMOTE
from imblearn.pipeline import Pipeline

param_grid = {'C': [1, 10, 100]}

clf = LogisticRegression(solver='lbfgs', multi_class = 'auto')
sme = SMOTEENN(smote = SMOTE(k_neighbors = 2), random_state=42)
grid = GridSearchCV(estimator=clf, param_grid = param_grid, score = "f1")

pipeline = Pipeline([('scale', StandardScaler()),
                     ('SMOTEENN', sme),
                     ('grid', grid)])

cv = StratifiedKFold(n_splits = 4, random_state=42)
score = cross_val_score(pipeline, X, y, cv=cv)

Надеюсь, это может вам помочь.

(правка: я добавил счет = "f1" в GridSearchCV)

...