Table of Contents

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

!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

  1. LinearRegression
  2. Ridge
  3. 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

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

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)