Pierwszy projekt machine learningowy

braintelligence.pl 6 lat temu

Hello World w świecie uczenia maszynowego

Co tutaj zrobimy?

Hello World w świecie uczenia maszynowego – 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żeli 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 w 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żeli 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ż, iż 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 ) # w tej chwili 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, iż 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, iż 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, iż 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ć, iż model zaczął się przetrenowywać.

Co jeszcze możesz zrobić?

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

Feature Importance – jako iż 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.

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

Idź do oryginalnego materiału