<jupyter_start><jupyter_text>Dimensionality ReductionLe tecniche per la riduzione della dimensionalità sono molto utili quando abbiamo molte featurese il modello non riesce atrovare pattern nei dati per questo motivo.Ne esistono diverse ma in questo notebook vedremo la più utilizzata, la Principal Component Analysis (PCA).Funziona quando ci sono relazioni lineari tra le variabili, quindi in presenza di variabili numeriche continue. **L'obiettivo è quello di ridurre ma con la minima perdita di informazione.**L'algoritmo per la riduzione della dimensionalità con PCA è più o meno il seguente:1. Standardizzare il dataset *d-dimensionale*2. Costruire la matrice di covarianza3. Decomporre la matrice di covarianza nei suoi **autovalori** e **autovettori**4. Ordinare gli autovalori riducendone l'ordine per valutare i corrispondenti autovettori5. Selezionare *k* autovettori, che corrispondono ai *k* più grandi autovalori, dove *k* è la nuova dimensionalità del sottospazio delle caratteristiche, con $k \leq d$6. Costruire la matrice di proiezione *W* dai primi *k* autovettori7. Trasformare il dataset di input per ottenere il nuovo spazio delle caratteristiche.![pca](https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fi.stack.imgur.com%2FG7Gkv.png&f=1&nofb=1)[Image Credits](https://stats.stackexchange.com/questions/320743/why-are-eigenvectors-the-principal-components-in-principal-component-analysis)Un esempio molto semplice per spiegare la PCA è quello dei pesci. Abbiamo dei pesci e possono essere misurati per:* lunghezza* altezza* pesoQueste tre dimensioni sono correlate tra loro, quindi possono essere riassunte in un'unica nuova dimensione:* stazza DatasetPer questo esempio utilizzeremo nuovamente il dataset Iris già visto nel notebook sui decision tree.<jupyter_code>import numpy as np
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score<jupyter_output><empty_output><jupyter_text>Riproduciamo l'esperimento con il decision tree ma con tutte le variabili.Il dataset è semplice e l'accuratezza sarà pari ad 1.Lo scopo di questo mnotebook non è un miglioramento ma mostrare la poca perdita di informazione utilizzando la PCA.<jupyter_code>iris = load_iris()
x = iris.data
y = iris.target

train_x, test_x, train_y, test_y = train_test_split(x, y, test_size = 0.2, random_state = 42)
clf = DecisionTreeClassifier()
clf.fit(train_x, train_y)

import time

start_time = time.time()
yhat = clf.predict(test_x)

print("execution time: ", time.time() - start_time)
print("\n")
print("accuracy: ", accuracy_score(test_y, yhat))<jupyter_output>execution time:  0.0004107952117919922


accuracy:  1.0<jupyter_text>PCA: scegliere il numero di componenti a prioriIn questo caso l'iperparametro da impostare è il numero stesso delle componenti.Vogliamo due dimensioni, vedremo come sono fatte le componenti.Notare che sul train applichiamo *fit_transform* mentre sul test solo *transform* questo vale per tutte le trasformazioni. Tra train e test ci potrebbe essere una scala di valori diversa che indurrebbe in errore lo stimatore.<jupyter_code>pca = PCA(n_components=2)
train_x_pca = pca.fit_transform(train_x)
test_x_pca = pca.transform(test_x)
import matplotlib.pyplot as plt

for i in np.unique(train_y):
  mask = train_y == i
  plt.scatter(train_x_pca[mask, 0], train_x_pca[mask, 1], label=i)
clf.fit(train_x_pca, train_y)

import time

start_time = time.time()
yhat_pca = clf.predict(test_x_pca)

print("execution time: ", time.time() - start_time)
print("\n")
print("accuracy: ", accuracy_score(test_y, yhat_pca))<jupyter_output>execution time:  0.0003371238708496094


accuracy:  0.9666666666666667<jupyter_text>PCA: scegliere la varianza spiegataUn altro iperparametro che è possibile scegliere è quanta dell'informazione nel dataset originale vogliamo mantenere.Solitamente deve essere almeno maggiore al 75% per non icorrere in errori grandi. Meglio se dal 90% in su, in questo caso una sola componente spiegherebbe quasi il 90% della variabilità quindi per averne tre usiamo il 99% come livello.Quando si usa la varianza spiegata *svd_solver* che effettua la [**Singol Value Decomposition**](https://it.wikipedia.org/wiki/Decomposizione_ai_valori_singolari) deve essere impostato a "*full*".<jupyter_code>pca = PCA(n_components=0.99, svd_solver="full")
train_x_pca = pca.fit_transform(train_x)
test_x_pca = pca.transform(test_x)
plt.figure(figsize=(18,10))
for i in np.unique(train_y):
  mask = train_y == i
  plt.subplot(3,1,1)
  plt.scatter(train_x_pca[mask,0], train_x_pca[mask,1], label = i)
  plt.subplot(3,1,2)  
  plt.scatter(train_x_pca[mask,0], train_x_pca[mask,2], label = i)
  plt.subplot(3,1,3)
  plt.scatter(train_x_pca[mask,1], train_x_pca[mask,2], label = i)
plt.show()
clf.fit(train_x_pca, train_y)

import time

start_time = time.time()
yhat_pca = clf.predict(test_x_pca)

print("execution time: ", time.time() - start_time)
print("\n")
print("accuracy: ", accuracy_score(test_y, yhat_pca))<jupyter_output>execution time:  0.0003066062927246094


accuracy:  1.0
{'fraction_non_alphanumeric': 0.08674652241112829, 'fraction_numerical': 0.026854714064914992, 'mean_word_length': 6.210306406685237, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 14, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '145976', 'license': 'MIT', 'n_tokens_mistral': 1958, 'n_tokens_neox': 1864, 'n_words': 531, 'path': 'machine_learning_pills/02_unsupervised/06_dimensionality_reduction.ipynb', 'repo_name': 'nickprock/appunti_data_science', 'size': '5176'}