#!/usr/bin/env python
# coding: utf-8

# Kody źródłowe do książki: Python. Uczenie maszynowe w przykładach
#  
# Rozdział 10.: Dobre praktyki uczenia maszynowego
#  
# Autor: Yuxi (Hayden) Liu (yuxi.liu.ece@gmail.com)

# # Najlepsze praktyki przygotowywania danych

# ## Dobra praktyka nr 4. Opracowanie niekompletnych danych

import numpy as np
from sklearn.impute import SimpleImputer


data_origin = [[30, 100],
               [20, 50],
               [35, np.nan],
               [25, 80],
               [30, 70],
               [40, 60]]


imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')
imp_mean.fit(data_origin)


data_mean_imp = imp_mean.transform(data_origin)
print(data_mean_imp)


imp_median = SimpleImputer(missing_values=np.nan, strategy='median')
imp_median.fit(data_origin)
data_median_imp = imp_median.transform(data_origin)
print(data_median_imp)


# Nowe próbki
new = [[20, np.nan],
       [30, np.nan],
       [np.nan, 70],
       [np.nan, np.nan]]
new_mean_imp = imp_mean.transform(new)
print(new_mean_imp)


# Efekty pomijania brakujących danych oraz uzupełniania danych
from sklearn import datasets
dataset = datasets.load_diabetes()
X_full, y = dataset.data, dataset.target


m, n = X_full.shape
m_missing = int(m * 0.25)
print(m, m_missing)


np.random.seed(42)
missing_samples = np.array([True] * m_missing + [False] * (m - m_missing))
np.random.shuffle(missing_samples)


missing_features = np.random.randint(low=0, high=n, size=m_missing)


X_missing = X_full.copy()
X_missing[np.where(missing_samples)[0], missing_features] = np.nan


# Pomijanie próbek zawierających brakujące dane
X_rm_missing = X_missing[~missing_samples, :]
y_rm_missing = y[~missing_samples]


# Szacowanie wartości wskaźnika R^2 na zbiorze danych w którym usunięto wybrakowane próbki
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_val_score
regressor = RandomForestRegressor(random_state=42, max_depth=10, n_estimators=100)
score_rm_missing = cross_val_score(regressor, X_rm_missing, y_rm_missing).mean()
print(f'Ocena modelu po usunięciu wybrakowanych próbek: {score_rm_missing:.2f}')


# Imputation with mean value
imp_mean = SimpleImputer(missing_values=np.nan, strategy='mean')
X_mean_imp = imp_mean.fit_transform(X_missing)


# Obliczenie wartości wskaźnika R^2 dla zbioru danych z wartościami uzupełnionymi średnią arytmetyczną
regressor = RandomForestRegressor(random_state=42, max_depth=10, n_estimators=100)
score_mean_imp = cross_val_score(regressor, X_mean_imp, y).mean()
print(f'Ocena modelu po uzupełnieniu braków średnią arytmetyczną: {score_mean_imp:.2f}')

# Obliczenie wartości wskaźnika R^2 dla pełnego zbioru danych
regressor = RandomForestRegressor(random_state=42, max_depth=10, n_estimators=500)
score_full = cross_val_score(regressor, X_full, y).mean()
print(f'Ocena modelu dla pełnego zbioru danych: {score_full:.2f}')


# # Dobre praktyki tworzenia zbioru treningowego

# ## Dobra praktyka nr 8. Rozważenie selekcji cech i wybór odpowiedniej metody

from sklearn.datasets import load_digits
dataset = load_digits()
X, y = dataset.data, dataset.target
print(X.shape)


# Ocena dokładności modelu dla oryginalnego, 64-wymiarowego zbioru danych:
from sklearn.svm import SVC
classifier = SVC(gamma=0.005, random_state=42)
score = cross_val_score(classifier, X, y).mean()
print(f'Ocena modelu dla oryginalnego zbioru danych: {score:.2f}')


# Wybór cech z wykorzystaniem lasu losowego
from sklearn.ensemble import RandomForestClassifier
random_forest = RandomForestClassifier(n_estimators=100, criterion='gini', n_jobs=-1, random_state=42)
random_forest.fit(X, y)

# Sortowanie cech na podstawie oceny ważności
feature_sorted = np.argsort(random_forest.feature_importances_)


# Wybór różnych liczb najważniejszych cech
K = [10, 15, 25, 35, 45]
for k in K:
    top_K_features = feature_sorted[-k:]
    X_k_selected = X[:, top_K_features]
    # Ocena dokładności modelu dla k wybranych cech
    classifier = SVC(gamma=0.005)
    score_k_features = cross_val_score(classifier, X_k_selected, y).mean()
    print(f'Ocena modelu dla {k} najważniejszych cech: {score_k_features:.2f}')


# ## Dobra praktyka nr 9. Rozważenie redukcji wymiarowości i wybór odpowiedniej metody

from sklearn.decomposition import PCA

# Wybranie różnych liczb najważniejszych komponentów
N = [10, 15, 25, 35, 45]
for n in N:
    pca = PCA(n_components=n)
    X_n_kept = pca.fit_transform(X)
    # Ocena dokładności modelu dla najważniejszych n komponentów
    classifier = SVC(gamma=0.005)
    score_n_components = cross_val_score(classifier, X_n_kept, y).mean()
    print(f'Ocena modelu dla {n} najważniejszych komponentów: {score_n_components:.2f}')



# ## Dobra praktyka nr 12. Inżynieria cech bez wiedzy eksperckiej

# ### Binaryzacja i dyskretyzacja

from sklearn.preprocessing import Binarizer
X = [[4], [1], [3], [0]]
binarizer = Binarizer(threshold=2.9)
X_new = binarizer.fit_transform(X)
print(X_new)


# ### Transformacja wielomianowa

from sklearn.preprocessing import PolynomialFeatures
X = [[2, 4],
     [1, 3],
     [3, 2],
     [0, 3]]
poly = PolynomialFeatures(degree=2)
X_new = poly.fit_transform(X)
print(X_new)


# ---

# Czytelnicy mogą pominąć następną komórkę.

get_ipython().system('jupyter nbconvert --to python ch10_part1.ipynb --TemplateExporter.exclude_input_prompt=True')

