Imblearn SMOTE: как установить параметр sample_strategy для набора данных мультиклассового дисбаланса?

Я пытаюсь обработать набор данных с сетевыми атаками, который имеет следующую форму:

df.shape
(1074992, 42)

А метки атак и нормальное поведение имеют следующий подсчет:

df['Label'].value_counts()
normal            812814
neptune           242149
satan               5019
ipsweep             3723
portsweep           3564
smurf               3007
nmap                1554
back                 968
teardrop             918
warezclient          893
pod                  206
guesspasswd           53
bufferoverflow        30
warezmaster           20
land                  19
imap                  12
rootkit               10
loadmodule             9
ftpwrite               8
multihop               7
phf                    4
perl                   3
spy                    2
Name: Label, dtype: int64

Далее я разделяю набор данных на функции и метки.

labels = df['Label']
features = df.loc[:, df.columns != 'Label'].astype('float64')

А потом попробуй поработать над балансировкой моего набора данных.

print("Before UpSampling, counts of label Normal: {}".format(sum(labels == "normal")))
print("Before UpSampling, counts of label Attack: {} \n".format(sum(labels != "normal")))
Before UpSampling, counts of label Normal: 812814
Before UpSampling, counts of label Attack: 262178 

Как вы можете заметить, количество атак непропорционально количеству нормального поведения.

Я попытался использовать SMOTE, чтобы привести класс меньшинства (Атака) к тому же значению, что и класс большинства (Нормальный).

sm = SMOTE(k_neighbors = 1,random_state= 42)   #Synthetic Minority Over Sampling Technique
features_res, labels_res = sm.fit_resample(features, labels)
features_res.shape ,labels_res.shape
((18694722, 41), (18694722,))

Чего я не понимаю, так это почему я получаю значения 18694722 после применения SMOTE.

print("After UpSampling, counts of label Normal: {}".format(sum(labels_res == "normal")))
print("After UpSampling, counts of label Attack: {} \n".format(sum(labels_res != "normal")))
After UpSampling, counts of label Normal: 812814
After UpSampling, counts of label Attack: 17881908 

В моем случае было бы лучше понизить выборку класса Normal или повысить выборку класса Attack? Любые идеи о том, как правильно это сделать?

Большое спасибо.


person Andrei Călugăr    schedule 01.04.2021    source источник


Ответы (1)


По умолчанию sampling_strategy для SMOTE равно not majority,

'не большинство': передискретизируйте все классы, но класс большинства

поэтому, если выборка класса большинства составляет 812814, у вас будет

(812814 * 23) = 18694722

образцы.

Попробуйте передать dict с желаемым количеством образцов для классов меньшинств. Из документов

Когда dict, ключи соответствуют целевым классам. Значения соответствуют желаемому количеству выборок для каждого целевого класса.

Пример

Адаптировано из документов. один из классов меньшинства имеет то же количество образцов, что и класс большинства.

from sklearn.datasets import make_classification
from collections import Counter
from imblearn.over_sampling import SMOTE 
X, y = make_classification(n_classes=5, 
    class_sep=2, 
    weights=[0.15, 0.15, 0.1, 0.1, 0.5], 
    n_informative=4, 
    n_redundant=1, 
    flip_y=0,
    n_features=20, 
    n_clusters_per_class=1,
    n_samples=1000,
    random_state=10)

sample_strategy = {4: 500, 0: 500, 1: 150, 2: 100, 3: 100}

sm = SMOTE(sampling_strategy=sample_strategy, random_state=0)
X_res, y_res = sm.fit_resample(X, y)
from collections import Counter
print('Resampled dataset shape %s' % Counter(y_res))
>>>
Resampled dataset shape Counter({4: 500, 0: 500, 1: 150, 3: 100, 2: 100})
person Miguel Trejo    schedule 01.04.2021
comment
Спасибо, @Miguel. Я уже изучал этот вариант со словарем, но поскольку у меня есть 23 целевых класса, я пытался найти что-то еще. Но я думаю, что этот вариант работает и для моего случая. - person Andrei Călugăr; 02.04.2021