#!/usr/bin/env python # coding: utf-8 # # Data Mining # # ## Lab 6: Dimensionality Reduction # # Pada modul ini, Anda akan mempelajari tentang bagaimana kita dapat melakukan reduksi dimensi pada data dengan dimensi yang sangat besar, e.g. dari teks atau gambar. Dalam kasus ini, kita akan menggunakan dataset MNIST. Salah satu metode yang akan dibahas secara mendalam dalam modul ini adalah *Principal Component Analysis* (PCA). # In[1]: from __future__ import print_function from sklearn.decomposition import PCA import matplotlib.pyplot as plt import numpy as np import pandas as pd import seaborn as sns get_ipython().run_line_magic('matplotlib', 'inline') np.random.seed(538) plt.style.use('ggplot') # ## Pengenalan PCA # In[2]: from sklearn.datasets import load_digits from sklearn.model_selection import train_test_split mnist = load_digits() img_rows, img_cols = 8, 8 X_train, X_test, y_train, y_test = train_test_split(mnist.data, mnist.target, test_size=0.33, random_state=1945) # Mengubah dimensi data menjadi n x pixels X_train = X_train.reshape(X_train.shape[0], img_rows * img_cols) X_test = X_test.reshape(X_test.shape[0], img_rows * img_cols) # Sekarang, kita ingin melihat nilai rata-rata dari masing-masing pixel, untuk kemudian dilihat hasil visualisasinya. # In[3]: plt.imshow(X_train.mean(axis=0).reshape(img_rows, img_cols), cmap='Greys') plt.xticks(range(8)) plt.yticks(range(8)) plt.show() # Perhatikan bahwa rata-rata untuk pixels di pojok kiri dan pojok kanan berwarna putih. Artinya, pixels tersebut **tidak pernah berubah warnanya** untuk semua data yang kita miliki. Dengan kata lain, pixels tersebut *tidak berguna* untuk menentukan gambar digit apakah yang akan kita klasifikasi tersebut. PCA bertujuan untuk "membuang" atribut-atribut yang tidak berguna tersebut. # In[4]: print(X_train.shape) print(X_test.shape) # In[5]: pca = PCA(2) # kita akan mengambil dua komponen paling pentingnya saja X_train_pca = pca.fit_transform(X_train) X_test_pca = pca.transform(X_test) # In[6]: print(X_train_pca.shape) print(X_test_pca.shape) # Karena dimensi hasil proyeksi hanya terdiri dari dua atribut, maka kita bisa memetakannya ke dalam diagram cartesian. # In[7]: # Kode dari http://nbviewer.jupyter.org/github/jakevdp/PythonDataScienceHandbook/blob/master/notebooks/05.09-Principal-Component-Analysis.ipynb plt.scatter(X_train_pca[:, 0], X_train_pca[:, 1], c=y_train, edgecolor='none', alpha=0.5, cmap=plt.cm.get_cmap('spectral', 10)) plt.xlabel('component 1') plt.ylabel('component 2') plt.colorbar(); # Dari *scatter plot* tersebut, kita dapat melihat bahwa angka 1, 4, dan 7 berada berdekatan (lihat bagian bawah kiri). Ini sesuai dengan intuisi kita bahwa angka 1, 4, dan 7 memiliki kemiripan dari sisi tarikan garis lurus. Inilah yang dicoba digambarkan sebagai "komponen prinsipil" dari gambar angka yang kita miliki. # ## Menentukan Jumlah Komponen Prinsipil # # Dalam mencari jumlah komponen prinsipil, kita ingin mempertahankan sebanyak mungkin variansi dari data yang sebenarnya. Angka yang lumrah digunakan adalah 90% atau 95%. Nilai variansi ini bersesuaian dengan $m$ nilai eigen terbesar pertama. # $$ # \frac{\sum_{i=1}^{m} \lambda_i}{\sum_{i=1}^{d} \lambda_i} \le 1 # $$ # dengan $d$ adalah jumlah dimensi (atribut) asli data dan $m \ll d$. Nilai ini dapat juga dipetakan sebagai total kumulatif nilai eigen yang terurut tersebut sehingga dapat terlihat seperti di bawah ini. # In[8]: pca = PCA().fit(X_train) plt.plot(np.cumsum(pca.explained_variance_ratio_)) plt.axhline(.90, linestyle='--', c='b') plt.axhline(.95, linestyle='--', c='y') plt.xlabel('number of components') plt.ylabel('cumulative explained variance'); # Dari grafik tersebut, bisa kita lihat bahwa untuk mencapai 90% variansi, dibutuhkan sekitar 20 komponen prinsipil, sedangkan untuk 95% variansi, dibutuhkan ~30 komponen prinsipil. # ## Menggunakan PCA untuk Memperbaiki Klasifikasi # # Dalam beberapa algoritma, penggunaan PCA bisa meningkatkan akurasi. Namun, beberapa algoritma yang lain mendapat keuntungan dari klasifikasi berupa proses yang lebih cepat. Dalam modul ini, kita akan melihat dampak PCA pada hasil klasifikasi dengan Naive Bayes dan k-Nearest Neighbours. # ### Naive Bayes # In[9]: from sklearn.naive_bayes import GaussianNB from sklearn.metrics import accuracy_score, confusion_matrix clf = GaussianNB() get_ipython().run_line_magic('timeit', '-n 1 clf.fit(X_train, y_train)') y_pred = clf.predict(X_test) print('Akurasi:', accuracy_score(y_test, y_pred)) sns.heatmap(confusion_matrix(y_test, y_pred), annot=True, fmt='d'); # In[10]: pca = PCA(.9) # PCA dengan komponen yang menjelaskan 90% variansi get_ipython().run_line_magic('timeit', '-n 1 pca.fit(X_train)') X_train_pca = pca.transform(X_train) X_test_pca = pca.transform(X_test) clf = GaussianNB() get_ipython().run_line_magic('timeit', '-n 1 clf.fit(X_train_pca, y_train)') y_pred = clf.predict(X_test_pca) print('Akurasi:', accuracy_score(y_test, y_pred)) sns.heatmap(confusion_matrix(y_test, y_pred), annot=True, fmt='d'); # Ingat bahwa Naive Bayes memanfaatkan asumsi bahwa setiap atribut *conditionally independent* jika diberikan kelasnya? PCA menghasilkan proyeksi dengan memanfaatkan vektor eigen yang saling tegak lurus satu sama lain sehingga hasil klasifikasi dengan Naive Bayes bisa lebih baik karena sesuai dengan asumsi yang diberikan di awal tersebut. # ### k-Nearest Neighbours # In[11]: from sklearn.neighbors import KNeighborsClassifier train_acc = [] acc = [] for k in range(1, 11): clf = KNeighborsClassifier(k) clf.fit(X_train, y_train) y_train_pred = clf.predict(X_train) get_ipython().run_line_magic('timeit', '-n 1 clf.predict(X_test) # diulang di bawah hanya untuk mengetahui proses pencarian data') y_pred = clf.predict(X_test) train_acc.append(accuracy_score(y_train, y_train_pred)) acc.append(accuracy_score(y_test, y_pred)) print('Akurasi terbaik', max(acc)) plt.plot(range(1, 11), train_acc) plt.plot(range(1, 11), acc) plt.legend(['train', 'test']); # In[12]: pca = PCA(.9) # PCA dengan komponen yang menjelaskan 90% variansi get_ipython().run_line_magic('timeit', '-n 1 pca.fit(X_train)') X_train_pca = pca.transform(X_train) X_test_pca = pca.transform(X_test) train_acc = [] acc = [] for k in range(1, 11): clf = KNeighborsClassifier(k) clf.fit(X_train_pca, y_train) y_train_pred = clf.predict(X_train_pca) get_ipython().run_line_magic('timeit', '-n 1 clf.predict(X_test_pca)') y_pred = clf.predict(X_test_pca) train_acc.append(accuracy_score(y_train, y_train_pred)) acc.append(accuracy_score(y_test, y_pred)) print('Akurasi terbaik', max(acc)) plt.plot(range(1, 11), train_acc) plt.plot(range(1, 11), acc) plt.legend(['train', 'test']); # Perhatikan dalam kasus k-NN bahwa waktu yang dibutuhkan untuk mengklasifikasikan data menjadi lebih cepat. Jika Anda coba untuk dataset yang berukuran lebih besar, Anda akan melihat efek yang lebih drastis pada perubahan kecepatan jika dibandingkan dengan pengorbanan akurasi -- dan terkadang kita membutuhkan ini.