Przykład Modelu Regresji Logistycznej. Część 1: model podstawowy

Regresja logistyczna jest algorytmem klasyfikacji uczenia maszynowego.

Model Regresji Regresja logistyczna jest algorytmem klasyfikacji uczenia maszynowego.
Model Regresji Logistycznej służy do przewidywania stanu zmiennej zależnej. Zmienna zależna jest w regresji logistycznej zmienną binarną, która przyjmuje postać: 1 i 0. W modelu tym zmienna zależna 1 oznacza zwykle potwierdzenie natomiast 0 oznacza zaprzeczenie.
służy do przewidywania stanu zmiennej zależnej. Zmienna zależna jest w regresji logistycznej zmienną binarną, która przyjmuje postać: 1 i 0. W modelu tym zmienna zależna 1 oznacza zwykle potwierdzenie natomiast 0 oznacza zaprzeczenie.

Założenia Modelu Regresji Logistycznej

  1. Zmienna zależna musi mieć postać binarną
  2. W modelu należy uwzględnić tylko zmienne niezależne mające istotny wpływ na zmienną zależną.
  3. Zmienne niezależne muszą być od siebie niezależne (nieskorelowane).
  4. Regresja logistyczna wymaga dość dużych rozmiarów próbek.

Otwórzmy plik danych wraz z niezbędnymi bibliotekami. Będziemy pracowali nad plikiem historii operacji na kartach płatniczych. Kolumnie ‘Class’ wartości 0 oznaczają brak malwersacji, 1 oznacza dokonanie malwersacji.

Przyjmijmy założenie, że celem podstawowym jest właściwe zaklasyfikowanie jak największej liczby malwersacji. Może odbywać się to kosztem wskazywania  sporej liczby zwykłych transakcji jako malwersacji.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

from sklearn.preprocessing import StandardScaler, Normalizer, scale
from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier, GradientBoostingClassifier, ExtraTreesClassifier
from sklearn.svm import SVC, LinearSVC
from sklearn.metrics import confusion_matrix, log_loss, auc, roc_curve, roc_auc_score, recall_score, precision_recall_curve
from sklearn.metrics import make_scorer, precision_score, fbeta_score, f1_score, classification_report
from sklearn.model_selection import cross_val_score, train_test_split, KFold, StratifiedShuffleSplit, GridSearchCV
from sklearn.linear_model import LogisticRegression

from sklearn import metrics
from sklearn.metrics import classification_report, confusion_matrix

df = pd.read_csv('c:/1/creditcard.csv')
df.head(3)

df.columns

Analiza zbilansowania zmiennych zależnych

Zbiór zmiennych zależnych jest zbilansowany wtedy, gdy stany 1 i 0 ma podobną liczbę wystąpień. Zazwyczaj zmienne wynikowe nie są zbilansowane, ponieważ zwykle bada się jakieś rzadkie zjawisko reprezentowane przez zmienną wynikową 1 na tle ogromnej liczby 0.

Gdy zbiór zmiennych wynikowych jest niezbilansowany, wtedy możemy mieć do czynienia ze zjawiskiem, kiedy model będzie ignorował wystąpienia 1 a i tak zachowa bardzo wysoki wskaźnik kompletności wyników (recall).

Przy drastycznej asymetrii występowania 0 i 1, nawet jeżeli model regresji logistycznej zignoruje wszystkie wystąpienia 1 i tak zachowa recall na bardzo wysokim poziomie.

 

Sprawdzenie poziomu zbilansowania wartości wynikowych

df.Class.value_counts(dropna = False)

sns.countplot(x='Class',data=df, palette='GnBu_d')
plt.show()

Wykres nie jest zbyt czytelny, warto więc sprawdzić strukturę procentową zmiennych wynikowych.

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

Widzimy, że skala malwersacji reprezentowana przez 1 w kolumnie ‘Class’ stanowi niespełna 0,46% .

Zbiór jest więc głęboko niezbilansowany.

