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
!wget https://dysk.agh.edu.pl/s/7mHMk2A8GT76Swk/download -O kc_house_data.csv.zip !unzip kc_house_data.csv.zip
import pandas as pd import numpy as np # Wczytaj do DataFrame df = pd.read_csv('kc_house_data.csv',parse_dates=['date']) df.head()
print(len(df)) print(df.shape) df.info() print(df.columns)
# informacje o danych print('--- Min values ---') print(df.min()) print('--- Max values ---') print(df.max()) print('--- Mean values ---') print(df.mean())
import matplotlib.pyplot as plt plt.rcParams["figure.figsize"] = (15,15) df.hist(bins=50)
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()
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)
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}')
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
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')
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]
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
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)
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')
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
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?
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ę?
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
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)