Попытка сбалансировать мой набор данных с помощью sample_weight в scikit-learn

Я использую RandomForest для классификации, и я получил несбалансированный набор данных, как: 5830-нет, 1006-да. Я пытаюсь сбалансировать свой набор данных с class_weight и sample_weight, но не могу.

Мой код:

X_train,X_test,y_train,y_test = train_test_split(arrX,y,test_size=0.25)
cw='auto'
clf=RandomForestClassifier(class_weight=cw) 
param_grid = { 'n_estimators': [10,50,100,200,300],'max_features': ['auto', 'sqrt', 'log2']}
sw = np.array([1 if i == 0 else 8 for i in y_train])
CV_clf = GridSearchCV(estimator=clf, param_grid=param_grid, cv= 10,fit_params={'sample_weight': sw})

Но я не получаю никаких улучшений в моих соотношениях TPR, FPR, ROC при использовании class_weight и sample_weight.

Зачем? Я делаю что-то не так?

Тем не менее, если я использую функцию balance_subsample, мои коэффициенты получат значительное улучшение:

def balanced_subsample(x,y,subsample_size):

    class_xs = []
    min_elems = None

    for yi in np.unique(y):
        elems = x[(y == yi)]
        class_xs.append((yi, elems))
        if min_elems == None or elems.shape[0] < min_elems:
            min_elems = elems.shape[0]

    use_elems = min_elems
    if subsample_size < 1:
        use_elems = int(min_elems*subsample_size)

    xs = []
    ys = []

    for ci,this_xs in class_xs:
        if len(this_xs) > use_elems:
            np.random.shuffle(this_xs)

        x_ = this_xs[:use_elems]
        y_ = np.empty(use_elems)
        y_.fill(ci)

        xs.append(x_)
        ys.append(y_)

    xs = np.concatenate(xs)
    ys = np.concatenate(ys)

    return xs,ys 

Мой новый код:

X_train_subsampled,y_train_subsampled=balanced_subsample(arrX,y,0.5)
X_train,X_test,y_train,y_test = train_test_split(X_train_subsampled,y_train_subsampled,test_size=0.25)
cw='auto'
clf=RandomForestClassifier(class_weight=cw) 
param_grid = { 'n_estimators': [10,50,100,200,300],'max_features': ['auto', 'sqrt', 'log2']}
sw = np.array([1 if i == 0 else 8 for i in y_train])
CV_clf = GridSearchCV(estimator=clf, param_grid=param_grid, cv= 10,fit_params={'sample_weight': sw})

Спасибо

2 ответа

Решение

Это еще не полный ответ, но, надеюсь, это поможет.

Сначала несколько общих замечаний:

  • Для отладки такого рода проблем часто бывает полезно иметь детерминированное поведение. Вы можете передать random_state приписывать RandomForestClassifier и различные объекты scikit-learn, которым присуща случайность, чтобы получать одинаковый результат при каждом запуске. Вам также понадобится:

    import numpy as np
    np.random.seed()
    import random
    random.seed()
    

для тебя balanced_subsample Функция вести себя одинаково при каждом запуске.

  • Не искать по сетке n_estimators: больше деревьев всегда лучше в случайном лесу.
  • Обратите внимание, что sample_weight а также class_weight иметь аналогичную цель: фактический вес образца будет sample_weight* веса выведены изclass_weight,

Не могли бы вы попробовать:

  • Используя subsample=1 в вашем balanced_subsample функция. Если нет особой причины не делать этого, нам лучше сравнивать результаты с одинаковым количеством образцов.
  • Используя вашу стратегию субсэмплинга с class_weight а также sample_weight оба установлены на None.

РЕДАКТИРОВАТЬ: Читая ваш комментарий еще раз, я понимаю, что ваши результаты не так удивительно!
Вы получаете лучший (более высокий) TPR, но худший (более высокий) FPR.
Это просто означает, что ваш классификатор изо всех сил старается получить правильные образцы из класса 1 и, таким образом, делает больше ложных срабатываний (в то же время, конечно, получая больше правильных!).
Эта тенденция сохранится, если вы продолжите увеличивать веса классов / образцов в одном и том же направлении.

Существует API с несбалансированным обучением, который помогает с избыточной выборкой / недостаточной выборкой данных, которые могут быть полезны в этой ситуации. Вы можете передать свой тренировочный набор в один из методов, и он выведет данные с избыточной дискретизацией для вас. Смотрите простой пример ниже

from imblearn.over_sampling import RandomOverSampler

ros = RandomOverSampler(random_state=1)

x_oversampled, y_oversampled = ros.fit_sample(orig_x_data, orig_y_data)

Вот это ссылка на API: http://contrib.scikit-learn.org/imbalanced-learn/api.html

Надеюсь это поможет!

Другие вопросы по тегам