Model Regresji Logistycznej. Część 2: Oversampling

Oversampling

Oversampling jest metodą częściowo usuwającą skutki niezbilansowania zbioru wynikowego.

Metodę tą stosuje się dla zbioru treningowego aby tak wytrenował przy jego pomocy model, by zniwelować skutki niezbilansowania.

Przy niezbilansowanym zbiorze zmiennych zależnych model regresji logistycznej może nie wskazać wszystkich zdarzeń o charakterze rzadkim. Każdy model ma tendencje do uogólniania rzeczywistości. Dla banku bardzo ważne jest wskazanie wszystkich malwersacji nawet za cenę wskazania niektórych zwykłych transakcji jako malwersacje.

Uwrażliwienie modelu na zdarzenia rzadkie możliwe jest poprzez nadpróbkowanie lub poprzez przesunięcie granicy prawdopodobieństwa.

Przesunięcie wrażliwości modelu na malwersacje poprawi wskaźnik Recall kosztem wskaźnika Precission.

Tworzenie Oversampling

Oversampling i próbkowanie w analizie danych są technikami stosowanymi do dostosowania rozkładu klas zestawu danych (tj. Stosunku między różnymi reprezentowanymi klasami / kategoriami). Terminy te są używane zarówno w statystycznym próbkowaniu, metodologii projektowania badań, jak i w uczeniu maszynowym.

(źródło: https://www.wikiwand.com/en/Oversampling_and_undersampling_in_data_analysis)

 Losowy oversampling  (losowe zwiększenie ilości próbek mniejszościowych)

Losowe nadpróbkowanie polega na uzupełnieniu danych treningowych wieloma kopiami niektórych klas mniejszościowych. Nadpróbkowanie można wykonać więcej niż raz (2x, 3x, 5x, 10x itd.)

 Losowy undersampling  (losowe zmniejszanie ilości próbek większościowych)

Losowo usuwa próbki z klasy większościowych, z lub bez wymiany. Jest to jedna z najwcześniejszych technik stosowanych w celu złagodzenia nierównowagi w zbiorze danych, może to jednak zwiększyć wariancję klasyfikatora i potencjalnie odrzucić użyteczne lub ważne próbki.

(źródło: https://en.wikipedia.org/wiki/Oversampling_and_undersampling_in_data_analysis)

Procedura oversampling

Poniższa analiza jest kontynuacją procesu budowy modelu regresji liniowej prowadzonego tutaj.

Przypomnijmy jak bardzo nasz zbiór zmiennych endogenicznych jest niezbilansowany.

df.Class.value_counts(dropna = False, normalize=True)

Tylko 0,46% zmiennych zależnych w zbiorze pierwotnym stanowią zmienne 1. Oznacza to, że na jedną zmienną oznaczoną jako 1 przypada 217 zmiennych 0.

Spróbujmy odwzorować tą zależność dla danych treningowych w Pythonie:

print("ytrain = 0: ", sum(ytrain == 0))
print("ytrain = 1: ", sum(ytrain == 1))

OVS_gauge = sum(ytrain == 0) / sum(ytrain == 1) 
OVS_gauge = np.round(OVS_gauge, decimals=0)
OVS_gauge = OVS_gauge.astype(int)
OVS_gauge

216

Na jedną treningową zmienną zależną 1 przypada 216 testowych zmiennych zależnych 0.

Jak widać zbiór treningowy zachował proporcje w stosunku do zbioru pierwotnego dzięki użyciu parametru stratify = y w równaniu definiującym zbiór testowy i zbiór treningowy.

Teraz możemy zwiększyć o 217 razy ilość testowych zmiennych zależnych.

ytrain_pos_OVS = pd.concat([ytrain[ytrain==1]] * OVS_gauge, axis = 0) 
ytrain_pos_OVS

11664.0

Co równa się liczbie pierwotnej ilości zmiennych 1 (w sumie: 54) pomnożonych przez 216.

Teraz to samo musimy zrobić ze wszystkimi rekordami zmiennych niezależnych X, które w wyniku miały wartość: y = 1.

Xtrain.loc[ytrain==1, :]

Zmienne te muszą być również zwielokrotnione 216 razy.

Xtrain_pos_OVS = pd.concat([Xtrain.loc[ytrain==1, :]] * OVS_gauge, axis = 0)

Sprawdzamy czy liczba wierszy dla zmiennych zależnych i niezależnych w zbiorze treningowym jest sobie równa.

Xtrain_pos_OVS.v1.count()

11664.0

Teraz wprowadzamy nowe, dodatkowe zmienne 1 do zbioru testowego.

ytrain_OVS = pd.concat([ytrain, ytrain_pos_OVS], axis = 0).reset_index(drop = True)
Xtrain_OVS = pd.concat([Xtrain, Xtrain_pos_OVS], axis = 0).reset_index(drop = True)

W pierwotnym zbiorze testowym mieliśmy: 11711 rekordów

ytrain.count()

Po przeprowadzeniu oversampling mamy: 23375 rekordów

ytrain_OVS.count()

Znakomicie, teraz podstawiamy nowy zbiór testowy oversampling do siatki grid według tej same formuły, którą użyliśmy wcześniej.

Parametry2 = {'C': np.power(10.0, np.arange(-3, 3))}
OVS_reg = LogisticRegression(warm_start = True)
OVS_grid = GridSearchCV(OVS_reg, param_grid = Parametry2, scoring = 'roc_auc', n_jobs = 5)

OVS_grid.fit(Xtrain_OVS, ytrain_OVS)

Teraz użyjemy bloku diagnostycznego do oceny modelu.

print("Recall Training data:     ", np.round(recall_score(ytrain_OVS, OVS_grid.predict(Xtrain_OVS)), decimals=4))
print("Precision Training data:  ", np.round(precision_score(ytrain_OVS, OVS_grid.predict(Xtrain_OVS)), decimals=4))

print("----------------------------------------------------------------------")
print("Recall Test data:         ", np.round(recall_score(ytest, OVS_grid.predict(Xtest)), decimals=4)) 
print("Precision Test data:      ", np.round(precision_score(ytest, OVS_grid.predict(Xtest)), decimals=4))
print("----------------------------------------------------------------------")
print("Confusion Matrix Test data")
print(confusion_matrix(ytest, OVS_grid.predict(Xtest)))


print("----------------------------------------------------------------------")
print(classification_report(ytest, OVS_grid.predict(Xtest)))

y_pred_proba = OVS_grid.predict_proba(Xtest)[::,1]
fpr, tpr, _ = metrics.roc_curve(ytest,  y_pred_proba)
auc = metrics.roc_auc_score(ytest, y_pred_proba)
plt.plot(fpr, tpr, label='Logistic Regression (auc = %0.2f)' % auc)
plt.xlabel('False Positive Rate',color='grey', fontsize = 13)
plt.ylabel('True Positive Rate',color='grey', fontsize = 13)
plt.title('Receiver operating characteristic')
plt.legend(loc="lower right")
plt.legend(loc=4)
plt.plot([0, 1], [0, 1],'r--')
plt.show()

 

Po przeprowadzeniu oversampling wielkość recall dla parametru testowego 1 zwiększyła się z 0.65 do poziomu 0.88. Stało się to kosztem precission które spadło dla zmiennej testowej 1 z poziomu 0.77 do poziomu 0.32.

Next part:

Model Regresji Logistycznej. Część 3: zmiana progu w modelu regresji logistycznej