{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Άσκηση 05 kMeans - Solution.ipynb","provenance":[{"file_id":"1xFEo4a5wEpEdMnmEMCmNPQIRAloABgbu","timestamp":1605019438239}]},"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(1,50)\n","\n","useful_inertia = []\n","for k in k_range: # ορίζουμε το εύρος του k\n"," ep_time = time.time()\n"," \n"," km = KMeans(k)\n"," km.fit(useful)\n"," useful_inertia.append(km.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","plt.xlim([1,10])\n","\n","elbow = 4\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":["from sklearn.cluster import KMeans\n","import time\n","\n","start_time = time.time()\n","k_range = range(1,50)\n","\n","useful_inertia = []\n","for k in k_range: # ορίζουμε το εύρος του k\n"," ep_time = time.time()\n"," \n"," km = KMeans(k)\n"," km.fit(data)\n"," useful_inertia.append(km.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":"7zMhVYPMeVyl"},"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","plt.xlim([1,10])\n","\n","elbow = 4\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":"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","k_range = range(2,100)\n","\n","silhouette_scores = []\n","for k in k_range:\n"," km = KMeans(k)\n"," km.fit(data)\n"," preds = km.predict(data)\n"," silhouette_scores.append(silhouette_score(data, preds))\n","\n","\n","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":[]}]}