blog programisty - machine learning

Pierwszy projekt machine learningowy

Hello World w świecie Machine Learningu

Co tutaj zrobimy?

Hello World w świecie Machine Learningu – Titanic
  • Mamy gotowca (kaggle). Co potrzeba? Co chcemy osiągnąć? Oraz dane, dane i jeszcze raz dane… !
  • Do zrobienia. Przegląd, analiza oraz wyczyszczenie/uzupełnienie danych. Co tam siedzi w środku? Co mamy?
  • Do zrobienia. Analiza. Wybór istniejących cech. Znalezienie powiązań, wzorców. Stworzenie nowych cech.
  • Do zrobienia. Tworzenie modelu i przewidywanie wartości. Do tego czy model nie jest za bardzo skupiony w jednym punkcie (bias)? Jak daleko punkty oddalone są od wartości średniej (variance problem).
  • Do zrobienia. Przetestowanie naszego modelu.
Co potrzeba, żeby odpalić to u siebie? 
  • Instalujesz Anaconda. Odpalasz Jupyter Notebook. Instalujesz biblioteki jakich nie masz. Można to zrobić na wiele sposobów. Jeden z nich to ustawić zmienną bezpośrednio w Anaconda, albo zrobić to w notebooku przy pomocy !pip install pandas.

Jeśli potrzebujesz większej pomocy napisz w komentarzu na dole lub na grupie facebookowej.

 

1. Titanic – tutaj możesz pobrać dane (kaggle) »

Sposobów na zrobienie tego zadania jest wiele, nieskończenie wiele. Więcej niż gwiazd we wszechświecie. No dobra… Przesadzam. Niemniej jest to tylko jedno z podejść jakich jest wiele. Problem jest trywialny, także nie ma co wydziwiać. Ale… już na tak prostym przykładzie uda nam się zobaczyć jak korzystać z enigmatycznego Machine-Learningu.

Cel: Czy pasażer titanica przeżyje?
Przewidujemy 1: { przeżyje } lub 0: { nie przeżyje }. Klasyfikacja binarna.
Metryka: Ile procent przeżyło?
Prosta metryka zwana Accuracyobliczająca procent prawidłowo przewidzianych wartości.
Przewidziane odpowiedzi: Wrzucamy CSV’kę w poniższym formacie na kaggle:

PassagerId, Survived
112       , 0
...       , ...
213       , 1

A tutaj kompletny i uporządkowany Notebook na Githubie.

Jeśli masz jakieś spostrzeżenia co do kodu/wpisu podziel się tym w komentarzu. Chętnie nauczę się czegoś nowego.

 

1.1. Importy

Na początku skup się na zrozumieniu konceptu oraz po co robimy kolejne kroki. Zrozumienie kodu przyjdzie z czasem. Jeśli znasz już Pythona to masz dobry head-start.

# data analysis and wrangling
import pandas as pd
import numpy as np
# machine learning stuff
from sklearn.dummy import DummyClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
import xgboost as xgb
from collections import defaultdict
from sklearn.model_selection import cross_val_score 
# visualization
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline

 

1.2. Co siedzi w danych?

# Wczytujemy dane do trenowania modelu
$ train = pd.read_csv('train.csv')
    
# Dane do testowania modelu 
$ test = pd.read_csv('test.csv')
  
$ train.shape # (891, 12) ( wiersz, kolumna ) 
$ test.shape  # (418, 11) ( wiersz, kolumna ) brakuje kolumny Survived, bo to będziemy przewidywać
# Połączmy dane, żeby zobaczyć, czy czegoś nie brakuje
# TIP: W zbiorze testowym brakuje tylko jednego Fare
df_all = pd.concat([df_train, df_test])

$df_all.info()

Int64Index: 1309 entries, 0 to 417
Data columns (total 12 columns):
Age            1046 non-null float64      <---- Cechy ( Features ) - tutaj brakuje danych
Cabin          295 non-null object        <---- Cechy ( Features ) - oraz tutaj
Embarked       1307 non-null object       ...
Fare           1308 non-null float64      <---- Cechy ( Features )- a tutaj brakuje tylko jednego wiersza 
Name           1309 non-null object       <---- Cechy ( Features )
Parch          1309 non-null int64        <---- Cechy ( Features )
PassengerId    1309 non-null int64        <--- ID
Pclass         1309 non-null int64        <---- Cechy ( Features )
Sex            1309 non-null object       ...
SibSp          1309 non-null int64        ...
Survived       891 non-null float64       <--- Odpowiedź ( Target Variable )
Ticket         1309 non-null object       <---- Cechy ( Features )
dtypes: float64(3), int64(4), object(5)
memory usage: 132.9+ KB

