{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Classification 1.2 bias variance - knn - crossvalidation","provenance":[],"toc_visible":true},"kernelspec":{"name":"python3","display_name":"Python 3"}},"cells":[{"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":{"collapsed":true,"id":"8zR-sydoN4o5"},"source":["# Παραμετρικοί και μη-παραμετρικοί ταξινομητές, bias - variance trade-off\n","\n","![](https://miro.medium.com/max/500/1*1jV03DHuQeVkdzUKrwmX4w.png)\n","\n","O Gaussian Naive Bayes είναι ένας παραμετρικός ταξινομητής. Οι παραμετρικοί ταξινομητές κάνουν κάποια υπόθεση για την κατανομή (των χαρακτηριστικών) των δεδομένων και την προσδιορίζουν μέσω παραμέτρων. Στην περίπτωση του Gaussian Naive Bayes, η υπόθεση είναι η κανονική κατανομή και οι παράμετροι είναι τα $μ$ και $σ^2$ των χαρακτηριστικών. Αντίθετα, οι μη-παραμετρικές μέθοδοι δεν κάνουν καμία υπόθεση για την κατανομή των δεδομένων. Προσοχή: και οι μη-παραμετρικοί ταξινομητές έχουν παραμέτρους (και πάρα πολλές σε ορισμένες περιπτώσεις, τα βάρη των νευρωνικών για παράδειγμα) που επηρ\n","εάζουν τη λειτουργία τους αλλά δεν σχετίζονται με κάποια υπόθεση κατανομής για τα δεδομένα. \n","\n","Σε γενικές γραμμές οι παραμετρικοί ταξινομητές είναι απλούστεροι, ταχύτεροι στις φάσεις train/test και χρειάζονται λιγότερα δεδομένα εκπαίδευσης. Από την άλλη, έχουν γενικά μικρότερη χωρητικότητα (capacity), δηλαδή μπορούν να διαχωρίσουν τις κλάσεις σε προβλήματα σχετικά μικρότερων διαστάσεων ενώ η απαίτηση τα πραγματικά δεδομένα να ακολουθούν μια ακριβή κατανομή είναι πολύ ισχυρή και δεν επαληθεύεται πρακτικά. Αντιστρόφως, οι μη παραμετρικοί ταξινομητές είναι πιο αργοί στην εκπαίδευση, έχουν γενικά μεγαλύτερες απαιτήσεις χώρου/μνήμης και χρειάζονται περισσότερα δεδομένα αλλά έχουν μεγαλύτερη χωρητικότητα, μπορούν να μάθουν δυσκολότερα προβλήματα και να έχουν καλύτερη απόδοση σε μεγαλύτερα datasets. \n","\n","Οι μη παραμετρικοί ταξινομητές μπορούν να εμφανίσουν επίσης εντονότερα το πρόβλημα της υπερεκπαίδευσης (overfitting), δηλαδή να προσαρμοστούν υπερβολικά στα δεδομένα εκπαίδευσης και να μειωθεί η ικανότητα γενίκευσης (generalisation) τους σε νέα δείγματα. Γενικά στη φάση της εκπαίδευσης προσπαθούμε να επιτύχουμε μια καλή ισορροπία μεταξυ της απόκλισης (bias) και της διακύμανσης (variance) από τις πραγματικές τιμές.\n","\n","![Bias-Variance trade off](https://cdn-images-1.medium.com/proxy/1*e4Kn-_M_KN2bw-e6kevywA.png \"Bias-Variance trade off\")\n","\n","\n","Ένα παράδειγμα μη-παραμετρικού ταξινομητή που θα εξετάσουμε είναι ο kNN (k-Nearest-Neighbours). "]},{"cell_type":"markdown","metadata":{"collapsed":true,"id":"4ZdyhJaEN4o8"},"source":["# k Nearest Neighbors Classifier (kNN)\n","O kNN είναι ένας μη παραμετρικός ταξινομητής βασισμένος σε παραδείγματα (instance-based). Η αρχή λειτουργίας του είναι πολύ απλή. Για ένα νέο δείγμα προς ταξινόμηση, πρώτα υπολογίζουμε τους k πλησιέστερους γείτονές του (στον ν-διάστατο χώρο των χαρακτηριστικών εισόδου) με βάση κάποια συνάρτηση απόστασης, συνήθως ευκλείδεια\n","$$d(x, x') = \\sqrt{\\left(x_1 - x'_1 \\right)^2 + \\left(x_2 - x'_2 \\right)^2 + \\dotsc + \\left(x_n - x'_n \\right)^2}$$\n","Η κλάση του νέου δείγματος θα είναι η κλάση της πλειοψηφίας των k γειτόνων (διαλέγουμε k περιττό γενικά), είτε απλά υπολογισμένη (άθροισμα) είτε (αντίστροφα) ζυγισμένη με βάση την απόσταση του κάθε γείτονα. \n","\n","Ο kNN δεν έχει πρακτικά φάση εκπαίδευσης. Ωστόσο, για να ταξινομήσουμε ένα νέο δείγμα στην φάση test, πρέπει να συγκρίνουμε την απόστασή του με κάθε δείγμα του train set. Αυτό σημαίνει ότι για την ταξινόμηση είναι απαραίτητα όλα τα δείγματα εκπαίδευσης (εξού και η ονομασία \"instance-based\", ενώ στον Naive Bayes χρειαζόμαστε μόνο τις παραμέτρους $μ$ και $σ^2$). Αυτό σημαίνει ότι ο kNN είναι πιο απαιτητικός και σε χώρο (αποθήκευση όλων των δειγμάτων) και σε χρόνο (υπολογισμός όλων των αποστάσεων για κάθε νέο δείγμα).\n","# Υπερπαράμετρος k\n","Το k της γειτονιάς του kNN είναι μια υπερπαράμετρος του ταξινομητή. Μια άλλη υπερπαράμετρος για παράδειγμα είναι η συνάρτηση της απόστασης. Οι υπερπαράμετροι είναι επιλογές που γίνονται από τον σχεδιαστή του συστήματος και δεν μπορούμε να ξέρουμε τις βέλτιστες τιμές τους αν πρώτα δεν τις αξιολογήσουμε εμπειρικά σε δεδομένα. Ένα άλλο παράδειγμα υπερπαραμέτρου είναι ο αριθμός των κρυφών νευρώνων σε ένα MLP. Στην περίπτωση του kNN το k ελέγχει το trade-off μεταξύ μεταξύ απόκλισης και διακύμνανσης.\n","\n","Έαν θέσουμε μικρό k, πχ k=1 παίρνουμε ένα ταξινομητή με υψηλή διακύμανση και χαμηλή απόκληση. Ο ταξινομητής τείνει να αγνοεί τη συνολική κατανομή και αποφασίζει μόνο από το κοντινότερο δείγμα. Στην περίπτωση k=1 το σύνορο απόφασης (decision boundary) περνά από τις μεσοκάθετους γειτονικών δειγμάτων διαφορετικής κλάσης. \n","\n","![kNN k=1](https://i.stack.imgur.com/UG81y.png \"kNN with k=1\")\n","\n","Αν διαλέξουμε μεγαλύτερο k, φτιάχνουμε ένα ταξινομητή με χαμηλότερη διακύμανση και υψηλότερη απόκλιση. Θα ταξινομίσει λάθος περισσότερα αποκλίνοντα δείγματα (outliers) αλλά θα σέβεται περισσότερο τη συνολική κατανομή.\n","![kNN k=20](https://i.stack.imgur.com/FZITG.png \"kNN with k=20\")\n","\n","# Το Iris dataset\n","Για να μελετήσουμε τον kNN, θα φορτώσουμε το dataset [\"Iris\"](https://archive.ics.uci.edu/ml/datasets/Iris). Το Iris είναι το διασημότερο dataset στο Machine Learning. Το χρησιμοποίησε πρώτος το 1936 ο διάσημος στατιστικός [Ronald Fisher](https://en.wikipedia.org/wiki/Ronald_Fisher) και αποτελείται από 50 παρατηρήσεις για κάθε είδος του άνθους Iris (Iris setosa, Iris virginica και Iris versicolor). Για κάθε δείγμα μετρήθηκαν 4 χαρακτηριστικά: το πλάτος και το μήκος των πετάλων και των σεπάλων.\n","\n","![Iris petals & sepals](https://www.integratedots.com/wp-content/uploads/2019/06/iris_petal-sepal-e1560211020463.png \"Iris petals & sepals\")\n","\n","Σημειώστε ότι με το Iris και τρεις κατηγορίες και άρα έχουμε multiclass και όχι binary classification. Εισάγουμε το Iris στο notebook."]},{"cell_type":"code","metadata":{"id":"z1uirGVkN4o-","executionInfo":{"status":"ok","timestamp":1634651023689,"user_tz":-180,"elapsed":464,"user":{"displayName":"Giorgos Siolas","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjxnZOAObbc3X0z9X2rs1N_1geznqhrotkq3KF-p_M=s64","userId":"10127542075805046236"}}},"source":["# Load Iris and organize our data\n","from sklearn.datasets import load_iris\n","data = load_iris()\n","label_names = data['target_names']\n","labels = data['target']\n","feature_names = data['feature_names']\n","features = data['data']"],"execution_count":1,"outputs":[]},{"cell_type":"code","metadata":{"id":"KSoLp7_UN4pB","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1634650464009,"user_tz":-180,"elapsed":403,"user":{"displayName":"Giorgos Siolas","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjxnZOAObbc3X0z9X2rs1N_1geznqhrotkq3KF-p_M=s64","userId":"10127542075805046236"}},"outputId":"0d30a0a8-7403-44cb-f489-4a484300fa7d"},"source":["# Ας τυπώσουμε τα ονόματα των χαρκτηριστικών\n","print(feature_names)\n","print(label_names)"],"execution_count":2,"outputs":[{"output_type":"stream","name":"stdout","text":["['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']\n","['setosa' 'versicolor' 'virginica']\n"]}]},{"cell_type":"code","metadata":{"id":"HIZ_g3-MN4pG","executionInfo":{"status":"ok","timestamp":1634651028780,"user_tz":-180,"elapsed":439,"user":{"displayName":"Giorgos Siolas","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjxnZOAObbc3X0z9X2rs1N_1geznqhrotkq3KF-p_M=s64","userId":"10127542075805046236"}}},"source":["# Χρησιμοποιούμε τη γνωστή train_test_split για να διαχωρίσουμε σε train και test set\n","# το (int) όρισμα \"random_state\" είναι το seed της γεννήτριας τυχαίων αριθμών\n","import numpy as np\n","from sklearn.model_selection import train_test_split\n","X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.40, random_state=78)"],"execution_count":2,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"m0D806YqN4pJ"},"source":["Διαλέγουμε τυχαία τιμή 5 για την υπερπαράμετρο k, εκπαιδεύουμε ένα kNN classifier και υπολογίζουμε την πιστότητα του στο Iris, στο προηγούμενο train/test split"]},{"cell_type":"code","metadata":{"id":"X1vVA6_zN4pK","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1634651033572,"user_tz":-180,"elapsed":456,"user":{"displayName":"Giorgos Siolas","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjxnZOAObbc3X0z9X2rs1N_1geznqhrotkq3KF-p_M=s64","userId":"10127542075805046236"}},"outputId":"03de0321-8084-4dcc-c5fa-a920c667d849"},"source":["from sklearn.neighbors import KNeighborsClassifier\n","from sklearn.metrics import accuracy_score\n","knn = KNeighborsClassifier(n_neighbors=1)\n","knn.fit(X_train, y_train)\n","pred = knn.predict(X_test)\n","print(accuracy_score(y_test, pred))"],"execution_count":3,"outputs":[{"output_type":"stream","name":"stdout","text":["0.9666666666666667\n"]}]},{"cell_type":"markdown","metadata":{"id":"zc4Mx50nN4pO"},"source":["# Ρύθμιση υπερπαραμέτρων με διασταυρούμενη επικύρωση (Cross Validation)\n","\n","![](https://cdn.sstatic.net/Sites/stats/Img/apple-touch-icon.png?v=8698dcfb5c72)\n","\n","[Cross Validated Website](https://stats.stackexchange.com/)\n","\n","Ένας σωστός τρόπος για να βρούμε τη βέλτιστη τιμή του k, να πραγματοποιήσουμε δηλαδή επικύρωση του μοντέλου, είναι ο ακόλουθος. Για k=1 μέχρι k=κάποιο n, κάνουμε fit τον ταξινομητή στο train set και μετράμε την απόδοση στο test set. Ο ταξινομητής με k που δίνει το μικρότερο σφάλμα ταξιμόνόμησης σύμφωνα με κάποιο κριτήριο (εδώ η πιστότητα) στο test set θα είναι ο βέλτιστος. Όμως, αν ακολουθήσουμε αυτή τη στρατηγική, ουσιαστικά κάνουμε υπερεκπαίδευση, καθώς χρησιμοποιούμε το test set ως training set, δηλαδή βελτιστοποιούμε κάποιο κριτήριο σφάλματος πάνω στο test set. Αυτό μπορεί να είναι επιβλαβές για την ικανότητα γενίκευσης του ταξινομητή: το test set χρησιμεύει μόνο για την τελική εκτίμηση της απόδοσης του ταξινομητή.\n","\n","Για να ακολουθήσουμε σωστά το πρωτόκολλο, αυτό που πρέπει να κάνουμε είναι να χρησιμοποιήσουμε μόνο το πραγματικό training set για να διαλέξουμε τις βέλτιστες υπερπαραμέτρους. Θα μπορούσαμε να κρατήσουμε ένα ποσοστό δειγμάτων ως σύνολο επικύρωσης (validation set πχ άλλο ένα 1/3) του training set και να ακολουθήσουμε την προηγούμενη διαδικασία: εκπαίδευση στο 1/3 training set, επικύρωση σε 1/3 και τελικά αξιολόγηση στο 1/3 data set. Ωστόσο αυτή η μεθοδολογία \"αχρηστεύει\" μεγάλο μέρος του dataset (τα 2/3) ως προς την εκπαίδευση του ταξινομητή. Πρακτικά λοιπόν, προτιμούμε να χρησιμοποιούμε τη μέθοδο της διασταυρούμενης επικύρωσης (Cross Validation).\n","\n","Στο Cross Validation αρχικά χωρίζουμε το training set σε έναν αριθμό \"πτυχών\" (folds). Συνηθισμένες τιμές είναι το 5 και το 10 (5-fold και 10-fold CV). Στη συνέχεια, για κάθε k-fold (άσχετο από το k του kNN), θεωρούμε ότι τα k μείον 1 folds είναι training set και ότι το fold που αφήσαμε έξω είναι το test set. Υπολογίζουμε τη μετρική σφάλματός μας στο test set που ορίζει το fold. Επαναλαμβάνουμε τη διαδικασία για τα k folds για κάθε τιμή των υπερπαραμέτρων και υπολογίζουμε τη μέση τιμή της μετρικής του σφάλματος. Με αυτό τον τρόπο, αφενός είμαστε αμερόληπτοι στην αξιολόγηση αφήνοντας τελείως έξω το test set και αφετέρου χρησιμοποιούμε αποτελεσματικά τα δεδομένα εκπαίδευσης: τα χρησιμοποιούμε όλα και παίρνοντας τη μέση τιμή εξαλείφουμε πιθανές ανωμαλίες στα δεδομένα.\n","\n","![Cross validation](https://sebastianraschka.com/images/faq/evaluate-a-model/k-fold.png \"Cross Validation\")\n","\n","To Scikit Learn έχει συναρτήσεις για να κάνει αυτόματα cross validation (να ορίζει folds και να υπολογίζει τιμές και μέσους όρους). Θα κάνουμε 5 fold cross validation για να υπολογίσουμε το βέλτιστο k του kNN στο Iris."]},{"cell_type":"code","metadata":{"id":"3q1krR5RN4pO","executionInfo":{"status":"ok","timestamp":1634651040942,"user_tz":-180,"elapsed":504,"user":{"displayName":"Giorgos Siolas","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjxnZOAObbc3X0z9X2rs1N_1geznqhrotkq3KF-p_M=s64","userId":"10127542075805046236"}}},"source":["from sklearn.model_selection import cross_val_score\n","from sklearn.neighbors import KNeighborsClassifier\n","\n","# φτιάχνουμε μια λίστα από το 1 έως το 50\n","myList = list(range(1,50))\n","# Κρατάμε μόνο τα περιττά k\n","neighbors = list(filter(lambda x: x % 2 != 0, myList))\n","# empty list that will hold cv scores\n","cv_scores = []\n","# perform 5-fold cross validation\n","for k in neighbors:\n"," knn = KNeighborsClassifier(n_neighbors=k)\n"," scores = cross_val_score(knn, X_train, y_train, cv=5, scoring='accuracy')\n"," cv_scores.append(scores.mean())"],"execution_count":4,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"6Usr5iw5N4pR"},"source":["Θα τυπώσουμε την τιμή του σφάλματος σε γραφική παράσταση ως συνάρτηση του k για το training set, και την τιμή της πιστότητας στο test set για το βέλτιστο k (υπολογισμένο στο training set)"]},{"cell_type":"code","metadata":{"id":"U7izRFzIPZHU","colab":{"base_uri":"https://localhost:8080/","height":425},"executionInfo":{"status":"ok","timestamp":1634650974441,"user_tz":-180,"elapsed":15558,"user":{"displayName":"Giorgos Siolas","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjxnZOAObbc3X0z9X2rs1N_1geznqhrotkq3KF-p_M=s64","userId":"10127542075805046236"}},"outputId":"e1bef449-fb85-46fb-a244-84c00188eedb"},"source":["# Κάνουμε update την matplotlib, ίσως χρειαστεί restart του runtime\n","!pip install --upgrade matplotlib"],"execution_count":7,"outputs":[{"output_type":"stream","name":"stdout","text":["Requirement already satisfied: matplotlib in /usr/local/lib/python3.7/dist-packages (3.2.2)\n","Collecting matplotlib\n"," Downloading matplotlib-3.4.3-cp37-cp37m-manylinux1_x86_64.whl (10.3 MB)\n","\u001b[K |████████████████████████████████| 10.3 MB 8.3 MB/s \n","\u001b[?25hRequirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.7/dist-packages (from matplotlib) (2.8.2)\n","Requirement already satisfied: numpy>=1.16 in /usr/local/lib/python3.7/dist-packages (from matplotlib) (1.19.5)\n","Requirement already satisfied: pyparsing>=2.2.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib) (2.4.7)\n","Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib) (1.3.2)\n","Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.7/dist-packages (from matplotlib) (7.1.2)\n","Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib) (0.10.0)\n","Requirement already satisfied: six in /usr/local/lib/python3.7/dist-packages (from cycler>=0.10->matplotlib) (1.15.0)\n","Installing collected packages: matplotlib\n"," Attempting uninstall: matplotlib\n"," Found existing installation: matplotlib 3.2.2\n"," Uninstalling matplotlib-3.2.2:\n"," Successfully uninstalled matplotlib-3.2.2\n","\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n","albumentations 0.1.12 requires imgaug<0.2.7,>=0.2.5, but you have imgaug 0.2.9 which is incompatible.\u001b[0m\n","Successfully installed matplotlib-3.4.3\n"]},{"output_type":"display_data","data":{"application/vnd.colab-display-data+json":{"pip_warning":{"packages":["matplotlib","mpl_toolkits"]}}},"metadata":{}}]},{"cell_type":"code","metadata":{"id":"TiB323l-N4pS","colab":{"base_uri":"https://localhost:8080/","height":330},"executionInfo":{"status":"ok","timestamp":1634651048492,"user_tz":-180,"elapsed":437,"user":{"displayName":"Giorgos Siolas","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GjxnZOAObbc3X0z9X2rs1N_1geznqhrotkq3KF-p_M=s64","userId":"10127542075805046236"}},"outputId":"8e06478a-d5b8-4186-e540-e699aafe8941"},"source":["# Κάνουμε import την matplotplib\n","import matplotlib.pyplot as plt\n","\n","# το σφάλμα είναι το αντίστροφο της πιστότητας\n","mean_error = [1 - x for x in cv_scores]\n","\n","# plot misclassification error vs k\n","plt.plot(neighbors, mean_error)\n","plt.xlabel('Number of Neighbors K')\n","plt.ylabel('Misclassification Error')\n","plt.show()\n","\n","# determining best k\n","optimal_k = neighbors[mean_error.index(min(mean_error))]\n","print(\"The optimal number of neighbors (calculated in the training set) is %d\" % optimal_k)\n","\n","# για το optimal k παίρνουμε και τα αποτέλεσματα στο test set\n","knn = KNeighborsClassifier(n_neighbors = optimal_k)\n","knn.fit(X_train, y_train)\n","pred = knn.predict(X_test)\n","print(\"\\nOptimal accuracy on the test set is\", accuracy_score(y_test, pred), \"with k=\", optimal_k)"],"execution_count":5,"outputs":[{"output_type":"display_data","data":{"image/png":"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\n","text/plain":["
"]},"metadata":{"needs_background":"light"}},{"output_type":"stream","name":"stdout","text":["The optimal number of neighbors (calculated in the training set) is 5\n","\n","Optimal accuracy on the test set is 0.9833333333333333 with k= 5\n"]}]},{"cell_type":"markdown","metadata":{"id":"E_vqjGz4HYFm"},"source":["👉 Δεν είναι απαραίτητο ότι η καλύτερη τιμή της υπερπαραμέτρου που βρίσκουμε θα έχει τη βέλτιστη απόδοση στο test set, αλλά είμαστε σίγουροι ότι θα είναι μια πολύ καλή τιμή - κοντά στη βέλτιστη."]},{"cell_type":"markdown","metadata":{"id":"T7MDvQnDDBo4"},"source":["# Η διαδίκασία επικύρωσης μοντέλων\n","\n","## train - validation - test\n","\n","Θεωρούμε ότι έχουμε αρκετά (πολλά) δείγματα. Αν δεν έχουμε πολλά δείγματα δεν μπορούμε να κάνουμε μηχανική μάθηση.\n","\n","![](https://scikit-learn.org/stable/_static/ml_map.png) [interactive map](https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html)\n","\n","Αν ανακατέψουμε τη σειρά των δειγμάτων και χωρίσουμε το dataset σε σχετικά μεγάλα κομάτια (2 ή 3), πιστεύουμε (ελπίζουμε) με αρκετή βεβαιότητα ότι η κατανομή των ετικετών και των τιμών των χαρακτηριστικών σε κάθε κομάτι θα είναι η ίδια με του συνολικού dataset.\n","\n","Διαχωρίζουμε άπαξ τα δεδομένα σε δεδομένα εκπαίδευσης (train set) και ελέγχου (test set). Γενικά το train set είναι μεγαλύτερο από το test set πχ 70%-30% (αυτό εξαρτάται από τα δεδομένα).\n","\n","Το test set θα χρησιμοποιηθεί μόνο στο τέλος για την εκτίμηση της γενίκευσης, δεν το αγκίζουμε στην εκπαίδευση.\n","\n","Το train set μπορούμε να το χρησιμποιήσουμε ολόκληρο για cross validation (οπότε έχουμε δύο σύνολα, το train και το test - Σχήμα Α) για την εύρεση των βέλτιστων υπερπαραμέτρων. Είναι το συνηθέστερο γιατί χρησιμοποιεί όλα τα δεδομένα του train. \n","\n","Αφού καταλήξουμε στις βέλτιστες υπερπαραμέτρους χρησιμοποιούμε ολόκληρο το train set για την εκπαίδευση (if applicable).\n","\n","Σε περιπτώσεις που δεν θα κάνουμε crossvalidation για εύρεση υπερπαραμέτρων (πχ deep learning) χωρίζουμε εκ νέου το train set σε train set και validation set (Σχήμα Β).\n","\n","![](https://upload.wikimedia.org/wikipedia/commons/b/bb/ML_dataset_training_validation_test_sets.png)\n","\n","Ποια είναι διαφορά train και validation στο Β:\n","- κατά την εκπαίδευση το σφάλμα στο train set χρησιμοποιείται για την επίβλεψη και διόρθωση των βαρών του ταξινομητή\n","- το σφάλμα στο validation χρησιμοποιείται για να έχουμε μια εκτίμηση της γενίκευσης αλλά δεν χρησιμοποιείται για την διόρθωση των βαρών. Αν το σφάλμα στο train set μικραίνει και στο validation set μεγαλώνει έχουμε αρχίσει να έχουμε υπερεκπαίδευση.\n","\n","## Άλλα σχήματα Cross Validation\n","\n","### Εξαντλητικά σχήματα\n","\n","#### Leave-one-out Cross Validation\n","![](https://i2.wp.com/neptune.ai/wp-content/uploads/Cross-validation-leave-one-out.jpg?resize=564%2C440&ssl=1)\n","\n","H πιο ακριβής μέθοδος cross validation αλλά και η πιο ακριβή (χρονοβόρα). Υπάρχει καη παραλλαγή Leave-p-out cross-validation.\n","\n","### Nested Cross Validation\n","\n","Χρησιμοποιείται για να κάνουμε ταυτόχρονα εύρεση βέλτιστων υπερπαραμέτρων και εκτίμηση της γενίκευσης.\n","\n","#### k*l-fold cross-validation\n","![image.png](https://i.stack.imgur.com/vh1sZ.png)\n","\n","Κάνουμε k εξωτερικά folds, το 1 fold είναι για εκτίμηση της γενίκευσης και τα k-1 για εκπαίδευση. Στο σύνολο train των k-1 κάνουμε l-fold crossvalidation για εύρεση των βέλτιστων υπερπαραμέτρων του ταξινομητή.\n","\n","Ο μέσος όρος της γενίκευσης στα k folds του train set είναι μια εκτίμηση χωρίς προκατάληωη (unbiased, σα να κάνουμε marginilize την επίδραση των υπερπαραμέτρων) της γενίκευσης στο test set.\n","\n","H Nested Cross Validation χρησιμεύει για την unbiased εκτίμηση της γενίκευσης στο test set αλλά όχι για την επιλογή υπερπαραμέτρων (βλέπε [εδώ](https://weina.me/nested-cross-validation/)).\n","\n"]}]}