Analiza zmiennych niezależnych Modelu Regresji Logistycznej

Według wymienionych wcześniej założeń do Modelu Regresji Logistycznej

  • W modelu należy uwzględnić tylko zmienne niezależne mające istotny wpływ na zmienną zależną.
  • Zmienne niezależne muszą być od siebie niezależne (nieskorelowane).

 

W pierwszej kolejności zbadamy jaki wpływ na zmienna zależną mają poszczególne zmienne niezależne.

CORREL = df.corr().sort_values('Class')
CORREL['Class']

Wektor korelacji pomiędzy zmienną zależną a poszczególnymi zmiennymi niezależnymi wykazał, że niektóre zmienne mają bardzo niskie, graniczące z zerem poziomy korelacji.

Analiza statystyczna zmiennych niezależnych

Teraz wyświetlimy statystyki kilku zmiennych w próbie. Zmienne typu V mają bardzo podobne charakterystyki więc nie wyświetliłem tylko kilka z pośród nich.

Wyraźnie widać, że zmienne typu V znacznie różnią się od zmiennych niezależnych ‘Time’ i ‘Amount’.

Sprawdźmy jaki wpływ na zmienną zależną maja obie te zmienne.

df.groupby('Class').Amount.mean()

Widać, że istnieje istotna różnica w stanie średnich pomiędzy zmienną wynikową 1 i 0.

Dzieje się tak mimo wyraźnego braku korelacji między zmianną ‘Amount’ i zmienną zależną ‘Class’.

pd.pivot_table(df, index='Class', values = 'Amount', aggfunc= [np.mean, np.median, min, max, np.std])

pd.pivot_table(df, index='Class', values = 'Time', aggfunc= [np.mean, np.median, min, max, np.std])

Zmienna ‘Time’ wykazuje małe różnice pomiędzy 0 a 1, nie wykazuje też korelacji ze zmienną zależną, dlatego nie bierzemy jej pod uwagę w budowaniu modelu.

Zmienną ‘Amount’ należy użyć przy tworzeniu Modelu Regresji Logistycznej pomimo braku korelacji ze zmienną zależną.

Aby użyć zmienną niezależną ‘Amount’ należy ją najpierw zestandaryzować.

scaler = StandardScaler()
df['Amount'] = scaler.fit_transform(df['Amount'].values.reshape(-1, 1))

Analiza korelacji zmiennych

Korelacja zmiennych wynikowych nie jest dobrym zjawiskiem przy budowie Modelu Regresji Logistycznej.

sns.heatmap (df.corr (), cmap="coolwarm")

Brak jakiejkolwiek wysokiej korelacji pomiędzy zmiennymi niezależnymi. Na wykresie widać poszczególne wysokie korelacje zmiennych niezależnych ze zmienną zależną.

Wszystko jest OK.

Przed rozpoczęciem tworzenia modelu usuwamy wszystkie rekordy z pustymi komórkami.

Tworzenie Modelu Regresji Logistycznej

Wskazuje na zmienne egzogeniczne i na kolumnę wynikową zmienną endogeniczną.

feature_cols = ['V1', 'V2', 'V4', 'V5', 'V6', 'V8', 'V9', 'V10', 'V11', 'V12', 'V13', 'V14', 'V15', 'V16', 'V17', 'V18', 'V19', 'V20',
       'V21', 'V22', 'V23', 'V24', 'V25', 'V26', 'V27', 'V28', 'Amount']
X = df[feature_cols] 
y = df.Class

Wskazuje na podział na zbiór treningowy i zbiór testowy.

Xtrain, Xtest, ytrain, ytest = train_test_split(X, y, test_size = .33, stratify = y, random_state = 148)

Tworzymy ustawianie siatki Grid.

Parameteres = {'C': np.power(10.0, np.arange(-3, 3))}
LR = LogisticRegression(warm_start = True)
LR_Grid = GridSearchCV(LR, param_grid = Parameteres, scoring = 'roc_auc', n_jobs = 5, cv=2)

