Exercise 25
Istnieją dwa sposoby budowania modelu na zmiennych dyskretnych.
PYTANIE: czy model zbudowany na różnych metodach kodowania może mieć różne właściwości predykcyjne?
15 kwietnia 1912 r. Podczas swojej dziewiczej podróży Titanic zatonął po zderzeniu z górą lodową, Zginęło 1502 spośród 2224 pasażerów i załogi. Ta sensacyjna tragedia zszokowała społeczność międzynarodową i doprowadziła do lepszych przepisów bezpieczeństwa dla statków.
Jednym z powodów tragedii, był brak wystarczającej liczby łodzi ratunkowych. Zaobserwowano, że niektóre grupy ludzi miały większe szanse na przetrwanie niż inne. Były to kobiety, dzieci oraz klasa pierwsza.
Celem ćwiczenia jest określenia, jakie grupy pasażerów miały większe szanse przeżycia katastrofy.
Zmienne:
Survived: (0 = No, 1 = Yes) Zmienna wynikowa określająca przeżycie
pclass: (1 = 1st, 2 = 2nd, 3 = 3rd) Klasa biletu
Sex: (male, female) płeć pasażera
Age: wiek pasażera w latach
Wiek jest ułamkowy, jeśli jest mniejszy niż 1. Jeżeli wiek jest szacowany, to czy ma on postać xx.5
SibSp: Liczba rodzeństwa / małżonków na pokładzie Titanica
Zestaw danych definiuje relacje rodzinne w ten sposób… Rodzeństwo = brat, siostra, przyrodni brat, przyrodnia siostra Współmałżonek = mąż, żona (kochanki i narzeczone zostały zignorowane)</b>.
Parch: liczba rodziców / dzieci na pokładzie Titanica
Zestaw danych definiuje relacje rodzinne w ten sposób… Rodzic = matka, ojciec Dziecko = córka, syn, pasierbica, pasierb Niektóre dzieci podróżowały tylko z nianią, dlatego dla nich parch = 0.
Ticket: numer biletu
Fare: opłata za bilet
Cabin: Numer kabiny
Embarked: (C = Cherbourg, Q = Queenstown, S = Southampton) Kod portu zaokrętowania.
Zobacz też:
http://sigmaquality.pl/pandas/who-had-a-chance-to-survive-on-the-titanic/
import pandas as pd
import seaborn as sns
import matplotlib as plt
import numpy as np
df = pd.read_csv('c:/1/kaggletrain.csv')
df.head(5)
Sprawdzamy kompletnoiść danych
df.isnull().sum()
df.shape
Naszym zadaniem jest porównanie dwóch metod tworzenia modeli regresji logistycznej. Kasujemy kolumnę 'Cabin’ ponieważ w około 3/4 rekordów jest niekompletna poza tym ma zbyt wiele wartości unikalnych.
df.Cabin.unique()
del df['Cabin']
del df['Ticket']
del df['Unnamed: 0']
del df['PassengerId']
Usunąłem kolumnę Cabin, również usunąłem kolumnę 'Ticket’, uważam że numer biletu nie miał wpływu na przeżywalnośc rejsu.
Teraz usunę rekordy gdzie brakuje wartości w kolumnach 'Embarked’ oraz 'Age’.
df = df.dropna(how='any')
Sprawdzenie wyniku
df.shape
df.isnull().sum()
Niekompletne rekordy zostały usunięte. Badam pozostałe zmienne niezależne.
df.Embarked.value_counts(normalize=True)
df.Sex.value_counts(normalize=True)
Dość enigmatyczna jest zmienna SibSp, sprawdźmy ją!
df.SibSp.value_counts()
df.SibSp.value_counts(normalize=True).plot(kind='bar')
Tak ja widzimy, 469 pasażerów podróżowała samodzielnie a 183 z jednym członkiem rodziny. Przetwarzam liczby na oznaczenia tekstowe, które łatwiej zrozumieć.
fam = {0:'lone', 1:'couple', 2:'three members', 3:'four members', 4:'five members', 5:'six members'}
df['SibSp'] = df['SibSp'].map(fam)
Parch – Zestaw danych definiuje relacje rodzinne¶
df.Parch.value_counts()
Ta zmienna jest zbyt trudna do interpretacji, dlatego przetworzę ją na wartość dyskretną.
df.Parch.dtype
family = {0:'lone', 1:'mother', 2:'father', 3:'daughter', 4:'son', 5:'stepdaughter', 6:'stepson'}
df['Parch'] = df['Parch'].map(family)
Podmieniliśmy trudne oznaczenie rozin na oznaczenia bardziej przyjazne, sprawdźmy czy dobrze.
df['Parch'].head(5)
df[df.Parch=='daughter'][['Parch','Age', 'Sex', 'Name', 'SibSp']]
Jedena cureczka jest chłopcem. Pani Baclini jest córką innego pasażera, mimo to jest oznaczona jako podrużyująca samotnie. W bazie widać błędy.
df[df.Parch=='son'][['Parch','Age', 'Sex', 'Name', 'SibSp']]
Dwa błędy.
df[df.Parch=='mother'][['Parch','Age', 'Sex', 'Name', 'SibSp']].sample(5)
df[df.Parch=='father'][['Parch','Age', 'Sex', 'Name', 'SibSp']].sample(5)
Niektóre matki mają 9 lat inne 2. Część matek jest mężczyznami. Parametr 'SibSp’ podający ilość towarzyszących członków rodziny dla niektórych rodziców wynosi zero . Wydaje mi się, że to oznaczenie jest błędne. Teraz nie będę tego poprawiał ponieważ nie mieści się to w ramach tego ćwiczenia. Zostawimy dane takimi jakie są.
Analiza zbilansowania zbioru zmiennych wynikowych
Nie będę już badał zmiennych, sprawdzę tylko czy zmienna zależna jest zbilansowana. Czy liczba uratowanych i ofiar jest podobna.
df.Survived.value_counts(normalize=True).plot(kind='bar')
Między zbiorami uratowanych i ofiar nie ma drastycznych różnic. Nie trzeba stosować oversampling.
Regresja logistyczna bez tworzenia Dummy Variables
Przy budowaniu każdego modelu trzeba brać pod uwagę wszystkie możliwe dane, również (a czasem przede wszystkim) dane tekstowe (dyskretne). Aby możliwe było użycie danych tekstowych, należy je przekształcić na dane cyfrowe.
Dummy Variables to dane kategoryczne 0, 1, Z jednej kolumny tekstowej np. zwierzęta domowe, zawierającej np. trzy stany: pies, kot, mysz tworzy się trzy kolumny: zwierzęta domowe_kot, zwierzęta domowe_pies, zwierzęta domowe_mysz. Jeżeli w danym rekordzie jest kot, wartość w kolumnie zwierzęta domowe_kot = 1, w pozostałych kolumnach wartość ta wynosi 0.
Zamiast tworzyć Dummy Variables można styworzyć cyfrowy kod zmiennych tekstowych. Poniżej zrobimy takie przekształcenie dla zmiennych tekstowych.
Dzielimy zmienne niezależne na tekstowe i numeryczne
df.dtypes
del df['Name']
categorical = df.describe(include=["object"]).columns
continuous = df.describe().columns
categorical
continuous
Przekształacamy zmienne dyskretne na zmienne kodowane cyfrowo
Ktoś może zapytać, po co najpierw tworzymy z danych cyfrowych 'SibSp’ i 'Parch’, zmienne tekstowe aby znowu przekształcić je w dane cyfrowe.
Robimy tak aby poprawić czytelność kolumn w metodzie Dummy Variables.
from sklearn.preprocessing import LabelEncoder
df[categorical] = df[categorical].apply(LabelEncoder().fit_transform)
df[categorical].sample(6)
Dzielimy zbiory na testowe i treningowe
y = df['Survived']
X = df.drop('Survived' , axis=1)
from sklearn.model_selection import train_test_split
Xtrain, Xtest, ytrain, ytest = train_test_split(X,y, test_size=0.33, stratify = y, random_state = 148)
Wielkości zbiorów.
print ('Training X set: ',Xtrain.shape)
print ('Test X set ', Xtest.shape)
print ('Training y set: ', ytrain.shape)
print ('Test y set ', ytest.shape)
Xtrain.head(4)
Logistic Regression bez Dummy Variables
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
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)
LR_Grid.fit(Xtrain, ytrain)
Ocena modelu regresji logistycznej bez Dummy Variables
ypred = LR_Grid.predict(Xtest)
from sklearn.metrics import classification_report, confusion_matrix
from sklearn import metrics
co_matrix = metrics.confusion_matrix(ytest, ypred)
co_matrix
print(classification_report(ytest, ypred))
print("Accuracy: ",np.round(metrics.accuracy_score(ytest, ypred), decimals=2))
print("Precision: ",np.round(metrics.precision_score(ytest, ypred), decimals=2))
print("Recall: ",np.round(metrics.recall_score(ytest, ypred), decimals=2))
print("F1 score: ",np.round(metrics.f1_score(ytest, ypred), decimals=2))
Usunięcie danych 'Name’, 'Cabin’,’Ticket’,’Unnamed: 0′, 'PassengerId’ poprawiło nieznacznie dobroć modelu.
Logistic Regression z Dummy Variables
Przywracamy kolumny zawierające zmienne tekstowe. Robimy tak żeby mieć identyczne dane jak przy Logistic Regression bez dummy variables.
df.columns
df2 = pd.read_csv('c:/1/kaggletrain.csv', usecols=['Survived','Pclass','Sex','Age','SibSp','Parch','Fare','Embarked'])
df2 = df2.dropna(how='any')
df2.isnull().sum()
fam = {0:'lone', 1:'couple', 2:'three members', 3:'four members', 4:'five members', 5:'six members'}
df2['SibSp'] = df2['SibSp'].map(fam)
family = {0:'lone', 1:'mother', 2:'father', 3:'daughter', 4:'son', 5:'stepdaughter', 6:'stepson'}
df2['Parch'] = df2['Parch'].map(family)
Teraz tworzymy zmienne typu Dummy Variables
Dummy_Variables = pd.get_dummies(df2, columns=categorical, drop_first=True)
Dummy_Variables.sample(5)
Dummy_Variables.columns
y = Dummy_Variables['Survived']
X = Dummy_Variables.drop('Survived', axis=1)
from sklearn.model_selection import train_test_split
Xtrain, Xtest, ytrain, ytest = train_test_split(X,y, test_size=0.33, stratify = y, random_state = 148)
Parameteres = {'C': np.power(10.0, np.arange(-3, 3))}
LR = LogisticRegression(warm_start = True)
LR_Dummy_Variables = GridSearchCV(LR, param_grid = Parameteres, scoring = 'roc_auc', n_jobs = 5, cv=2)
LR_Dummy_Variables.fit(Xtrain, ytrain)
Ocena modelu regresji logistycznej
ypred_DV = LR_Dummy_Variables.predict(Xtest)
co_matrix = metrics.confusion_matrix(ytest, ypred_DV)
co_matrix
print(classification_report(ytest, ypred_DV))
print("Accuracy: ",np.round(metrics.accuracy_score(ytest, ypred_DV), decimals=2))
print("Precision: ",np.round(metrics.precision_score(ytest, ypred_DV), decimals=2))
print("Recall: ",np.round(metrics.recall_score(ytest, ypred_DV), decimals=2))
print("F1 score: ",np.round(metrics.f1_score(ytest, ypred_DV), decimals=2))
Odpowiedź: Model regresji logistycznej wykorzystujący zmienne takstowe zakodowane oraz Model regresji logistycznej wykorzystujący zmienne typu Dummy_Variables mają te same zdolności predykcyjne.

