{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Classification 1.1 datasets - train test sets - GNB.ipynb","provenance":[]},"kernelspec":{"name":"python3","display_name":"Python 3"},"accelerator":"GPU"},"cells":[{"cell_type":"markdown","metadata":{"id":"MZLbuyvjNC53"},"source":["# Εισαγωγή scikit-learn και dataset στο notebook"]},{"cell_type":"markdown","metadata":{"id":"QoIlBu68NC54"},"source":["Αρχικά κάνουμε upgrade στις βιβλοθήκες που θα χρειαστούμε, αν δεν έχουμε ήδη κάνει. Στο Colab θα χρεαστεί πιθανότατα να κάνουμε restart το runtime."]},{"cell_type":"code","metadata":{"scrolled":true,"id":"wVeTFMhlNC55","trusted":true},"source":["!pip install --upgrade pip #upgrade pip package installer\n","!pip install scikit-learn --upgrade #upgrade scikit-learn package\n","!pip install numpy --upgrade #upgrade numpy package\n","!pip install --upgrade matplotlib # Κάνουμε update την matplotlib"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"HtGvRuQMNC5_"},"source":["![UCI ML Logo](http://archive.ics.uci.edu/ml/assets/logo.gif \"UCI Machine Learning Repository\")\n","\n","To [UCI ML Repository](http://archive.ics.uci.edu/ml/index.php) είναι το διασημότερο αποθετήριο datasets για Machine Learning. Το dataset με το οποίο θα δουλέψουμε είναι το [Breast Cancer Wisconsin Diagnostic Database](https://archive.ics.uci.edu/ml/datasets/Breast+Cancer+Wisconsin+%28Diagnostic%29). Το dataset περιλαμβάνει διάφορες πληροφορίες για όγκους σχετιζόμενους με τον καρκίνο του μαστού καθώς και ετικέτες για κάθε δείγμα (sample), αν το δείγμα αντιστοιχεί σε καλοήθη όγκο ή κακοήθη. Το σύνολο δεδομένων έχει 569 δείγματα για αντίστοιχους όγκους και περιλαμβάνει 30 χαρακτηριστικά (attributes) για κάθε δείγμα, όπως ακτίνα του όγκου, υφή, ομοιομορφία και περιοχή. Θα χρησιμοποιήσουμε αυτό το dataset και τα χαρακτηριστικά για να προβλέψουμε αν ένας όγκος είναι κακοήθης ή όχι.\n","\n","Το Scikit-learn έχει για κάποια datasets, μεταξύ των οποίων και το breast cancer, έτοιμες συναρτήσεις για να τα φορτώνουμε χωρίς να χρειαστεί να διαβάσουμε text file. Τα datasets αποτελούν τα toy datasets του scikit-learn."]},{"cell_type":"code","metadata":{"id":"ZocYkGPENC6A","trusted":true},"source":["from sklearn.datasets import load_breast_cancer\n","\n","# Load dataset\n","data = load_breast_cancer()\n","data"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"u67rXHqANC6D"},"source":["Η μεταβλητή \"data\" είναι ένα αντικείμενο Python που δουλεύει σαν dictionary.\n","\n","| **key** | **value** | **type** | **size** |\n","| :------------------- | :---------------------------------------------------- | :----------- | :--------- |\n","| **'DESCR'** | 'Breast Cancer Wisconsin (Diagnostic) Database...' | str | 1 | \n","| **'data'** | [[1.799, 1.038, 1.228,...]...] | float array | (569,30) | \n","| **'feature_names'** | ['mean radius', 'mean texture', ...] | str array | (30,) |\n","| **'target'** | [0, 0, 0, ..., 0, 0, 1] | int array | (569,) |\n","| **'target_names'** | ['malignant', 'benign'] | str array | (2,) |\n","\n","Τα σημαντικά κλειδιά του λεξικού είναι οι ονομασίες των κατηγοριών εξόδου (target_names), οι κατηγορίες (ή κλάσεις ή ετικέτες) εξόδου (target), τα ονόματα των χαρακτηριστικών (feature_names) και τέλος τα ίδια τα χαρακτηριστικά (data). Στην πράξη χρειαζόμαστε μόνο τα χαρακτηριστικά (features) και τις ετικέτες τους (labels). Οι ονομασίες μας πληροφορούν για τη φυσική ερμηνεία των χαρακτηριστικών.\n","\n","Δημιουργούμε νέες μεταβλητές για κάθε σημαντικό σύνολο πληροφορίας του dataset:"]},{"cell_type":"code","metadata":{"id":"rjctATtVNC6E","trusted":true},"source":["# Organize our data\n","label_names = data['target_names']\n","labels = data['target']\n","feature_names = data['feature_names']\n","features = data['data']"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"du2g0h6tNC6G","trusted":true},"source":["# ποιες είναι οι κατηγορίες (ετικέτες) μας\n","print(label_names)"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"yHURhwN6NC6K","trusted":true},"source":["# οι κατηγορίες όλων των 569 δειγμάτων 0: κακοήθης - malignant (Μ) 1: καλοήθης - benign (Β)\n","print(labels)\n","# οι κατηγορίες είναι ένα μονοδιάστατο array\n","print(labels.shape)\n","# μετράμε τη συχνότητα των δύο κλάσεων\n","import numpy as np\n","print(\"frequencies:\", np.bincount(labels))\n","# Class distribution: 357 benign, 212 malignant"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"dvIQ-oKgNC6M","trusted":true},"source":["# η κατηγορία του πρώτου δείγματος\n","print(labels[0])"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"MMwrGyN-T5Tr"},"source":["Εφόσον το 0 είναι κακοήθης και το 1 καλοήθης, το πρώτο δείγμα αντιπροσωπεύει έναν κακοήθη όγκο."]},{"cell_type":"code","metadata":{"id":"oZhaPsQkNC6Q","trusted":true},"source":["# τα ονόματα των χαρακτηριστικών (features)\n","print(feature_names)"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"jkQ1sjkUNC6U","trusted":true},"source":["# το όνομα του πρώτου χαρακτηριστικού\n","print(feature_names[0])"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"c3y1smBANC6X","trusted":true},"source":["# οι διαστάσεις όλων των χαρακτηριστικών\n","# τα χαρακτηριστικά του πρώτου δείγματος (κακοήθες)\n","print(features.shape)\n","print(features[0])"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"QVEyDtLzNC6a"},"source":["Στο συγκεκριμένο παράδειγμα λοιπόν, τo πρώτο δείγμα μας είναι κακοήθες με ακτίνα του κυττάρου 1.79900000e+01."]},{"cell_type":"markdown","metadata":{"id":"5yWY1o4A1QaJ"},"source":["# Ασκηση 1\n","\n","## Toy dataset #2: \"Wine\"\n","\n","1. Εισάγετε τη συνάρτηση \"load_wine\" και αποθηκεύστε τα δεδομένα στο αντικείμενο data_2.\n","2. Οργανώστε τα δεδομένα σας στους πίνακες label_names_2, labels_2, feature_names_2, features_2 (Προσοχή στα ονόματα για να μην κάνετε overwrite τους πίνακες τους wisconsin)\n","\n","\n","* Ποιά είναι τα ονόματα των χαρακτηριστικών;\n","* Ποιές και πόσες είναι οι κατηγορίες των δειγμάτων;\n","* Πόσα είναι τα δείγματα;\n","* Ποιό είναι η τιμή της στάχτης (ash) του 10ου δείγματος;\n"]},{"cell_type":"code","metadata":{"id":"D0PqeNwux9nu"},"source":["# δοκιμάστε, η λύση είναι στο SHOW CODE\n","from sklearn.datasets import load_wine\n","\n","data_2 = load_wine()\n","label_names_2 = data_2['target_names']\n","labels_2 = data_2['target']\n","feature_names_2 = data_2['feature_names']\n","features_2 = data_2['data']\n","\n","print(feature_names_2)\n","print(label_names_2)\n","print(label_names_2.shape)\n","print(features_2.shape)\n","print(features_2[9][2])\n"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"ZScX_Zpd_-4l"},"source":["#@title\n","from sklearn.datasets import load_wine\n","\n","data2 = load_wine()\n","label_names2 = data2['target_names']\n","labels2 = data2['target']\n","feature_names2 = data2['feature_names']\n","features2 = data2['data']\n","\n","print(feature_names2)\n","print(label_names2, label_names2.shape)\n","print(features2.shape[0])\n","print(features2[9][2])"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"hf5MPEWN-kcW"},"source":["Έχουμε φορτώσει το wisconsin breast cancer dataset, θα προχωρήσουμε στο να δημιουργήσουμε απλούς ταξινομητές για να προβλέπουμε αν οι όγκοι είναι καλοήθεις ή κακοήθεις."]},{"cell_type":"markdown","metadata":{"id":"ZBZBRvfDNC6c"},"source":["# Train set, test set & αξιολόγηση (ορθότητα) ταξινομητών"]},{"cell_type":"markdown","metadata":{"id":"I5K4xNQMNC6d"},"source":["Η αξιολόγηση των ταξινομητών γίνεται πάντα σε δεδομένα που δεν έχουν δει κατά την εκπαίδευση έτσι ώστε να αξιολογήσουμε τη δυνατότητα γενίκευσής τους. Συνεπώς, πρωτού φτιάξουμε το μοντέλο κάθε ταξινομητή χωρίζουμε τα δεδομένα μας τυχαία σε ένα σύνολο εκπαίδευσης (train set) και ένα σύνολο ελέγχου (test set).\n","Παρακάτω βλέπουμε ένα παράδειγμα διαχωρισμού του dataset με αναλογία 60-40:\n","\n","![data split](https://i.ibb.co/x3V1FQ4/train-test.png)\n","\n","Χρησιμοποιούμε το train set για να εκτιμούμε και να βελτιώνουμε το μοντέλο του ταξινομητή κατά την ανάπτυξή του. Δεν επιτρέπεται σε κανένα σημείο η χρήση των δεδομένων test για την εκπαίδευση του ταξινομητή.\n","\n","![training](https://i.ibb.co/MMWjVkn/training.png)\n","\n","Χρησιμοποιούμε μετά το test set για να αξιολογήσουμε στατιστικά την απόδοση του μοντέλου μας.\n","\n","![testing](https://i.ibb.co/JsSDLpX/testing.png)\n","\n","Το sklearn έχει τη συνάρτηση train_test_split() που ανακατεύει τυχαία τα δείγματα και τα διαχωρίζει σε train και test με βάση κάποιο ποσοστό που θα της δώσουμε."]},{"cell_type":"code","metadata":{"id":"w_6FSK_hNC6e","trusted":true},"source":["from sklearn.model_selection import train_test_split\n","\n","# Split our data\n","train, test, train_labels, test_labels = train_test_split(features, labels, test_size=0.33)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"XAe7U6rNNC6g"},"source":["Θα δοκιμάσουμε πρώτα κάποιες πολύ απλές τακτικές ταξινόμησης. Η κλάση DummyClassifier δέχεται μια παράμετρο που καθορίζει την τακτική της ταξινόμησης ως εξής:\n","* “uniform”: προβλέπει τυχαία και ομοιόμορφα.\n","* “constant”: προβλέπει πάντα μία κατηγορία που τη διαλέγει ο χρήστης.\n","* “most_frequent”: προβλέπει πάντα την πιο συχνή κατηγορία στο training set.\n","* “stratified”: κάνει προβλέψεις διατηρώντας την κατανομή των κλάσεων στο training set."]},{"cell_type":"code","metadata":{"id":"vaLmfZkZNC6h","trusted":true},"source":["from sklearn.dummy import DummyClassifier\n","dc_uniform = DummyClassifier(strategy=\"uniform\")\n","dc_constant_0 = DummyClassifier(strategy=\"constant\", constant=0)\n","dc_constant_1 = DummyClassifier(strategy=\"constant\", constant=1)\n","dc_most_frequent = DummyClassifier(strategy=\"most_frequent\")\n","dc_stratified = DummyClassifier(strategy=\"stratified\")\n","\n","#με τη μέθοδο fit \"εκπαιδεύουμε\" τον ταξινομητή στο σύνολο εκπαίδευσης (τα χαρακτηριστικά και τις ετικέτες τους)\n","model = dc_uniform.fit(train, train_labels)\n","\n","#με τη μέθοδο predict παράγουμε προβλέψεις για τα δεδομένα ελέγχου (είσοδος τα χαρακτηριστικά μόνο)\n","preds = dc_uniform.predict(test)\n","print(preds)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"UVXonGNONC6k"},"source":["Για την αξιολόγηση, το πιο απλό κριτήριο είναι να συγκρίνουμε το ποσοστό ομοιότητας των πίνακων preds και test_labels. Το κριτήριο αυτό ονομάζεται ορθότητα (accuracy). Αν το κάναμε manually, για κάθε στοιχείο (δείγμα) των πινάκων που είναι όμοιο (0 και 0 ή 1 και 1) αυξάνουμε έναν μετρητή. Στην περίπτωση που είναι ανόμοια δεν τον αυξάνουμε. Διαιρούμε την τελική τιμή του μετρητή με το πλήθος των στοιχείων του πίνακα.\n","Το προηγούμενο for loop μας το δίνει έτοιμο η συνάρτηση accuracy_score:"]},{"cell_type":"code","metadata":{"id":"cHKESBEKNC6l","trusted":true},"source":["from sklearn.metrics import accuracy_score\n","print(accuracy_score(test_labels, preds))\n","\n","# ο υπολογισμός του accuracy είναι επίσης -ακόμα πιο βολικά- και μέθοδος του αντικειμένου dummy classifier\n","print(dc_uniform.score(test, test_labels)) # σε κάθε κλήση της dc_uniform έχουμε ξανά τυχαίες προβλέψεις"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"collapsed":true,"id":"BKM-YNvqNC6o"},"source":["Παρατηρούμε ότι αν τρέξουμε το πρoηγούμενο κελί διαδοχικές φορές, το δεύτερο accuracy αλλάζει γιατί καλούμε εκ νέου τον ταξινομητή να κάνει (τυχαίες) προβλέψεις.\n","\n","Ας αποθηκεύσουμε την ορθότητα όλων των dummy classifiers σε ένα λεξικό και να την τυπώσουμε από την καλύτερη στη χειρότερη"]},{"cell_type":"code","metadata":{"id":"ZS1PyAOzNC6p","trusted":true},"source":["wisconsin_accuracy = {}\n","wisconsin_accuracy['uniform (random)'] = dc_uniform.score(test, test_labels)\n","model = dc_constant_0.fit(train, train_labels)\n","wisconsin_accuracy['constant 0'] = dc_constant_0.score(test, test_labels)\n","model = dc_constant_1.fit(train, train_labels)\n","wisconsin_accuracy['constant 1'] = dc_constant_1.score(test, test_labels)\n","model = dc_most_frequent.fit(train, train_labels)\n","wisconsin_accuracy['most frequent label'] = dc_most_frequent.score(test, test_labels)\n","model = dc_stratified.fit(train, train_labels)\n","wisconsin_accuracy['stratified'] = dc_stratified.score(test, test_labels)\n","\n","print(\"Classification Accuracy on the Wisconsin Breast Cancer Dataset (33% test set)\\n\")\n","sorted_accuracy = [(k, wisconsin_accuracy[k]) for k in sorted(wisconsin_accuracy, key=wisconsin_accuracy.get, reverse=True)]\n","for k, v in sorted_accuracy:\n"," print(k,v)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"collapsed":true,"id":"tTIPdDYXNC6s"},"source":["# Naive Bayes Classifier"]},{"cell_type":"markdown","metadata":{"id":"8USxUnlANC6u"},"source":["![$P(A\\mid B)={\\frac {P(B\\mid A)\\,P(A)}{P(B)}}$](https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/Bayes%27_Theorem_MMB_01.jpg/220px-Bayes%27_Theorem_MMB_01.jpg \"A blue neon sign, showing the simple statement of Bayes’ theorem\")\n","\n","H βασική ιδέα λειτουργίας του ταξινομητή είναι α) ο γνωστός νόμος του Bayes $$P(A\\mid B)={\\frac {P(B\\mid A)\\,P(A)}{P(B)}}$$\n","\n","και β) η (naive) υπόθεση ότι τα χαρακτηριστικά είναι όλα ανεξάρτητα μεταξύ τους (δεν ισχύει γενικά, αλλά ο ταξινομητής είναι πρακτικά καλός σε πολλές περιπτώσεις). Παράδειγμα: θα βρέξει σήμερα? Naive Bayes: \"Θα το προβλέψω με βάση το παρελθόν θεωρώντας ότι τα χαρακτηριστικά θερμοκρασία, νεφοκάλυψη και ατμοσφαιρική πίεση είναι όλα ανεξάρτητα μεταξύ τους\".\n","\n","Με δεδομένα μια μεταβλητή κατηγορίας (κλάσης) $y$ και ένα εξαρτώμενο διάνυσμα χαρακτηριστικών $x_1$ μέχρι $x_n$, σύμφωνα με το θεώρημα του Bayes θα ισχύει \n","$$P(y \\mid x_1, \\dots, x_n) = \\frac{P(y) P(x_1, \\dots x_n \\mid y)}{P(x_1, \\dots, x_n)}$$\n","Ισχύει ότι $P(x_1, \\dots, x_i, \\dots, x_n \\mid y) = \\prod_{i=1}^{n} P(x_i | y, x_1, \\dots, x_{i-1}, x_{i+1}, \\dots, x_n)$ και κάνουμε την αφελή υπόθεση ότι το χαρακτηριστικό $x_i$ για κάθε $i$ εξαρτάται μόνο από την κλάση $y$ και όχι από οποιοδήποτε άλλο χαρακτηριστικό\n","$$P(x_i | y, x_1, \\dots, x_{i-1}, x_{i+1}, \\dots, x_n) = P(x_i | y)$$\n","αυτό οδηγεί στην απλοποίηση\n","$$P(y \\mid x_1, \\dots, x_n) = \\frac{P(y) \\prod_{i=1}^{n} P(x_i \\mid y)}{P(x_1, \\dots, x_n)}$$\n","Με δεδομένη είσοδο, το $P(x_1, \\dots, x_n)$ είναι σταθερό. Συνεπώς μπορούμε να χρησιμοποιήσουμε τον ακόλουθο κανόνα ταξινόμησης $$P(y \\mid x_1, \\dots, x_n) \\propto P(y) \\prod_{i=1}^{n} P(x_i \\mid y)$$\n","$$\\Downarrow$$\n","$$\\hat{y} = \\arg\\max_y P(y) \\prod_{i=1}^{n} P(x_i \\mid y)$$\n","Το $P(y)$ είναι η υπόθεσή μας και ισούται με τη σχετική συχνότητα της κλάσης $y$ στο training set. To $P(x_i \\mid y)$ είναι η πιθανοφάνεια δηλαδή η πιθανότητα του δείγματος με δεδομένη την υπόθεσή μας και μπορεί επίσης να υπολογιστεί απλά από το training set. Οι διάφοροι Naive Bayes classifiers διαφοροποιούνται κυρίως από τις υποθέσεις που κάνουν ως προς την κατανομή $P(x_i \\mid y)$. Η κλάση $\\hat{y}$ που ανατίθεται σε ένα νέο δείγμα είναι αυτή που μεγιστοποιεί το δεξί μέλος της σχέσης."]},{"cell_type":"markdown","metadata":{"id":"4_GNZAxxNC6u"},"source":["## Ένα παράδειγμα NB με κατηγορικές μεταβλητές\n","\n","Έστω ότι για 14 μέρες παρατηρήσαμε 4 μεταβλητές του καιρού (νεφοκάλυψη, θερμοκρασία, υγρασία και άνεμο) και το αν τελικά παίξαμε τέννις. Τα χαρακτηριστικά μας είναι κατηγορικά, παίρνουν δηλαδή διακριτές τιμές από ενα ορισμένο σύνολο τιμών.\n","\n","| Day | Outlook | Temperature | Humidity | Wind | Play Tennis? |\n","|-----|----------|-------------|----------|--------|--------------|\n","| 1 | Sunny | Hot | High | Weak | No |\n","| 2 | Sunny | Hot | High | Strong | No |\n","| 3 | Overcast | Hot | High | Weak | Yes |\n","| 4 | Rain | Mild | High | Weak | Yes |\n","| 5 | Rain | Cool | Normal | Weak | Yes |\n","| 6 | Rain | Cool | Normal | Strong | No |\n","| 7 | Overcast | Cool | Normal | Strong | Yes |\n","| 8 | Sunny | Mild | High | Weak | No |\n","| 9 | Sunny | Cool | Normal | Weak | Yes |\n","| 10 | Rain | Mild | Normal | Weak | Yes |\n","| 11 | Sunny | Mild | Normal | Strong | Yes |\n","| 12 | Overcast | Mild | High | Strong | Yes |\n","| 13 | Overcast | Hot | Normal | Weak | Yes |\n","| 14 | Rain | Mild | High | Strong | No |"]},{"cell_type":"markdown","metadata":{"id":"tMoHXWhaNC6v"},"source":["Το πρώτο βήμα είναι να γράψουμε 4 πίνακες αναφοράς (\"look-up tables\"), έναν για κάθε χαρακτηριστικό, με την πιθανότητα να παιχτεί ή να μην παιχτεί τέννις σε σχέση με το χαρακτηριστικό. Έχουμε συνολικά 5 περιπτώσεις που δεν μπορέσαμε να παίξουμε και 9 που μπορέσαμε. Οι 4 πίνακες είναι οι ακόλουθοι:\n","\n","| OUTLOOK | Play = Yes | Play = No | Total |\t| TEMPERATURE | Play = Yes | Play = No | Total |\t| HUMIDITY | Play = Yes | Play = No | Total |\t| WIND | Play = Yes | Play = No | Total |\n","|----------|------------|-----------|-------|\t|-------------|------------|-----------|-------|\t|----------|------------|-----------|-------|\t|--------|------------|-----------|-------|\n","| Sunny | 2/9 | 3/5 | 5/14 |\t| Hot | 2/9 | 2/5 | 4/14 |\t| High | 3/9 | 4/5 | 7/14 |\t| Strong | 3/9 | 3/5 | 6/14 |\n","| Overcast | 4/9 | 0/5 | 4/14 |\t| Mild | 4/9 | 2/5 | 6/14 |\t| Normal | 6/9 | 1/5 | 7/14 |\t| Weak | 6/9 | 2/5 | 8/14 |\n","| Rain | 3/9 | 2/5 | 5/14 |\t| Cool | 3/9 | 1/5 | 4/14 |\t| Cool | 3/9 | 1/5 | 4/14 |\t| Cool | 3/9 | 1/5 | 4/14 |\n","και τέλος υπολογίζουμε την πιθανότητα να παίξουμε και να μην παίξουμε:\n","\n","P(Play=Yes) = 9/14\n","\n","P(Play=No) = 5/14\n","\n","### Testing\n","\n","Έστω ένα νέο δείγμα X = (Outlook=Sunny, Temperature=Cool, Humidity=High, Wind=Strong). Σε ποια κατηγορία ανήκει; (θα παίξουμε τέννις ή όχι).\n","\n","Υπολογίζουμε πρώτα από τους πίνακες αναφοράς την \"πιθανότητα\" να παίξουμε\n","\n","* P(Outlook=Sunny | Play=Yes) = 2/9\n","* P(Temperature=Cool | Play=Yes) = 3/9\n","* P(Humidity=High | Play=Yes) = 3/9\n","* P(Wind=Strong | Play=Yes) = 3/9\n","* P(Play=Yes) = 9/14\n","\n","Σύμφωνα με τον κανόνα ταξινόμησης του NB η πιθανότητα να παίξουμε είναι ανάλογη του γινομένου των προηγούμενων \n","\n","P(X|Play=Yes)P(Play=Yes) = (2/9) \\* (3/9) \\* (3/9) \\* (3/9) \\* (9/14) = 0.0053\n","\n","Υπολογίζουμε παρόμοια την \"πιθανότητα\" να μην παίξουμε\n","\n","* P(Outlook=Sunny | Play=No) = 3/5\n","* P(Temperature=Cool | Play=No) = 1/5\n","* P(Humidity=High | Play=No) = 4/5\n","* P(Wind=Strong | Play=No) = 3/5\n","* P(Play=No) = 5/14\n","\n","P(X|Play=No)P(Play=No) = (3/5) \\* (1/5) \\* (4/5) \\* (3/5) \\* (5/14) = 0.0206\n","\n","Επειδή η ποσότητα 0.0206 είναι μεγαλύτερη από την 0.0053, η απόφαση του Naive Bayes είναι να μην παίξουμε τέννις. Οι ποσότητες αυτές (του αριθμητή) μας αρκούν για την απόφαση γιατί ο παρονομαστής είναι σταθερός. Για να πάρουμε τις πλήρεις πιθανότητες για το συγκεκριμένο δείγμα Χ υπολογίζουμε και τον παρονομαστή:\n","\n","* P(X) = P(Outlook=Sunny) \\* P(Temperature=Cool) \\* P(Humidity=High) \\* P(Wind=Strong)\n","* P(X) = (5/14) \\* (4/14) \\* (7/14) \\* (6/14)\n","* P(X) = 0.02186\n","\n","* P(Play=Yes | X) = 0.0053/0.02186 = 0.2425\n","* P(Play=No | X) = 0.0206/0.02186 = 0.9424\n","\n","Γιατί δεν αθροίζουν στην μονάδα;\n","![](https://i.imgur.com/lSWnEMC.png)"]},{"cell_type":"markdown","metadata":{"id":"zqVEooVDNC6w"},"source":["Θέλουμε να δοκιμάσουμε τον Naive Bayes στο Wisconsin. Εδώ όμως έχουμε συνεχείς μεταβλητές. Όπως είπαμε θα πρέπει να κάνουμε μια υπόθεση για την κατανομή $P(x_i \\mid y)$. Θα θεωρήσουμε ότι η κατανομή κάθε χαρακτηριστικού ως προς κάθε κλάση ακολουθεί την κανονική κατανομή:\n","$$P(x_i \\mid y) = \\frac{1}{\\sqrt{2\\pi\\sigma^2_y}} \\exp\\left(-\\frac{(x_i - \\mu_y)^2}{2\\sigma^2_y}\\right)$$\n","Ο συγκεκριμένος ταξινομητής είναι ο Gaussian Naive Bayes. Πρακτικά, με τα δεδομένα του training set, για κάθε κλάση υπολογίζουμε τη μέση τιμή $\\mu_y$ και τη διακύμανση $\\sigma^2_y$ κάθε χαρακτηριστικού για τη συγκεκριμένη κλάση. \n","Πρακτικά, όσο πιο κοντά στη μέση τιμή του (ως προς το σύνολο του train set)είναι ένα χαρακτηριστικό ενός δείγματος, τόσο πιο κοντά στη μοναδα θα είναι η πιθανοφάνια του χαρκτηριστικού και αντιθετοαντίστροφα.\n","\n","Ας δοκιμάσουμε τον Gaussian Naive Bayes στο Wisconsin:"]},{"cell_type":"code","metadata":{"id":"7u7DytKBNC6x","trusted":true},"source":["from sklearn.naive_bayes import GaussianNB\n","gnb = GaussianNB()\n","# κάνουμε εκπαίδευση (fit) δηλαδή ουσιαστικά υπολογίζουμε μέση τιμή και διακύμανση για όλα τα χαρακτηριστικά και κλάσεις στο training set\n","model = gnb.fit(train, train_labels)\n","# η GaussianNB έχει builtin μέθοδο υπολογισμό accuracy. Αποθηκεύουμε την τιμή της στον πίνακά μας με τα αποτελέσματα από τα άλλα classifiers\n","wisconsin_accuracy['gaussian naive bayes'] = gnb.score(test, test_labels)\n","# και ξανατυπώνουμε τα sorted αποτελέσματα\n","print(\"Classification Accuracy on the Wisconsin Breast Cancer Dataset (33% test set)\\n\")\n","sorted_accuracy = [(k, wisconsin_accuracy[k]) for k in sorted(wisconsin_accuracy, key=wisconsin_accuracy.get, reverse=True)]\n","for k, v in sorted_accuracy:\n"," print(k,v)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"8xPMzJn6NC61"},"source":["# Εισαγωγή dataset μέσω Pandas και CSV file\n","\n","To scikit learn έχει διαθέσιμο για φόρτωση απευθείας με συναρτήσεις μόνο ένα μικρό αριθμό datasets. Στη γενική περίπτωση, η τυπική διαδικασία για εισαγωγή datasets που θα συναντήσουμε είναι να διαβάζουμε ένα delimited text file (τιμές που διαχωρίζονται με ένα delimiter δλδ comma -Comma Separated Values, CSV-, semicolon etc) και να το αποθηκεύουμε σε πίνακες χαρακτηριστικών και ετικετών (class labels). \n","\n","Θα κάνουμε την προηγούμενη διαδικασία manually διαβάζοντας το breast cancer από text file. Η σελίδα του UCI για το breast cancer είναι [αυτή](https://archive.ics.uci.edu/ml/datasets/Breast+Cancer+Wisconsin+%28Diagnostic%29), και το dataset μπορούμε να το αποθηκεύσουμε locally στο Desktop απο το φάκελο \"Data Folder\" και το αρχείο [\"wdbc.data\"](https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data). Το ανοίγουμε, δεξί κλικ και \"Save as\" (ή απευθείας \"Save link as\"). \n","\n","**ΠΡΟΣΟΧΗ: Ανάλογα το cloud οι διαδικασία εισαγωγής (και εξαγωγής) δεδομένων είναι διαφορετική.**\n","\n","Παρακαλούμε να έχετε μια εξοικίωση και με τις τρεις πλατφόρμες, μπορεί να τις χρειαστούμε όλες."]},{"cell_type":"markdown","metadata":{"id":"5Cgmq3aXfhdN"},"source":["## 1. Google Colaboratory\n","\n","Κάντε expand το αριστερό sidebar, πηγαίνετε στο tab \"Files\" και στο UPLOAD διαλέγουμε το αρχείο \"wbcd.data\". Κάνουμε \"ΟΚ\" στο reminder ότι τα αρχεία θα διαγραφούν."]},{"cell_type":"markdown","metadata":{"id":"Nl-J6kAxhQdA"},"source":["Το αρχείο \"wdbc.data\" πρέπει να βρίσκεται στο file system:"]},{"cell_type":"code","metadata":{"id":"dF4rNf84hWdW","trusted":true,"scrolled":false},"source":["!ls"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"6FB_8hY11Qat"},"source":["Εισάγουμε και διαβάζουμε το csv \"wdbc.data\" με την read_csv και option \"header=None\" γιατί η πρώτη γραμμή περιέχει δεδομένα και όχι ονόματα κολόνων και τυπώνουμε τις πρώτες πέντε γραμμές:"]},{"cell_type":"code","metadata":{"trusted":true,"id":"_0C5rsqp1Qat"},"source":["import pandas as pd\n","\n","df = pd.read_csv(\"wdbc.data\", header=None)\n","df"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"h2AMxWYx1Qa3"},"source":["## 2. Kaggle\n","\n","1. Διαλέξτε πάνω δεξιά \"Add Data\", μετά \"Upload\" και με \"Select Files to Upload\" (ή με drag'n'drop) ανεβάστε το αρχείο CSV (στην περίπτωσή μας το \"wdbc.data\"). \n","2. Στο πεδίο title βάλτε \"wdbc.data\" (χωρίς τα εισαγωγικά) και πατήστε \"Create\". Επειδή το αρχείο (το dataset) είναι ήδη διαθέσιμο στο repository του Kaggle, δεν θα μας αφήσει να το ανεβάσουμε (\"This file already exists in dataset Breast-Cancer Diagnosis open_in_new. Consider removing it and using the existing data source.\"\n","3. Καντε Esc και Confirm για να βγούμε στο notebook. Πηγαίντε πάλι στο \"Add data\" και στο \"Search Datasets\" γραψτε \"wisconsin\". Επιλέξτε το \"Breast Cancer Wisconsin (Diagnostic) Data Set\" και κάντε add.\n","\n","Το dataset θα μπει στο file system, στο directory \"input\" το οποίο είναι στο ίδιο ύψος με αυτό του notebook στο filesystem:"]},{"cell_type":"code","metadata":{"trusted":true,"id":"qEP7pbb91Qa3"},"source":["!ls ../input"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"oROghpIp1Qa6"},"source":["Εισάγουμε και διαβάζουμε το csv \"wdbc.data\" μέσα από το directory \"wdbcdata\" με την read_csv και option \"header=None\" γιατί η πρώτη γραμμή περιέχει δεδομένα και όχι ονόματα κολόνων και τυπώνουμε τις πρώτες πέντε γραμμές:\n","\n"]},{"cell_type":"code","metadata":{"trusted":true,"id":"e3jmeZb_1Qa7"},"source":["import pandas as pd\n","\n","df = pd.read_csv(\"../input/breast-cancer-wisconsin-data/data.csv\")\n","df.head()"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"D0nCGgb6pJ1T"},"source":["Φυσικά μπορούμε να ανεβάσουμε κανονικά datasets που δεν υπάρχουν στο αποθετήριο."]},{"cell_type":"markdown","metadata":{"id":"Yuoy1EZa1Qa8"},"source":["## 3. JetBrains Datalore\n","\n","1. Πηγαίνετε στο συνδετήρα (\"attached files\")\n","2. Κάντε drag'n'drop το αρχείο csv στο αριστερό pane, μεσα στο attached files."]},{"cell_type":"code","metadata":{"scrolled":true,"trusted":true,"id":"ZbcfeHLb1Qa-"},"source":["import pandas as pd\n","\n","df = pd.read_csv(\"wdbc.data\", header=None)\n","df.head()"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"WMSwMFdB1QbA"},"source":["# Μετατροπή δεδομένων σε numpy array"]},{"cell_type":"markdown","metadata":{"id":"MbrNcOcFNC64"},"source":["Στο \"Data folder\" του UCI εκτός του \"wdbc.data.txt\" έχει και το [\"wdbc.names\"](https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.names) με τις ονομασίες των features. Έχουμε 32 attributes, το πρώτο είναι το ID του δείγματος, το δεύτερο η διάγνωση (\"Μ\" για malignant και \"B\" για benign) και τέλος 30 real-valued χαρακτηριστικά εισόδου. Θα αποθηκεύσουμε τη δεύτερη κολώνα (διάγνωση) σε ένα dataframe \"labels_df\" και τα αριθμητικά features σε ένα dataframe \"features_df\". Το sample ID στην πρώτη κολώνα δεν μας ενδιαφέρει. Ακολουθούμε πάντα τη διαδικασία του διαχωρισμού σε διαφορετικά dataframes όταν τα attributes είναι διαφορετικών data types (όπως εδώ που έχουμε string για την κλάση και float για τα υπόλοιπα χαρακτηριστικά), γιατί αλλιώς δυσκολεύει η μετατροπή σε numpy array που θα κάνουμε στη συνέχεια."]},{"cell_type":"code","metadata":{"id":"Klu_WNOFtfQi"},"source":["!cat wdbc.data"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"scrolled":true,"id":"1D6TgwjpNC65","trusted":true},"source":["import pandas as pd\n","import numpy as np\n","\n","df = pd.read_csv(\"wdbc.data\", header=None)\n","df.head()\n","\n","labels_df = df.iloc[:, [1]] # τα labels είναι στη δεύτερη κολώνα\n","features_df = df.iloc[:, 2:] # τα features είναι όλες οι επόμενες κολονες\n","# και δεν μας ενδιαφέρουν τα ids στην πρώτη\n","\n","# μετατρέπουμε το dataframe σε numpy array\n","np_features = features_df.values\n","\n","print(np_features[0]) #τυπώνουμε το πρώτο δείγμα\n","print(np_features.shape) #τυπώνουμε τις διαστάσεις του πίνακα των χαρακτηριστικών\n","# επιβεβαιώνουμε ότι ο αρχικός πίνακας features ναι ίδιος με τον np_features\n","print(np.array_equal(features_df, np_features))\n","print(np_features - features_df)\n","# είναι ίδιοι πρακτικά, απλά ο np_features έχει λίγο μεγαλύτερο precision "],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"6JiB5LnqNC68"},"source":["Στο dataframe - κολώνα με τις κλάσεις \"labels_df\" πρέπει να μετατρέψουμε τα string 'M' και 'Β' σε 0 και 1 αντίστοιχα. Ορίζουμε ένα mapping και εφαρμόζουμε τη μέθοδο replace με το συγκεκριμένο mapping. \n","\n","Τέλος, αν εφαρμόσουμε μόνο τη μέθοδο \"values\" στο \"labels_df\" θα πάρουμε ένα np array δύο διαστάσεων (569, 1), ενώ θέλουμε να είναι μονοδιάστατος (569,). Για το λόγο αυτό εφαρμόζουμε επιπρόσθετα τη μέθοδο flatten(). Επιβεβαιώνουμε ότι ο αρχικός πίνακας labels είναι ίδιος με τον np_labels."]},{"cell_type":"code","metadata":{"id":"XVpk3OM_NC68","trusted":true},"source":["mapping = {'M': 0, 'B': 1}\n","labels_df = labels_df.replace({\"1\": mapping}) #βρίσκονται στην κολόνα \"1\". Το \"1\" εδώ είναι όνομα, όχι αριθμός.\n","np_labels = labels_df.values.flatten()\n","\n","# επιβεβαιώνουμε ότι ο αρχικός πίνακας labels είναι ίδιος με τον np_labels\n","print(np_labels)\n","print(np_labels.shape)\n","print(np.array_equal(labels_df, np_labels))"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"o5NFqcEouD9i"},"source":[""],"execution_count":null,"outputs":[]}]}