diff --git a/Prace_domowe/Praca_domowa3/Grupa3/Slowakiewicz Patryk/HW3 - Slowakiewicz.html b/Prace_domowe/Praca_domowa3/Grupa3/Slowakiewicz Patryk/HW3 - Slowakiewicz.html new file mode 100644 index 000000000..b4abedd5c --- /dev/null +++ b/Prace_domowe/Praca_domowa3/Grupa3/Slowakiewicz Patryk/HW3 - Slowakiewicz.html @@ -0,0 +1,14731 @@ + + +
+ + +import numpy as np
+import pandas as pd
+import matplotlib.pyplot as plt
+from sklearn.model_selection import train_test_split
+from sklearn.model_selection import cross_val_score
+from sklearn.tree import DecisionTreeClassifier,plot_tree
+from sklearn.pipeline import Pipeline
+from sklearn.linear_model import LogisticRegression
+from sklearn.ensemble import RandomForestClassifier
+import warnings
+from sklearn.metrics import accuracy_score, recall_score, precision_score, classification_report, roc_auc_score
+warnings.filterwarnings('ignore')
+
Dane podzieliłem na 3 zbiory: treningowy, testowy i walidacyjny.
+ +df = pd.read_csv('australia.csv')
+
df.columns
+
Index(['MinTemp', 'MaxTemp', 'Rainfall', 'Evaporation', 'Sunshine', + 'WindGustSpeed', 'WindSpeed9am', 'WindSpeed3pm', 'Humidity9am', + 'Humidity3pm', 'Pressure9am', 'Pressure3pm', 'Cloud9am', 'Cloud3pm', + 'Temp9am', 'Temp3pm', 'RainToday', 'RainTomorrow'], + dtype='object')+
x = df.drop('RainTomorrow', axis = 1)
+y = df.RainTomorrow
+x_train, x_test, y_train, y_test = train_test_split(x, y)
+x_test, x_val, y_test, y_val = train_test_split(x_test, y_test)
+
Postanowiłem sprawdzić jak działać będzie:
+tree = DecisionTreeClassifier(min_samples_leaf=300)
+tree.fit(x_train, y_train)
+tree.score(x_test, y_test)
+
0.8483645301569295+
lr = LogisticRegression(penalty='none', max_iter=500)
+lr.fit(x_train, y_train)
+lr.score(x_test, y_test)
+
0.8575345055776139+
rf = RandomForestClassifier(n_estimators=150, min_samples_leaf=300)
+rf.fit(x_train, y_train)
+rf.score(x_test, y_test)
+
0.8548875023633957+
Aby zbadać skuteczność modeli sprawdziłem metodą średniej z crossvalidacji każdy z nich dla 4 równych metryk. Ogólne accuracy jest podobne dla każdego z modeli, gdzie Regresja Logistyczna jest o ok 0.5 pp lepsza.
+Aby upewnić się co do wyniku sprawdzam modele na zbiorze testowym. W tym wypadku róznica w Accuracy jest jeszcze mniejsza. Warto się zastanownić czy któraś z miar nie jest dla nas ważniejsza. Uważam, że wyłapywanie dni które są deszczowe jest dla nas jak najbardziej kluczowe, dlatego powinniśmy dużą uwagę przyłożyć do miary Recall. W tym wypadku Log Reg jest dużo lepsze od pozostałych modeli, choć nadal z dość słabym wynikiem, nieco ponad 52%.
Biorąc pod uwagę ponniższe wyniki uważam, że Log Reg jest najlepszym modelem do naszego problemu.
+ +df = pd.DataFrame(columns=['accuracy','precision','recall', 'roc_auc'], index=['Tree', 'Log Reg', 'Random Forest'])
+ls = [tree, lr, rf]
+for i in range(0, len(ls)):
+ for metric in df.columns.values:
+ df.loc[df.index[i],metric] = np.mean(cross_val_score(ls[i], x_train, y_train, scoring=metric))
+df
+
+ | accuracy | +precision | +recall | +roc_auc | +
---|---|---|---|---|
Tree | +0.845374 | +0.719639 | +0.496483 | +0.866734 | +
Log Reg | +0.851826 | +0.730565 | +0.525895 | +0.880104 | +
Random Forest | +0.849321 | +0.761191 | +0.467711 | +0.881172 | +
tree_y_hat = tree.predict(x_test)
+lr_y_hat = lr.predict(x_test)
+rf_y_hat = rf.predict(x_test)
+ls_hat = [tree_y_hat, lr_y_hat, rf_y_hat]
+
df1 = pd.DataFrame(columns=['accuracy','precision','recall', 'roc_auc'], index=['Tree', 'Log Reg', 'Random Forest'])
+metric = df1.columns.values
+for i in range(0, len(ls)):
+ df1.loc[df.index[i],metric[0]] = accuracy_score(y_test, ls_hat[i])
+ df1.loc[df.index[i],metric[1]] = precision_score(y_test, ls_hat[i])
+ df1.loc[df.index[i],metric[2]] = recall_score(y_test, ls_hat[i])
+ df1.loc[df.index[i],metric[3]] = roc_auc_score(y_test, ls_hat[i])
+
df1
+
+ | accuracy | +precision | +recall | +roc_auc | +
---|---|---|---|---|
Tree | +0.847797 | +0.699387 | +0.504425 | +0.722758 | +
Log Reg | +0.857535 | +0.731123 | +0.526991 | +0.737167 | +
Random Forest | +0.854888 | +0.76023 | +0.468584 | +0.714215 | +
+
\n", + " | accuracy | \n", + "precision | \n", + "recall | \n", + "roc_auc | \n", + "
---|---|---|---|---|
Tree | \n", + "0.845374 | \n", + "0.719639 | \n", + "0.496483 | \n", + "0.866734 | \n", + "
Log Reg | \n", + "0.851826 | \n", + "0.730565 | \n", + "0.525895 | \n", + "0.880104 | \n", + "
Random Forest | \n", + "0.849321 | \n", + "0.761191 | \n", + "0.467711 | \n", + "0.881172 | \n", + "
\n", + " | accuracy | \n", + "precision | \n", + "recall | \n", + "roc_auc | \n", + "
---|---|---|---|---|
Tree | \n", + "0.847797 | \n", + "0.699387 | \n", + "0.504425 | \n", + "0.722758 | \n", + "
Log Reg | \n", + "0.857535 | \n", + "0.731123 | \n", + "0.526991 | \n", + "0.737167 | \n", + "
Random Forest | \n", + "0.854888 | \n", + "0.76023 | \n", + "0.468584 | \n", + "0.714215 | \n", + "
import dalex as dx
+import pandas as pd
+import numpy as np
+import matplotlib.pyplot as plt
+import seaborn as sns
+import category_encoders as ce
+import sklearn.pipeline
+from sklearn.preprocessing import OneHotEncoder, MinMaxScaler
+from sklearn.svm import SVR, SVC
+from sklearn.model_selection import GridSearchCV
+from sklearn.model_selection import train_test_split, cross_val_score
+import warnings
+warnings.filterwarnings('ignore')
+
x_train = dx.datasets.load_apartments()
+y_train = x_train['m2_price']
+x_train.drop('m2_price', axis=1, inplace=True)
+
+x_test = dx.datasets.load_apartments_test()
+y_test = x_test['m2_price']
+x_test.drop('m2_price', axis= 1, inplace=True)
+
+x_train.head()
+
+ | construction_year | +surface | +floor | +no_rooms | +district | +
---|---|---|---|---|---|
1 | +1953 | +25 | +3 | +1 | +Srodmiescie | +
2 | +1992 | +143 | +9 | +5 | +Bielany | +
3 | +1937 | +56 | +1 | +2 | +Praga | +
4 | +1995 | +93 | +7 | +3 | +Ochota | +
5 | +1992 | +144 | +6 | +5 | +Mokotow | +
dist = x_test['district'].unique()
+
enc = ce.OneHotEncoder(cols=['district'], )
+enc.fit(x_test)
+x_test = enc.fit_transform(x_test)
+x_train = enc.fit_transform(x_train)
+
x_test.columns.values[-10:] = dist
+x_train.columns.values[-10:] = dist
+
def score_model(y, y_hat, func = (lambda x: x)):
+ l = len(y)
+ return round(sum((func(y)-func(y_hat))**2)/l, 2)
+
Błąd średniokwadratowy ze średniej
+ +score_model(y_test, y_test.mean())
+
810804.49+
Okazuje się gorszy od baseline
+ +svm = SVR()
+svm.fit(x_train, y_train)
+y_hat = svm.predict(x_test)
+
score_model(y_test, y_hat)
+
826320.67+
sns.displot(y_hat)
+
<seaborn.axisgrid.FacetGrid at 0x2192a5f0a90>+
sns.displot(y_test)
+
<seaborn.axisgrid.FacetGrid at 0x2192c241e50>+
Skaluję zmienne przy pomocy MinMaxScaler
+ +mm = MinMaxScaler()
+mm_x_train = mm.fit_transform(x_train)
+mm_x_test = mm.transform(x_test)
+
mm_x_train = pd.DataFrame(mm_x_train, columns=x_train.columns.values)
+mm_x_test = pd.DataFrame(mm_x_test, columns=x_train.columns.values)
+
m = min(y_train)
+r = max(y_train)-min(y_train)
+mm_y_train = (y_train-m)/r
+mm_y_test = (y_test-m)/r
+
Okazuje się, że przeskalowanie danych znacznie poprawia predykcyjność modelu, z zaznaczeniem, że przy mierzeniu błędu średniokwadratowego przeskalowuję spowrotem uzyskane pradykcję, aby były porównywalne.
+ +svm2 = SVR()
+svm.fit(mm_x_train, mm_y_train)
+mm_y_hat = svm.predict(mm_x_test)
+
score_model(mm_y_test, mm_y_hat, lambda x: x*r+m)
+
360463.38+
Użyłem GridSearch aby sprawdzić czy jest możliwość polepszenia predykcyjności modelu. Okazuję się, że taki model ma nieznacznie większy błąd. A jedyny parametr jaki zmieniliśmy jest C (cost)
+ +grid_search = {
+ 'C' : np.logspace(-4, 4, 10),
+ 'gamma' : ['scale', 'auto'],
+ 'degree' : range(1,5),
+ 'kernel' : ['linear', 'poly', 'rbf']
+}
+
svr3 = SVR()
+
gs = GridSearchCV(svr3, grid_search, cv=10)
+
gs.fit(mm_x_train, mm_y_train)
+
GridSearchCV(cv=10, estimator=SVR(), + param_grid={'C': array([1.00000000e-04, 7.74263683e-04, 5.99484250e-03, 4.64158883e-02, + 3.59381366e-01, 2.78255940e+00, 2.15443469e+01, 1.66810054e+02, + 1.29154967e+03, 1.00000000e+04]), + 'degree': range(1, 5), 'gamma': ['scale', 'auto'], + 'kernel': ['linear', 'poly', 'rbf']})+
gs.best_params_
+
{'C': 0.3593813663804626, 'degree': 1, 'gamma': 'scale', 'kernel': 'rbf'}+
svr4 = SVR(C = 0.3593813663804626, degree= 1, gamma='scale', kernel='rbf')
+svr4.fit(mm_x_train, mm_y_train)
+gs_y_hat = svr4.predict(mm_x_test)
+
score_model(mm_y_test, gs_y_hat, lambda x: x*r+m)
+
360518.27+
Zbiór pobrałem ze strony https://www.kaggle.com/iabhishekofficial/mobile-price-classification?select=train.csv. +Zawiera informację o parametrach telefonach komórkowych i ich przedziale cenowym. Aby zredukować problem z multi-label classification zmapuję przedziały cenowe odpowiednio:
+x = pd.read_csv('train.csv')
+y = x['price_range']
+x.drop('price_range', axis = 1, inplace=True)
+y = y.map(lambda x: x//2)
+x_train, x_test, y_train, y_test = train_test_split(x, y, stratify = y, test_size=0.2, random_state=1)
+
x_train.head()
+
+ | battery_power | +blue | +clock_speed | +dual_sim | +fc | +four_g | +int_memory | +m_dep | +mobile_wt | +n_cores | +pc | +px_height | +px_width | +ram | +sc_h | +sc_w | +talk_time | +three_g | +touch_screen | +wifi | +
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1922 | +764 | +0 | +1.0 | +1 | +9 | +1 | +45 | +0.5 | +124 | +8 | +11 | +52 | +539 | +1341 | +19 | +1 | +12 | +1 | +0 | +0 | +
1622 | +1057 | +1 | +2.7 | +0 | +3 | +1 | +41 | +0.1 | +97 | +4 | +10 | +397 | +891 | +2033 | +16 | +9 | +2 | +1 | +1 | +0 | +
1921 | +569 | +1 | +2.5 | +1 | +0 | +0 | +41 | +0.3 | +124 | +1 | +1 | +388 | +605 | +2651 | +17 | +7 | +4 | +0 | +0 | +0 | +
1499 | +1742 | +1 | +0.5 | +1 | +5 | +1 | +43 | +0.9 | +176 | +3 | +7 | +356 | +1407 | +1921 | +9 | +2 | +3 | +1 | +1 | +0 | +
1082 | +1044 | +1 | +2.8 | +1 | +7 | +0 | +33 | +0.6 | +129 | +4 | +13 | +42 | +1262 | +1816 | +17 | +16 | +15 | +1 | +0 | +1 | +
Ponieważ w naszych danych wszystkie przedziały cenowe mają taką samą ilość danych a przy podziale używamy parametru stratify to nasz baseline będzie wynosił 50%
+ +y_train.hist()
+
<AxesSubplot:>+
Nawet podstawowy model bardzo dobrze przewiduję ceny telefonów z 96,5 accuracy.
+ +svc = SVC()
+svc.fit(x_train, y_train)
+svc.score(x_test, y_test)
+
0.965+
cross_val_score(svc, x_train, y_train).mean()
+
0.985625+
Skaluję dane za pomocą MinMaxScaler. A poniweaż nasz target jest już przeskalowany to wystarczy użyć to na x_train, x_test.
+Uzyskaliśmy bardzo ciekway wynik, ponieważ skalowanie danych pogorszyło wyniki przewidywań, aby to sprawdzić użyłem równeż walidacji krzyżowej której wyniki również były lepsze na danych nieprzeskalowanych.
+ +mm = MinMaxScaler()
+mm_x_train = mm.fit_transform(x_train)
+mm_x_test = mm.transform(x_test)
+mm_x_train = pd.DataFrame(mm_x_train, columns=x_train.columns.values)
+mm_x_test = pd.DataFrame(mm_x_test, columns=x_train.columns.values)
+
svc2 = SVC()
+svc2.fit(mm_x_train, y_train)
+svc2.score(mm_x_test, y_test)
+
0.9325+
cross_val_score(svc, mm_x_train, y_train).mean()
+
0.95375+
W tym przypaku dzięki GridSearch udało się poprawić wyniki SVC dla nieprzeskalowanych danych do 98,25% accuracy. Aby upewnić się, że skalowanie faktycznie daje gorsze wyniki jego brak, wykonałem gridsearch również dla danych przeskalowanych ale wyniki nadal były gorsze 96%.
+ +grid_search2 = {
+ 'C' : np.logspace(-2, 2, 5),
+ 'gamma' : ['scale', 'auto'],
+ 'degree' : range(1,3),
+ 'kernel' : ['rbf']
+}
+
svc3 = SVC()
+gs_c = GridSearchCV(svc3, grid_search2)
+
gs_c.fit(x_train, y_train)
+
GridSearchCV(estimator=SVC(), + param_grid={'C': array([1.e-02, 1.e-01, 1.e+00, 1.e+01, 1.e+02]), + 'degree': range(1, 3), 'gamma': ['scale', 'auto'], + 'kernel': ['rbf']})+
print('Accuracy dla modelu nie skalowanego: ' + str(gs_c.best_estimator_.score(x_test, y_test)))
+
Accuracy dla modelu nie skalowanego: 0.9825 ++
svc3 = SVC()
+gs_c2 = GridSearchCV(svc3, grid_search2)
+
gs_c2.fit(mm_x_train, y_train)
+
GridSearchCV(estimator=SVC(), + param_grid={'C': array([1.e-02, 1.e-01, 1.e+00, 1.e+01, 1.e+02]), + 'degree': range(1, 3), 'gamma': ['scale', 'auto'], + 'kernel': ['rbf']})+
print('Accuracy dla modelu skalowanego: ' + str(gs_c2.best_estimator_.score(mm_x_test, y_test)))
+
Accuracy dla modelu skalowanego: 0.96 ++
Należy zauważyć, że wyniki modelowań różniły się w obu przypadkach. Na pierwszym zbiorze apartments z paczki dalex skalowanie danych znacznie poprawiło wyniki modelu ale już GridSearch minimalnie je pogorszył.
+W drugim przypadku skalowanie danych przyniosło znaczące pogorsznie wyników, a w takim wypadku GridSearch przyczynił się do ich małej poprawy.
\n", + " | construction_year | \n", + "surface | \n", + "floor | \n", + "no_rooms | \n", + "district | \n", + "
---|---|---|---|---|---|
1 | \n", + "1953 | \n", + "25 | \n", + "3 | \n", + "1 | \n", + "Srodmiescie | \n", + "
2 | \n", + "1992 | \n", + "143 | \n", + "9 | \n", + "5 | \n", + "Bielany | \n", + "
3 | \n", + "1937 | \n", + "56 | \n", + "1 | \n", + "2 | \n", + "Praga | \n", + "
4 | \n", + "1995 | \n", + "93 | \n", + "7 | \n", + "3 | \n", + "Ochota | \n", + "
5 | \n", + "1992 | \n", + "144 | \n", + "6 | \n", + "5 | \n", + "Mokotow | \n", + "
\n", + " | battery_power | \n", + "blue | \n", + "clock_speed | \n", + "dual_sim | \n", + "fc | \n", + "four_g | \n", + "int_memory | \n", + "m_dep | \n", + "mobile_wt | \n", + "n_cores | \n", + "pc | \n", + "px_height | \n", + "px_width | \n", + "ram | \n", + "sc_h | \n", + "sc_w | \n", + "talk_time | \n", + "three_g | \n", + "touch_screen | \n", + "wifi | \n", + "
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1922 | \n", + "764 | \n", + "0 | \n", + "1.0 | \n", + "1 | \n", + "9 | \n", + "1 | \n", + "45 | \n", + "0.5 | \n", + "124 | \n", + "8 | \n", + "11 | \n", + "52 | \n", + "539 | \n", + "1341 | \n", + "19 | \n", + "1 | \n", + "12 | \n", + "1 | \n", + "0 | \n", + "0 | \n", + "
1622 | \n", + "1057 | \n", + "1 | \n", + "2.7 | \n", + "0 | \n", + "3 | \n", + "1 | \n", + "41 | \n", + "0.1 | \n", + "97 | \n", + "4 | \n", + "10 | \n", + "397 | \n", + "891 | \n", + "2033 | \n", + "16 | \n", + "9 | \n", + "2 | \n", + "1 | \n", + "1 | \n", + "0 | \n", + "
1921 | \n", + "569 | \n", + "1 | \n", + "2.5 | \n", + "1 | \n", + "0 | \n", + "0 | \n", + "41 | \n", + "0.3 | \n", + "124 | \n", + "1 | \n", + "1 | \n", + "388 | \n", + "605 | \n", + "2651 | \n", + "17 | \n", + "7 | \n", + "4 | \n", + "0 | \n", + "0 | \n", + "0 | \n", + "
1499 | \n", + "1742 | \n", + "1 | \n", + "0.5 | \n", + "1 | \n", + "5 | \n", + "1 | \n", + "43 | \n", + "0.9 | \n", + "176 | \n", + "3 | \n", + "7 | \n", + "356 | \n", + "1407 | \n", + "1921 | \n", + "9 | \n", + "2 | \n", + "3 | \n", + "1 | \n", + "1 | \n", + "0 | \n", + "
1082 | \n", + "1044 | \n", + "1 | \n", + "2.8 | \n", + "1 | \n", + "7 | \n", + "0 | \n", + "33 | \n", + "0.6 | \n", + "129 | \n", + "4 | \n", + "13 | \n", + "42 | \n", + "1262 | \n", + "1816 | \n", + "17 | \n", + "16 | \n", + "15 | \n", + "1 | \n", + "0 | \n", + "1 | \n", + "