====== Eksploracja Danych: Laboratorium 3 ====== Tematem będzie regresja z użyciem języka Python :!: Konwersja notatnika Colab na PDF [[https://github.com/pszwed-ai/lab-eksploracja-danych/blob/main/ConvertNotebookToPDF.ipynb]] ===== Zbiór danych ===== *Zbiór danych dotyczących sprzedaży domów dostępny na [[https://www.kaggle.com/harlfoxem/housesalesprediction|Kaggle]]. *Jego lokalna kopia może zostać pobrana z {{ :med:kc_house_data.csv.zip |kc_house_data.csv.zip}}. *Można też wykonać następujący kod w notatniku Colab !wget https://dysk.agh.edu.pl/s/7mHMk2A8GT76Swk/download -O kc_house_data.csv.zip !unzip kc_house_data.csv.zip ===== 3.1 Wczytaj do Pandas Data Frame ===== import pandas as pd import numpy as np # Wczytaj do DataFrame df = pd.read_csv('kc_house_data.csv',parse_dates=['date']) df.head() ===== 3.2 Wyświetl informacje o zbiorze danych ===== === Ile jest kolumn (atrybutów). Ile jest obserwacji (instancji, rekordów danych)? === print(len(df)) print(df.shape) df.info() print(df.columns) === Zakresy i średnie wartości === # informacje o danych print('--- Min values ---') print(df.min()) print('--- Max values ---') print(df.max()) print('--- Mean values ---') print(df.mean()) ===Histogramy dla poszczególnych atrybutów=== import matplotlib.pyplot as plt plt.rcParams["figure.figsize"] = (15,15) df.hist(bins=50) ===== 3.3 Usuwanie i konwersja danych ===== Zazwyczaj część danych z zewnętrznego źródła powinna zostać usunięta. Na pewno należy usunąć ''id'' (ogólnie klucze z bazy danych). Co jeszcze? Może kod pocztowy? Datę konwertujemy na wartość numeryczną. df2 = df.drop(columns=['id',???? ]) df2['date']=pd.to_numeric(df2['date']) df2.head() ===== 3.4 Regresja ===== ==== 3.4.1 Przetwarzamy cały zbiór danych ==== import sklearn.linear_model regr = sklearn.linear_model.LinearRegression() # y to wektor wartości wyjściowych y =df2['price'].to_numpy() # nie chcemy używać ceny w regresji bo otrzymalibyśmy równanie price=1.0*price df2_noprice=df2.drop(columns=['price']) X=df2_noprice.to_numpy() regr.fit(X, y) regr.score(X,y) ==== 3.4.2 Obliczamy metryki ==== Metryki są obliczane przez porównanie wartości przewidywanych (zwróconych przez model) ''y_pred'' i znanych //ground truth// ''y'' import sklearn.metrics y_pred = regr.predict(X) scores={'r2':sklearn.metrics.r2_score, 'mse':sklearn.metrics.mean_squared_error, 'rmse':lambda y_true,y_pred : np.sqrt(sklearn.metrics.mean_squared_error(y_true,y_pred)), 'maxe':sklearn.metrics.max_error, 'med':sklearn.metrics.median_absolute_error, 'mae':sklearn.metrics.mean_absolute_error, } for k in scores: r = scores[k](y,y_pred) print(f'{k}:{r}') ==== 3.4.3 Train Test Split ==== from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 123) regr = sklearn.linear_model.LinearRegression() regr.fit(X_train, y_train) y_pred = regr.predict(X_test) for k in scores: r = scores[k](y_test,y_pred) print(f'{k}:{r}') Czy wyniki zależą od wielkości zbioru uczącego - pośrednio definiowanego przez parametr ''test_size''? Poeksperymentuj z różnymi wartościami. Wypróbuj formułę: ''test_size = 1-k*len(df.columns)/len(df)'', gdzie k=1,2,3,...10 Ile danych (w stosunku do liczby atrybutów) potrzeba do nauczenie modelu, aby uzyskać akceptowalne rezultaty? ** Przedstaw wyniki w formie tabelki ** ==== 3.4.4 Wydruk równania regresji ==== Wydrukuj równanie regresji dla typowego modelu. Czy na podstawie wag można określić, które atrybuty mają mały/duży wpływ na wynik? Jaką operację należałoby przeprowadzić, aby uzyskać wiarygodny wynik? def print_formula(regr,labels,target): print(f'{target} = ') for i in range(len(regr.coef_)): print(f'\t{regr.coef_[i]: .3g}\t* {labels[i]} +') print(f'\t{regr.intercept_:.8}') print_formula(regr,df2_noprice.columns,'price') ==== 3.4.5 k-fold CrossValidation ==== Wyznacz średnie wartości metryk otrzymanych podczas walidacji krzyżowej from sklearn.model_selection import KFold from sklearn.utils import Bunch # słownik na składowanie wyników b = Bunch() for k in scores: b[k]=[] # b[k].append(0) print(b) # train_index, test_index to indeksy wierszy użytych jako zbiory treningowe i testowe kf = KFold(n_splits=10) for train_index, test_index in kf.split(X, y): X_train,y_train = X[train_index],y[train_index] X_test,y_test = X[test_index],y[test_index] regr = sklearn.linear_model.LinearRegression() regr.fit(X_train, y_train) y_pred = regr.predict(X_test) for k in scores: r = scores[k](y_test,y_pred) b[k].append(r) for k in b: oblicz i wypisz średnie wartości w listach b[k] ==== 3.4.6 Przetestuj Ridge i Lasso ==== Wpierw zmieńmy kod //split train test// na funkcję. def train_and_test(X,y,regr=sklearn.linear_model.LinearRegression()): # print(regr) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 123) regr.fit(X_train, y_train) y_pred = regr.predict(X_test) for k in scores: r = scores[k](y_test,y_pred) print(f'{k}:{r}') **Porównaj w tabelce wyniki **(zwłaszcza r2)** zwrócone przez** - LinearRegression - Ridge - Lasso ===== 3.5 Analiza danych ===== ==== 3.5.1 Czy atrybuty są skorelowane? ==== Obliczmy współczynniki korelacji Pearsona dla wszystkich atrybutów. Dane zostaną zebrane w postaci macierzy. import scipy.stats n = len(df2.columns) rs = np.zeros((n,n)) # print(rs) # print(df.iloc[:,0]) for i in range(n): for j in range(n): r,p = scipy.stats.pearsonr(df2.iloc[:,i],df2.iloc[:,j]) rs[i,j]= r Można trochę to zoptymalizować, bo macierz jest symetryczna. Wyświetlmy macierz w bardziej czytelnej postaci... import itertools def plot_matrix(cm, labels, normalize=False, title='', cmap=plt.cm.Blues): fig = plt.figure() ax=fig.add_subplot(111) ax.matshow(cm, interpolation='nearest', cmap=cmap) plt.title(title) # plt.colorbar() tick_marks = np.arange(len(labels)) plt.xticks(tick_marks, labels, rotation=90) ax.set_xticks(tick_marks) ax.set_yticks(tick_marks) ax.set_xticklabels(labels) ax.set_yticklabels(['']+labels) fmt = '.2f' #if normalize else 'd' thresh = 0.5 for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])): plt.text(j, i, format(cm[i, j], fmt), horizontalalignment="center", color="white" if cm[i, j] > thresh else "black") plt.tight_layout() plt.show() plot_matrix(rs,labels=df2.columns) ==== 3.5.2 Przetestuj działanie dla podzbiorów atrybutów ==== * Wybierz atrybuty do usunięcia i sprawdź wyniki * Poeksperymentuj z różnymi wariantami podzbiorów atrybutów * Wybieraj słabo skorelowane z ceną lub mocno skorelowane ze sobą * Porównaj LinearRegression, Ridge i Lasso **Wyniki zbierz w tabelce** df3 = df2_noprice.drop(columns = ['date',...]) X = df3.to_numpy() regr = sklearn.linear_model.LinearRegression() train_and_test(X,y,regr) print_formula(regr,df3.columns,'price') ==== 3.5.3 A może transformacja danych? ==== Eksperymenty z przetranformowanymi danymi są elementami procesu nazywanego //data wrangling// Zobacz co się stanie z ceną w wyniku zastąpienia wartości danych ich logarytmami? plt.rcParams["figure.figsize"] = (10,10) df2.hist('price',bins=50) df2_log=pd.DataFrame(df2) df2_log['logprice']=np.log(df2['price']) df2_log.hist('logprice',bins=50) Napiszemy funkcję, która * obliczy logarytm y_train * przeprowadzi regresję * obliczy wartość przewidywaną y_pred i wyznaczy np.exp(y_pred) * następnie wzynaczy metryki dla np.exp(y_pred) def train_and_test_log(X,y,regr=sklearn.linear_model.LinearRegression()): X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 123) regr.fit(X_train, ...) y_pred = regr.predict(X_test) y_pred=... for k in scores: r = scores[k](y_test,y_pred) print(f'{k}:{r}') df3=df2_noprice X = df3.to_numpy() regr = sklearn.linear_model.Ridge(solver='svd') train_and_test_log(X,y,regr) Jaki był rezultat? ==== 3.5.4 Normalizacja cech ==== Wypróbuj normalizację cech (sprowadzenie do średniej = 0 oraz podzielenie przez odchylenie standardowe) from sklearn.preprocessing import StandardScaler X=df2_noprice.to_numpy() scaler = StandardScaler() X_n=scaler.fit_transform(X) Wykonaj testy używając X_n zamiast X. Czy poprawiły się wyniki? Wydrukuj równanie regresji. Które współczynniki mają teraz największy wpływ na cenę? ===== 3.6 Regresja wielomianowa ===== from sklearn.preprocessing import PolynomialFeatures # df3 = df2_noprice.drop(columns = [....]) df3 = df2_noprice X = df3.to_numpy() poly = PolynomialFeatures(degree=2) X=poly.fit_transform(X) regr = sklearn.linear_model.Lasso() train_and_test(X,y,regr) # print_formula(regr,df3.columns,'price') print(f'Liczba parametrów modelu: {len(regr.coef_)+1}') Przetestuj LinearRegression, Ridge i Lasso dla rozszerzenia zbiorów cech do postaci wielomianów 2 i 3 stopnia. **Wyniki zbierz w tabelce** ===== 3.7 Inne algorytmy regresji ===== W bibliotece scikit zdefiniowanych jest co najmniej kilkanaście algorytmów regresji... **Zbierz wartości współczynika determinacji r2 w tabelce. Który algorytm jest najbardziej obiecujący?** from sklearn.linear_model import ElasticNet, LassoLars, BayesianRidge, SGDRegressor, Perceptron from sklearn.svm import SVR from xgboost import XGBRegressor from sklearn.tree import DecisionTreeRegressor from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScaler df3 = df2_noprice X = df3.to_numpy() regressors = [ElasticNet(), LassoLars(alpha=.1), BayesianRidge(), make_pipeline(StandardScaler(),SGDRegressor(max_iter=1000, tol=1e-3)), Perceptron(), SVR(kernel='poly',degree=2), DecisionTreeRegressor(), XGBRegressor(), ] for regr in regressors: print(f'------------ {regr.__class__.__name__} ---------------') train_and_test(X,y,regr)