Przeważająca większość ocalonych to były kobiety w klasie 1 oraz 2. Do tego mężczyźni mieli większe szanse w 1 klasie. Moglibyśmy poświęcić więcej czasu na analizę danych, ale skupmy się bardziej na budowaniu nowych cech i trenowaniu naszych modeli. W notebooku wrzucę więcej wykresów (obiecuję). Więcej frajdy sprawia mi tworzenie nowych cech i próby podrasowania modelu, także przejdźmy odrazu do tego : )

1.3. Pierwszy prosty model

###########
## TRAIN ##
###########

# Wybieramy cechy jakie chcemy wykorzystać
feats = [ 'Pclass', 'SibSp', 'Parch' ]

# Tworzymy X-macierz oraz y-wektor
X = df_train[ feats ].values
y = df_train['Survived'].values

# Wybieramy model jaki chcemy wykorzystać
model = ExtraTreesClassifier(n_estimators=100, max_depth=4) # jakiekolwiek parametry na początek

# Trenujemy model
model.fit(X, y)

# Tworzymy odpowiedzi ( wektor )
y_pred = model.predict(X) 

# Używamy metryki do sprawdzenia wytrenowanego modelu
score = accuracy_score(y, y_pred) # Daje nam to 71% przewidywalności
###########
## TEST  ##
###########

# Wybieramy cechy jakie chcemy wykorzystać, czyli to samo co w train
X = df_test[ feats ].values

# Przewidujemy, czy przeżył
predictions = df_test['Survived'] = model.predict(X)

PassengerId = df_test['PassengerId']

# Łączymy przewidziane wartości do CSV'ki po czym wrzucamy to na Kaggle
submission = pd.DataFrame({ 'PassengerId': PassengerId, 'Survived': predictions })
submission.to_csv("../output/titanic/extra_tree_1_feature.csv", index=False)

# Daje to nam lokalnie 71%, a po wrzuceniu na Kaggle 68% przewidywalności


## Do tego w Pythonie tak widzimy Macierze oraz Wektory
- [1, 2, 3, 4, 5]             # to jest wektor
- [[1], [2], [3], [4], [5]]   # to jest wektor wektorów, czyli macierz (posiada jedną cechę)
- [[1, 10], [2, 20], [3, 30]] # to jest wektor wektorów, czyli macierz (posiada dwie cechy)

1.4. Feature Engeneering ( pierwsza najprostsza cecha )

$ train['Name']# Przykład: Harris, Mrs. Henry Birkhardt (Irene Wallach) 

df['name_length'] = df['Name'].apply(len)

Zapewne długość imienia nie ma znaczenia jeśli chodzi o potencjalne przeżycie katastrofy, ale od czegoś trzeba zacząć.

 

1.5. Feature Engeneering ( kolejna cecha )

$ train['Name']# Przykład: Harris, Mrs. Henry Birkhardt (Irene Wallach) 

# WAŻNE: Zauważ, że po imieniu jest przecinek!

# Tworzymy nową cechę na podstawie 'Name'
train['title'] = train['Name'].map(lambda x: x.split(',')[1].split('.')[0].strip())

# Wrzucamy 'dziwne' nazwy do jednego worka ( czyli te co występują stosunkowo rzadko )
rare_titles =
['Mlle','the Countess','Mme', 'Ms', 'Lady', 'Countess', 'Capt',
 'Col','Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona']

train['title'].values[train['title'].isin( rare_titles )] = 'Rare'

$ train['title'].value_counts()
# Mr 517
# Miss 182
# Mrs 125 
# Master 40 
# Rare 27 


### Dobra... Mamy Stringi. Teraz trzeba to skategoryzować.
## (czyli zamienić na wartości liczbowe, bo tylko takie przyjmuje nasz model )
# Obecnie mamy Mr, Miss, Mrs... 
# A chcemy 0, 1, 2, 3...
$ train['title_cat'] = train['title'].factorize()[0]

 

1.6. Uzupełnianie brakujących danych

# Sprawdźmy czy nie brakuje wartości 
df_train['Age'].isnull().any() 
# True  <-- wygląda na to, że TAK 

