{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Άσκηση 05 kMeans.ipynb","provenance":[{"file_id":"1rkGmboIIcteo6kXXWgavqsnbEM5jV0Tq","timestamp":1605018712256}]},"kernelspec":{"name":"python3","display_name":"Python 3"}},"cells":[{"cell_type":"markdown","metadata":{"id":"Om_7-uxyeVx_"},"source":["# Άσκηση\n","\n","Μέχρι στιγμής έχουμε δει συσταδοποίηση μόνο πάνω σε δισδιάστατα δεδομένα, τα οποία μπορούμε να οπτικοποιήσουμε εύκολα και να κρίνουμε το αποτέλεσμα και με το μάτι. Τώρα όμως θα βάλουμε στην είσοδο του αλγορίθμου δεδομένα πολλών διαστάσεων με θόρυβο. Για τη σωστή επιλογή του $k$, θα πρέπει αναγκαστικά να βασιστούμε στις μετρικές που αναφέραμε προηγουμένως. Ας φτιάξουμε αρχικά τα δεδομένα μας."]},{"cell_type":"code","metadata":{"id":"XbI2Ng9xeVyD"},"source":["import numpy as np\n","\n","np.random.seed(13)\n","\n","# Χρήσιμα features\n","f1 = np.random.rand(50,4) * 10\n","f2 = np.random.rand(50,4) * 10 + 15\n","f3 = np.random.rand(50,4) * 10 + 30\n","f4 = np.random.rand(50,4) * 10 + 45\n","useful = np.concatenate([f1, f2, f3, f4])\n","print('useful features: ', useful.shape)\n","\n","# Θόρυβος\n","noise = np.random.rand(len(useful),useful.shape[1]**2) + np.random.rand(useful.shape[1]**2,) * useful.max()\n","print('noise: ', noise.shape)\n","\n","# Προσθέτουμε τις στήλες θορύβου\n","data = np.hstack([useful, noise])\n","print('features + noise:', data.shape)\n","\n","# Shuffle\n","np.random.shuffle(data.T)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"LqdOXJ_LeVyO"},"source":["## Ερώτημα 1\n","\n","Χρησιμοποιήστε το εμπειρικό κριτήριο \"elbow\", για να υπολογίσετε μέσω της αδράνειας το βέλτιστο $k$, χρησιμοποιώντας ως δεδομένα **μόνο** τα χρήσιμα χαρακτηριστικά (μεταβλητή **useful**). Δοκιμάστε όλες τις τιμές για $k \\in \\left[ 1, 50 \\right]$ και χρονομετρήστε το διάστημα που παίρνει να εκπαιδευτεί ο κάθε $k$-means. Ο σκελετός σάς δίνεται παρακάτω.\n","\n","- Ποιο είναι το βέλτιστο $k$;\n","- Τι παρατηρείτε για τον χρόνο εκπαίδευσης όσο μεγαλώνει το $k$;\n","\n","Συμπληρώνουμε στον παρακάτω κώδικα τις εντολές που λείπουν εκεί όπου υπάρχουν σχόλια και συμπληρώνουμε τα ορίσματα εκεί όπου υπάρχουν `???`.\n","Έπειτα απαντάμε τις παραπάνω ερωτήσεις.\n","\n","Τις τιμές του $k$ θα τις αποθηκεύσουμε σε μία λίστα που θα ονομάσουμε `k_range`. Τις τιμές της αδράνειας θα τις αποθηκεύσουμε σε μια λίστα που θα ονομάσουμε `useful_inertia`."]},{"cell_type":"code","metadata":{"id":"HjnFvX62eVyQ"},"source":["from sklearn.cluster import KMeans\n","import time\n","\n","start_time = time.time()\n","k_range = range(???)\n","# <-- κάτι πρέπει να μπει εδώ :)\n","\n","for k in k_range: # ορίζουμε το εύρος του k\n"," ep_time = time.time()\n"," \n"," # ορίζουμε και εκπαιδεύουμε έναν k-means\n"," # αποθηκεύουμε τη μεταβλητή inertia_ \n"," \n"," if k%5==0:\n"," print('k={:<2}, time={:.2f} sec'.format(k, float(time.time()-ep_time)))\n","print('training time: {} sec'.format(time.time()-start_time))\n","\n","# Έλεγχος αν συμβαδίζουν οι διαστάσεις\n","assert len(k_range) == len(useful_inertia), 'Πρέπει οι λίστες k_range και useful_inertia να έχουν τον ίδιο αριθμό στοιχείων!'"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"BesKl7mIeVyW"},"source":["import matplotlib.pyplot as plt\n","%matplotlib inline\n","\n","plt.plot(k_range, useful_inertia)\n","plt.ylabel('inertia')\n","plt.xlabel('k')\n","plt.title('Inertia over values of k')\n","\n","# Αφότου εντοπίσουμε το elbow, βγάζουμε τις παρακάτω εντολές από σχόλια και αναθέτουμε την τιμή του στη μεταβλητή elbow:\n","\n","#elbow = ???\n","#plt.scatter(elbow,useful_inertia[elbow-1], c='r', lw=0, s=50)\n","#plt.annotate(\"elbow\", xy=(elbow,useful_inertia[elbow-1]), xytext=(20, 100000), arrowprops=dict(arrowstyle=\"->\"))\n","#plt.xlim([k_range[0], k_range[-1]])\n","#plt.ylim([0,useful_inertia[0]])"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"MUbtDGHJeVyd"},"source":["## Ερώτημα 2\n","\n","Εφαρμόστε την ίδια διαδικασία για τα δεδομένα **μαζί με το θόρυβο** (μεταβλητή **data**). Χρησιμοποιήστε τις ίδιες τιμές του $k$ με πριν. Χρονομετρήστε όπως και πριν τη διαδικασία.\n","\n","- Αλλάζει το βέλτιστο $k$ σε σχέση με πριν;\n","- Ανταποκρίνεται ο αλγόριθμος ικανοποιητικά στο θόρυβο που προσθέσαμε;\n","- Τι παρατηρείτε για το χρόνο εκπαίδευσης σε σχέση με πριν που είχαμε μόνο τα χρήσιμα χαρακτηριστικά;\n","\n","Τις τιμές του inertia θα τις αποθηκεύσουμε σε μια λίστα που θα ονομάσουμε `data_inertia`."]},{"cell_type":"code","metadata":{"id":"Ka4btfdfeVye"},"source":["# Αντιγράφουμε τα παραπάνω 2 κελιά κώδικα και τροποποιούμε όπου χρειάζεται.\n","\n","# Κελί 1: αποθηκεύουμε το inertia_ για όλες τις τιμές του k."],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"7zMhVYPMeVyl"},"source":["plt.plot(k_range, useful_inertia, label='useful')\n","plt.plot(k_range, data_inertia, c='g', label='data')\n","plt.ylabel('inertia')\n","plt.xlabel('k')\n","plt.legend(loc='upper right')\n","plt.title('Inertia over values of k')\n","\n","# Αφότου εντοπίσουμε το elbow, βγάζουμε τις παρακάτω εντολές από σχόλια και αναθέτουμε την τιμή του στην μεταβλητή elbow:\n","# tip: κάντε zoomin με plt.xlim([1,10])\n","\n","#elbow = ???\n","#plt.scatter(elbow,data_inertia[elbow-1], c='r', lw=0, s=50)\n","#plt.annotate(\"elbow\", xy=(elbow,data_inertia[elbow-1]), xytext=(20, 100000), arrowprops=dict(arrowstyle=\"->\"))\n","#plt.xlim([k_range[0], k_range[-1]])\n","#plt.ylim([0,useful_inertia[0]])"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"KOU8MwfreVyq"},"source":["## Ερώτημα 3\n","\n","Χρησιμοποιήστε το κριτήριο **silhouette** για τον υπολογισμό του βέλτιστου $k$. Αυτή τη φορά ελέγξτε για όλες τις τιμές του $k \\in \\left[ 2, 100 \\right]$.\n","\n","- Ποιο **k** βρήκατε; Ήταν διαφορετικό από πριν;\n","\n","Τις τιμές του **k** θα τις αποθηκεύσουμε σε μία λίστα που θα ονομάσουμε `k_range`. Τις τιμές των silhouette score θα τις αποθηκεύσουμε σε μια λίστα που θα ονομάσουμε `silhouette_scores`."]},{"cell_type":"code","metadata":{"id":"BBTnMzGbeVyu"},"source":["from sklearn.metrics import silhouette_score\n","\n","# Αντιγράφουμε τα κελιά παραπάνω, τροποποιούμε όπου χρειάζεται.\n","\n","# Κελί 1: αυτή τη φορά αποθηκεύουμε το silouette_score και όχι το inertia!"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"KIj9aRSaeVy1"},"source":["assert len(k_range) == len(silhouette_scores), 'Πρέπει οι λίστες k_range και silhouette_scores να έχουν τον ίδιο αριθμό στοιχείων!' \n","\n","plt.plot(k_range, silhouette_scores)\n","best_k = np.argmax(silhouette_scores) + 2 # +2 γιατί ξεκινάμε το range() από k=2 και όχι από 0 που ξεκινάει η αρίθμηση της λίστας\n","plt.scatter(best_k, silhouette_scores[best_k-2], color='r') # για τον ίδιο λόγο το καλύτερο k είναι αυτό 2 θέσεις παρακάτω από το index της λίστας\n","plt.annotate(\"best k\", xy=(best_k, silhouette_scores[best_k-2]), xytext=(50, 0.39),arrowprops=dict(arrowstyle=\"->\")) # annotation\n","print('Maximum average silhouette score for k =', best_k)"],"execution_count":null,"outputs":[]}]}