{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Λύση Άσκησης.ipynb","provenance":[]},"kernelspec":{"name":"python2-spark21","display_name":"Python 2 with Spark 2.1","language":"python"}},"cells":[{"cell_type":"markdown","metadata":{"id":"CvdzwUp0mebD"},"source":["# Άσκηση: μελέτη επίδρασης προεπεξεργασίας στη διαστατικότητα και την ομαδοποίηση\n","\n","\n","\n","Αρχικά κάνουμε update και import τις βιβλιοθήκες που θα χρειαστούμε."]},{"cell_type":"code","metadata":{"id":"35-RlmEMmebG"},"source":["!pip install --upgrade scikit-learn\n","!pip install --upgrade numpy\n","!pip install --upgrade scipy\n","!pip install --upgrade nltk"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"dI_9NGNfEwYc"},"source":["import numpy as np\n","from sklearn.feature_extraction.text import TfidfVectorizer\n","from sklearn.cluster import KMeans\n","from sklearn.metrics import silhouette_score\n","import matplotlib.pyplot as plt\n","%matplotlib inline"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"ua5-z6r4mebN"},"source":["Φέρνουμε το σύνολο κειμένων μας (Reuters)."]},{"cell_type":"code","metadata":{"id":"zCUw7JWfmebP"},"source":["import nltk\n","\n","\n","nltk.download('reuters') # κατεβάζουμε το dataset\n","from nltk.corpus import reuters # το κάνουμε import\n","\n","# List of document ids\n","documents = reuters.fileids()\n"," \n","train_docs_id = list(filter(lambda doc: doc.startswith(\"train\"),\n"," documents))\n","\n","train_docs = [reuters.raw(doc_id) for doc_id in train_docs_id]"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"eajysVOHv_22"},"source":["Τα δεδομένα μας θα είναι τα πρώτα 500 έγγραφα του train set"]},{"cell_type":"code","metadata":{"id":"4TQkSfnmv6xH"},"source":["data = train_docs[:500]"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"dcWNXljdmebU"},"source":["Θα χρησιμοποιήσουμε το [TF-IDF Vectorizer](http://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html) του scikit-learn προκειμένου να μετατρέψουμε τα κείμενά μας σε έναν πίνακα διανυσμάτων. Καλείστε να πειραματιστείτε και να επιλέξετε εσείς τα ορίσματα του TF-IDF. Στη συνέχεια θα χρησιμοποιήσουμε τον αλγόριθμο k-means και τη μετρική silhouette για να εντοπίσουμε τον αριθμό των ομάδων στις οποίες ανήκουν τα κείμενα. Για να μπορέσουμε να δούμε και ορισμένα στοιχεία για τις θεματικές ενότητες στις οποίες ανήκουν τα κείμενα, θα τυπώσουμε τους πιο σημαντικούς όρους της κάθε ομάδας.\n","\n","1. Δοκιμάστε να τρέξετε τον TF-IDF Vectorizer χωρίς παραμέτρους. Τι διαστάσεις έχει το διάνυσμα TF-IDF; Τα αποτελέσματα βγάζουν νόημα;\n","2. Δοκιμάστε να τρέξετε τον Vectorizer, αφαιρώντας τα english stopwords (παράμετρος stop_words='english'). Τι διαστάσεις έχει τώρα το διάνυσμα; Βελτιώθηκε καθόλου η ποιότητα του clustering;\n","3. Δοκιμάστε να τρέξετε τον Vectorizer, αφαιρώντας και τους όρους που εμφανίζονται σε λιγότερα από 10 documents (παράμετρος min_df=10). Τι διαστάσεις έχει το διάνυσμα; Βελτιώθηκε το clustering;\n","4. Δοκιμάστε να τρέξετε τον Vectorizer, αφαιρώντας και τους όρους που εμφανίζονται σε περισσότερα από το 50% των κειμένων (παράμετρος max_df=0.5). Βελτιώνει αυτό το clustering;\n","5. Δοκιμάστε να βελτιώσετε περαιτέρω την ποιότητα του clustering. Αυξήστε το μέγιστο k σε 50. Σε πόσες κατηγορίες χωρίζεται το σύνολο των κειμένων μας; Ποια είναι η θεματική ενότητα της κάθε κατηγορίας; Πως θα μπορούσαν να βελτιωθούν περισσότερο τα αποτελέσματα (πχ τί λείπει από τον TfidfVectorizer);"]},{"cell_type":"markdown","metadata":{"id":"GxH5xO8B06gR"},"source":["## 1. \n","διαστάσεις (500, 6998)"]},{"cell_type":"code","metadata":{"id":"WXIlUPsLvnPV"},"source":["vectorizer = TfidfVectorizer()\n","\n","tf_idf_array = vectorizer.fit_transform(data).toarray()\n","print('TF-IDF array shape:', tf_idf_array.shape)\n","\n","silhouette_scores = []\n","for k in range(2, 20):\n"," km = KMeans(k)\n"," preds = km.fit_predict(tf_idf_array)\n"," silhouette_scores.append(silhouette_score(tf_idf_array, preds))\n"," \n","plt.plot(range(2, 20), 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.xlim([2,19])\n","plt.annotate(\"best k\", xy=(best_k, silhouette_scores[best_k-2]), xytext=(5, silhouette_scores[best_k-2]),arrowprops=dict(arrowstyle=\"->\")) # annotation\n","print('Maximum average silhouette score for k =', best_k)\n","\n","km = KMeans(best_k)\n","km.fit(tf_idf_array)\n","terms = vectorizer.get_feature_names_out()\n","order_centroids = km.cluster_centers_.argsort()[:, ::-1]\n","for i in range(best_k):\n"," out = \"Cluster %d:\" % i\n"," for ind in order_centroids[i, :10]:\n"," out += ' %s' % terms[ind]\n"," print(out)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"fITDN0cmtMQW"},"source":["## 2-5. \n","διαστάσεις (500, 661)"]},{"cell_type":"code","metadata":{"id":"IXIlXJnWzwt-"},"source":["vectorizer = TfidfVectorizer(max_df=0.5, min_df=10, stop_words='english')\n","\n","tf_idf_array = vectorizer.fit_transform(data).toarray()\n","print('TF-IDF array shape:', tf_idf_array.shape)\n","\n","silhouette_scores = []\n","for k in range(2, 50):\n"," km = KMeans(k)\n"," preds = km.fit_predict(tf_idf_array)\n"," silhouette_scores.append(silhouette_score(tf_idf_array, preds))\n"," \n","plt.plot(range(2, 50), 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.xlim([2,49])\n","plt.annotate(\"best k\", xy=(best_k, silhouette_scores[best_k-2]), xytext=(5, silhouette_scores[best_k-2]),arrowprops=dict(arrowstyle=\"->\")) # annotation\n","print('Maximum average silhouette score for k =', best_k)\n","\n","km = KMeans(best_k)\n","km.fit(tf_idf_array)\n","terms = vectorizer.get_feature_names()\n","order_centroids = km.cluster_centers_.argsort()[:, ::-1]\n","for i in range(best_k):\n"," out = \"Cluster %d:\" % i\n"," for ind in order_centroids[i, :10]:\n"," out += ' %s' % terms[ind]\n"," print(out)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"M43_uCubz7RW"},"source":["* Είναι λογικό το best k να βρίσκεται στο άνω όριο εφόσον ξέρουμε ότι οι κατηγορίες είναι 90\n","* Σημειώστε ότι ο TfidfVectorizer δεν κάνει stemming (φαίνεται και από τα clusters). Μπορούμε πρώτα να εφαρμόσουμε stemming με το [nltk](https://pythonspot.com/nltk-stemming/). Μια άλλη λύση είναι το πακέτο [PyStemmer](https://pypi.org/project/PyStemmer/).\n","\n"]}]}