# Napiszmy pomocniczą funkcję do uzupełnienia brakujących danych
def fill_missing_age(df):
    for i in range(1,4):
        median_age=df[df["title_cat"]==i]["Age"].median()
        df["Age"]=df["Age"].fillna(median_age)
        return df

df_train = fill_missing_age(df)

Wszelkie kolejne cechy (FamilySize, Fare, Age, Cabin…) znajdziesz w Notebooku jaki przygotowałem.

 

1.7. Kilka słów o Cross-Validation

Nazwa wydaje się mądra, ale po co nam to? Często testujemy nasz model na tych samych danych, na jakich go trenowaliśmy. Stwarza to wiele problemów. Jeden z nich to overfitting, drugi to bias. Dość łatwo jest przeuczyć model do tego poziomu, że radzi sobie tylko na danych treningowych. Albo jest skupiony za bardzo na jednym punkcie. Zamiast wykrywać kota, albo psa wykrywa tylko i wyłącznie koty (bias). Tutaj bardziej naukowa publikacja na ten temat. Może ktoś będzie miał większy zapał do przeczytania tego niż ja. : )

Dobra to wiemy, że budując oraz testując na tych samych danych łatwo o overfitting. Na szczęście jest kilka sposobów, żeby z tym walczyć. Jednym z nich jest podzielenie zbioru na kawałki (k-fold). Można użyć cross_val_score domyślnie używamy Stratified k-fold. Co to daje? Pozwala stworzyć bardziej zbalansowane paczki, aniżeli w przypadku zwykłego fold’a. Mamy wtedy kilka oddzielnych doświadczeń z jakich jest zbierana średnia. Ale… Im mniej cv=k tym może być większy bias naszego modelu. Im większy cv=k tym większa zmienność naszego modelu. A to może prowadzić do overfittingu. Oczywiście to wszystko to upraszczanie dużo bardziej skomplikowanych problemów, ale zostawmy to na razie jak jest. : )

Inny przykład overfittingu na bardziej ‚realnym’ przykładzie. Czerwona linia to zbiór treningowy, a zielona to zbiór testowy. Jak widać ten pierwszy dał lepszy wynik, aniżeli w rzeczywistości był. Zatem można założyć, że model zaczął się przetrenowywać.

 

 

Co jeszcze możesz zrobić?

Feature Engineering – możesz dodać/wymyślić dodatkowe cechy.

Feature Importance – jako że mamy estymatory oparte o drzewa możemy dzięki temu stworzyć wykres pokazujący jakie cechy miały największy wpływ na model. A to z kolei pozwoli nam wybrać tylko najlepsze cechy. Jest to czasami potrzebne, bo zbyt duża ilość cech może prowadzić do overfittingu. Spróbuj stworzyć wykres, który pokaże cechy mające największy wpływ na jakość modelu.

Hyperparameters tuning – parametry do drzew ustawialiśmy na czuja. Daliśmy po prostu losowe wartości.

model = RandomForestClassifier(max_depth=3, n_estimators=100, random_state=1)

Wyjątkiem jest random_state, który pozwala nam dostać powtarzalny wynik. Celem zadania jest znalezienie najlepszych hyperparameters dla wybranego modelu. W tym celu budujemy ten sam model kilkanaście razy z innymi parametrami i wybieramy najlepsze. Poczytaj sobie chociażby o GridSearchCV, albo RandomizedSearchCV.

 

W kolejnym wpisie: Wykorzystamy pipeline do szybkiego i wygodnego sprawdzania pomysłów » (wkrótce)

 

2. Drugi projekt to koncepcja sieci neuronowej 

Całkiem przyjemny materiał pokazujący proces myślowy do stworzenia sieci neuronowej od początku do końca. Warto obejrzeć, bo materiały są naprawdę wysokiej jakości.

 

 

 

 

A już naprawdę na koniec przykład uczenia przy pomocy Reinforcement Learning

Jest to podejście z wykorzystaniem algorytmu, który nie dostaje feedbacku natychmiastowo. Otrzymuje go dopiero w momencie, gdy osiągnie swój cel. Wygrana w grę. Przejście z punktu A, do punktu B. Jest to dobrze nam znany wzorzec prób i błędów, gdy sami uczymy się nowej umiejętności.

Zdjęcie główne by Martin Shreder on Unsplash