Wyjaśnienia do kodu:

 Parameteres = {'C': np.power(10.0, np.arange(-3, 3))} 

array([1.e-03, 1.e-02, 1.e-01, 1.e+00, 1.e+01, 1.e+02])

Czyli typowe ustawienia dla siatki.

 warm_start  – algorytm wykorzystuje poprzednie wyniki modelu. Gdy warm_start =True, istniejące atrybuty dopasowanego modelu są używane do inicjalizacji nowego modelu w kolejnym wezwaniu do dopasowania w celu przyspieszyć konwergencji. warm_start jest przydatny przy wielokrotnym dopasowaniu tego samego estymatora z tymi samymi danymi, ale przy różnych parametrach.

 

 scoring = 'roc_auc' 

Wykres ROC ocenia najlepsze ustawienie klasyfikacji. Wyszukuje obszar pod „zakrzywioną” krzywą ROC, która jest prawdopodobnie najlepszym sposobem do pomiaru wydajności klasyfikacji w ramach wyszukiwania siatki.

 jobs = 5 

Liczba zadań do uruchomienia równoległego.

 cv = 2 

Oznacza ilość weryfikacji krzyżowych.

 

Model przyjmuje postać równania:

LR_Grid.fit(Xtrain, ytrain)

Sprawdzam, jaką konfigurację superparametru wygrał Grid.

print("The Best parameter:",LR_Grid.best_params_)
print("The Best estimator:",LR_Grid.best_estimator_)

Ewaluacja Modelu Regresji Logistycznej

Proszę wprowadzić do kodu blok diagnostyczny.

print("\n------Training data---------------------------------------------------")
print("The RECALL Training data:      ", np.round(recall_score(ytrain, LR_Grid.predict(Xtrain)), decimals=3))
print("The PRECISION Training data:   ", np.round(precision_score(ytrain, LR_Grid.predict(Xtrain)), decimals=3))
print()
print("------Test data-------------------------------------------------------")

print("The RECALL Test data is:        ", np.round(recall_score(ytest, LR_Grid.predict(Xtest)), decimals=3))
print("The PRECISION Test data is:     ", np.round(precision_score(ytest, LR_Grid.predict(Xtest)), decimals=3))
print()
print("The Confusion Matrix Test data :--------------------------------------")
print(confusion_matrix(ytest, LR_Grid.predict(Xtest)))
print("----------------------------------------------------------------------")
print(classification_report(ytest, LR_Grid.predict(Xtest)))

# PLOT
y_pred_proba = LR_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.axvline(0.5, color = '#00C851', linestyle = '--')
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()

Model Regresji Logistycznej dobrze estymuje zdarzenia oznaczone jaki 0, gorzej ze zdarzeniami 1 (malwersacje). Poziom recall dla malwersacji wynosi zaledwie 65%. Precision było na poziomie 77%.

Pamiętajmy, że model został stworzony głębokim niezbilansowaniu zbioru zmiennej zależnej.

Wykorzystaliśmy równie z wszystkie zmienne mimo że część z nich nie wykazywała korelacji ze zmienną zależną.

Aby wyświetlić same zmienne o wysokim poziomie (powyżej 0.2) korelacji ze zmienną zależną ‘Class’trzeba wpisać:

kot = CORREL[(CORREL['Class']>0.2)|(CORREL['Class']<-0.2)][['Class']]
kot.index

Teraz podstawimy wyłącznie te zmienne do modelu.

Wynik okazuje się rozczarowujące, model pogorszył swoje właściwości. Wracam więc od wcześniejszych ustawień modelu.

 

W kolejnych odcinkach będę starał się polepszyć model aby efektywnie wyłapywał wszystkie malwersacje

Kolejne kroki w tym procesie to :

  1. Oversampling
  2. Zmiany granic prawdopodobieństwa
  3. Zabiegi na wagach.

Next part:

Model Regresji Logistycznej. Część 2: Oversampling