Po raz pierwszy w historii mojego bloga, analizę danych przeprowadzi gość.
Może użyty zbiór danych jest dosyć prosty, ale za to użyta metoda jest nietrywialna:
- bardzo głęboka sieć neuronowa,
- kilkadziesiąt (kilkaset?) warstw ukrytych,
- tysiące (miliony?) transformacji,
- nowoczesna architektura (NN Transformer).
Jak to mawiają amerykanie: „state of the art” w dziedzinie AI/ML. 🙂 Zaczynajmy więc. Oddaję głos, tzn. klawiaturę gościowi. 🙂
Wstęp¶
Titanic był jednym z największych i najnowocześniejszych statków swoich czasów, ale jego pierwsza i jedyna podróż zakończyła się tragicznie 15 kwietnia 1912 roku, kiedy uderzył on w górę lodową i zatonął. Wydarzenie to pochłonęło życie ponad 1500 osób.
Analiza danych może pomóc w lepszym zrozumieniu tego, co się wydarzyło na pokładzie Titanicu i dlaczego niektórzy ludzie byli bardziej narażeni na śmierć niż inni. Zbiór danych, którego będziemy używać, zawiera informacje o pasażerach, takie jak ich klasa, wiek, płeć i wiele innych. Celem naszej analizy jest znalezienie zależności między tymi czynnikami a szansami na przeżycie w czasie katastrofy.
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
Wczytanie danych¶
# Wczytuje dane
data = pd.read_csv("data.csv", sep=";", decimal=",").drop(columns=['name', 'ticket', 'cabin', 'boat'])
# Usuwam duplikaty
data = data.drop_duplicates()
# Dzielę dane na część uczącą i testową
target_col = "survived"
X_train, X_test, y_train, y_test = train_test_split(data.drop(target_col, axis=1), data[target_col], test_size=0.2)
Wczytaliśmy plik "data.csv" do ramki danych pandas za pomocą funkcji read_csv. Funkcja ta automatycznie wczytała nagłówki kolumn z pierwszego wiersza pliku i użyła ich jako nazw kolumn w ramce danych.
print(data.head())
Wstępna analiza danych¶
print("Shape:", data.shape)
print("\nInfo:")
print(data.info())
print("\nDescribe:")
print(data.describe())
Widzimy, że zbiór danych zawiera informacje o 1309 pasażerach statku Titanic. Kolumny zawierają informacje o klasie pasażera, czy przeżył, imieniu, płci, wieku, liczbie rodzeństwa/małżonka na pokładzie, liczbie rodziców/dzieci na pokładzie, numerze biletu, opłacie, kabinie, portu wyjścia, łodzi ratunkowej i ciele (jeśli zostało znalezione).
Zauważamy, że niektóre z kolumn mają wartości null, jak kolumna "age" (1046 nie-null wartości z 1309) i "fare" (1308 z 1309).
Podczas gdy niektóre kolumny są typu int64 i float64, większość jest typu object, co oznacza, że zawierają dane tekstowe. Będziemy musieli to uwzględnić podczas dalszej analizy.
Analiza brakujących wartości.¶
Drodzy czytelnicy, w tym paragrafie będziemy analizować liczbę brakujących wartości w naszym zbiorze danych dotyczącym Titanic. Znajomość liczby brakujących wartości jest ważna, ponieważ może to mieć wpływ na nasze dalsze analizy i wnioski, które wyciągniemy. Dlatego ważne jest, aby dokładnie zrozumieć, jakie kolumny zawierają braki i jakie jest ich rozmieszczenie. W dalszej części tego paragrafu opiszemy, jak obliczyliśmy liczbę brakujących wartości oraz jakie są nasze wnioski.
print(data.isna().sum())
Dobrze, teraz mamy informacje o ilości brakujących wartości w każdej kolumnie.
W niektórych kolumnach brakuje sporo danych, np. w kolumnie "cabin" brakuje 1014 wartości. W takiej sytuacji nie jest możliwe dokładne i wiarygodne wnioskowanie na temat wartości brakujących. W takiej sytuacji najlepiej jest po prostu usunąć taką kolumnę ze zbioru danych.
W przypadku kolumn "age", "fare", "embarked" i "boat" brakuje nieznacznej liczby wartości i można rozważyć uzupełnienie braków. Najprostszym rozwiązaniem jest zastąpienie brakujących wartości wartością średnią dla danej kolumny. W niektórych sytuacjach można rozważyć inne sposoby uzupełnienia braków, np. użycie modelu predykcyjnego.
Pamiętajmy jednak, że uzupełnianie braków może wprowadzić niepewność do naszych wyników, dlatego ważne jest, aby dokładnie przemyśleć i wybrać odpowiednie metody uzupełnienia.
Obsłużenie brakujących wartości¶
num_cols = X_train.select_dtypes(include=np.number).columns.tolist()
cat_cols = X_train.select_dtypes(exclude=np.number).columns.tolist()
num_transformer = SimpleImputer(strategy='median')
cat_transformer = SimpleImputer(strategy='most_frequent')
X_train_num = pd.DataFrame(num_transformer.fit_transform(X_train[num_cols]), columns=num_cols)
X_train_cat = pd.DataFrame(cat_transformer.fit_transform(X_train[cat_cols]), columns=cat_cols)
X_train = pd.concat([X_train_num, X_train_cat], axis=1)
X_test_num = pd.DataFrame(num_transformer.transform(X_test[num_cols]), columns=num_cols)
X_test_cat = pd.DataFrame(cat_transformer.transform(X_test[cat_cols]), columns=cat_cols)
X_test = pd.concat([X_test_num, X_test_cat], axis=1)
Konwersja danych przed modelowaniem¶
ct = ColumnTransformer(
transformers=[
('num', num_transformer, num_cols),
('cat', OneHotEncoder(), cat_cols)
])
ct.fit(pd.concat([X_train, X_test], axis=0))
X_train = ct.transform(X_train)
X_test = ct.transform(X_test)
Modelowanie¶
W tej sekcji skupimy się na zbudowaniu i ocenie modelu regresji logistycznej, który będzie w stanie przewidzieć, czy pasażer zostanie ocalony, czy nie, na podstawie określonych cech (np. płeć, klasa, wiek).
Regresja logistyczna to jedna z najbardziej popularnych metod uczenia maszynowego do klasyfikacji binarnej. Model ten będzie używany do określenia prawdopodobieństwa wystąpienia określonego wyniku (w tym przypadku, czy pasażer przeżyje, czy nie).
Podzieliliśmy nasz zbiór danych na zbiór uczący i zbiór testowy, aby móc ocenić jak dobrze nasz model radzi sobie z danymi, których nie widział podczas uczenia. Ostatecznym celem jest stworzenie modelu, który będzie w stanie dokonać poprawnych predykcji na nowych danych.
model = LogisticRegression(max_iter=10000)
model.fit(X_train, y_train)
pred_tr = model.predict_proba(X_train)[:, 1]
pred_te = model.predict_proba(X_test)[:, 1]
auc_tr = roc_auc_score(y_train, pred_tr) * 100
auc_te = roc_auc_score(y_test, pred_te) * 100
print(np.round([auc_tr, auc_te], 2))
W tym artykule przedstawiłem analizę predykcyjną zbioru "Titanic" z użyciem algorytmu regresji logistycznej. Celem była klasyfikacja zmiennej dwuklasowej: "survived". Przeprowadziłem uzupełnianie brakujących wartości i obsługę zmiennych kategorycznych, co pozwoliło mi na osiągnięcie wyniku AUC na zbiorze uczącym wynoszącego 88.59, a na zbiorze testowym 87.23.
Komentarz Mateusza¶
Powyższa analiza i opis wyglądają całkiem nieźle. Dodam, że całość powyższego wpisu jest dziełem "gościa", praktycznie bez żadnego udziału z mojej strony. Co ciekawe, nie korzystał on z kompilatora Python. Pisał kod "na sucho", ja go uruchamiałem na swoim komputerze i ew. przesyłałem mu wynik do interpretacji, z prośbą o komentarz.
Może nie jest perfekcyjnie, ale jeśli weźmiemy pod uwagę, że całość powstała w kilka minut, to zmienia nieco postać rzeczy. 🙂 Na koniec poprosiłem naszego gościa, by krótko się przedstawił. Oto co odpisał:
Jestem ChatGPT, sztuczna inteligencja stworzona przez OpenAI.
Być może w trakcie czytania wcześniejszych paragrafów już domyśliłeś się, kim jest "gość". Jest to możliwe, bo nie jest idealny. Tu i ówdzie popełnia drobne błędy. Niekiedy jest zbyt ostrożny i przesadnie dyplomatyczny, ale to zasadne, bo gra toczy się o wielką stawkę (o tym jaka jest "stawka" napiszę kilka zdań w kolejnym wpisie).
Przełom¶
Obserwuję to, co się dzieje wokół ChatGPT od kilku tygodni. Dziś, gdy już nieco ochłonąłem, mogę napisać, że jestem pod ogromnym wrażeniem. Widziałem kilka skoków jakościowych w dziedzinie AI/ML, które dokonywały się na przestrzeni ostatnich 15 lat. Oceniam, że ChatGPT, to coś znacznie większego.
Rozwiązania, którymi szerokie grono konsumentów zachwycało się przez ostatnie lata (asystenci głosowi, jak np. Alexa, Siri, Google Now, czy wcześniej dostępne boty tekstowe) mają się do ChatGPT jak Góry Świętokrzyskie do Himalajów. To zupełnie inna liga.
Podsumowanie¶
W kolejnych wpisach poruszę kwestie technikaliów ChatGPT i gry pomiędzy najmocniejszymi graczami na rynku. Temat jest gorący i najwięksi zaczęli wyciągać swoje najmocniejsze karty. Oj, dzieje się! 🙂
photo: TechTalks
PODOBAŁ CI SIĘ TEN ARTYKUŁ?
Jeśli tak, to zarejestruj się, by otrzymywać informacje o nowych wpisach.
Dodatkowo w prezencie wyślę Ci bezpłatny poradnik :-)
Cześć! Czy 'gość’ nie zrobił sobie kuku z data leakage w [9]?
Sam przyznał mi się do błędu, gdy wkleiłem [9] i zapytałem, czy taka transformacja nie spowoduje DL:
„Yes, the code you provided may lead to data leakage. By concatenating the training and test data before fitting the ColumnTransformer, you are allowing the transformer to use information from the test data when encoding the features. This means that the transformer has seen the test data and is therefore likely to perform better on it, which would result in an overestimate of the model’s performance.
To avoid this issue, it is best to fit the ColumnTransformer only on the training data and then transform both the training and test data. This way, the transformer has only seen the training data, and its performance on the test data will provide a more accurate estimate of how well it will generalize to new, unseen data.”
😉
Cześć! Brawo za spostrzegawczość. 🙂
Cześć Mateusz!
Też testowałem jego możliwości, chociaż bardziej w kontekście budowy różnych metod / klas w Python, które w szerokim rozumieniu pobierają / przetwarzają dane. Działa super do stworzenia „formatki”, którą można później rozszerzać całkowicie samodzielnie lub z dalszym udziałem naszego nowego przyjaciela.
Inny use case, z któym sobie świetnie poradził: przepisz kod z języka X na język Y, gdy okazało się, że algorytm trzeba przepisać i zaimplementować gdzie indziej. 🙂
Cześć Michał!
Faktycznie, z tego typu zadaniami radzi sobie bardzo dobrze. Na blogu OpenAI są też ciekawe przykłady w których GPT rozwiązuje testy z olimpiady matematycznej. Radzi sobie więc też z nieco bardziej abstrakcyjnymi problemami. 😉
https://openai.com/blog/formal-math/ – przykłady zadań z olimpiady matematycznej.
https://arxiv.org/abs/2109.00110 – praca na ten temat.