Προγραμματισμός Υπολογιστών με C++ ( 2012-13 ) 13η διάλεξη Ίων Ανδρουτσόπουλος http://www.aueb.gr/users/ion/ 1
Τι θα ακούσετε σήμερα Κληρονομικότητα και: δυναμική καταχώριση μνήμης, κατασκευαστές αντιγράφων, τελεστές εκχώρησης, καταστροφείς. Αρχικές πληροφορίες για την 3η εργασία. 2
Από την προηγούμενη φορά... class Person { string name; unsigned short numaddresses; string* addresses; public: Person(const string& namein, unsigned short numaddressesin, const string addressesin[]); Person(const Person& original); ~Person() { delete []addresses; } Person& operator=(const Person& right); // Επιστρέφουν αναφορά στο όνομα ή τη διεύθυνση που υπάρχει // στο εσωτερικό του αντικειμένου. Μπορούν να χρησιμοποιηθούν // και για να αλλάξουμε το όνομα ή τη διεύθυνση μέσα στο αντικείμενο: string& getname() { return name; } string& getaddress(unsigned i) { return addresses[i]; } }; 3
Η βασική τάξη Course class Course { string name; string code; public: Course(const string& namein = "", const string& codein = "") : name(namein), code(codein) {} const string& getname() const { return name; } const string& getcode() const { return code; } }; Οι getname() και getcode επιστρέφουν αναφορές στα name και code αντί για αντίγραφά τους (πιο γρήγορο), αλλά δεν μπορούν να χρησιμοποιηθούν για να αλλάξουμε τα name και code γιατί οι αναφορές είναι const. Δε χρειάζεται να ορίσουμε κατασκευαστή αντιγράφου, καταστροφέα και τελεστή εκχώρησης, γιατί μας αρκούν αυτοί που ορίζει αυτόματα η C++ (π.χ. η τάξη δε χρησιμοποιεί δυναμική 4 καταχώριση μνήμης).
Η παράγωγη τάξη Student class Student : public Person { string code; unsigned short numcourses; Course* courses; public: Student(const string& namein, unsigned short numaddressesin, const string addressesin[], const string& codein, unsigned short numcoursesin, const Course coursesin[]); const string& getcode() const { return code; } Course& getcourse(unsigned short i) { return courses[i]; } Student(const Student& original); Student& operator=(const Student& right); ~Student() { delete []courses; } }; 5
Καταστροφείς παραγώγων τάξεων Τη μνήμη που δεσμεύει με new για τις ταχυδρομικές διευθύνσεις κάθε αντικείμενο της Person την αποδεσμεύει ο καταστροφέας της Person. Ο καταστροφέας της Student είναι υπεύθυνος μόνο για την επιπλέον μνήμη που δεσμεύει με new κάθε αντικείμενο της Student για να αποθηκεύσει τα μαθήματα. Κατά την καταστροφή ενός αντικειμένου της Student καλείται αυτόματα και ο καταστροφέας της Person (της τάξης την οποία κληρονομεί η Student). 6
Παράδειγμα χρήσης της Student int main() { string addr[] = {"Πατησίων 76", "Κοδριγκτώνος 10"}; Course c1("c++", "epl132"), c2("intro to CS", "epl131"), c3("other", "epl133"); Course cour[] = {c1, c2}; Student s1("νίκος", 2, addr, "p300015", 2, cour); } s1.getcourse(1) = c3; // Αλλαγή μαθήματος. // s.getcode() = "p300016"; // Λάθος. Επιστρέφει const αναφορά. Course cour2[] = {c1, c2, c3}; Student s2("νίκος", 2, addr, "p300015", 3, cour2); s1 = s2; // Αλλαγή υπάρχοντος αντικειμένου s1. Τελεστής εκχώρησης. Student s3 = s1; // Νέο αντικείμενο s3. Κατασκευαστής αντιγραφής. cout << s3.getname() << endl; // Κληρονομημένη μέθοδος. 7
Κατασκευαστής της Student Student::Student(const string& namein, unsigned short numaddressesin, const string addressesin[], const string& codein, unsigned short numcoursesin, const Course coursesin[]) : // Κλήση του κατασκευαστή της βασικής τάξης: Person(nameIn, numaddressesin, addressesin), // Κλήση του κατασκευαστή αντιγράφου της string: code(codein), numcourses(numcoursesin), courses(new Course[numCourses]) { for(unsigned short i = 0; i < numcourses; i++) { courses[i] = coursesin[i]; } } 8
Κατ/τής αντιγράφου της Student Student::Student(const Student& original) : Person(original), // Κατ/τής αντιγράφου της βασικής τάξης. // Ως όρισμα χρησιμοποιείται το κομμάτι // Person του original (το original είναι Student). code(original.code), numcourses(original.numcourses), // Χρησιμοποιεί τον προεπιλεγμένο κατ/τή της Course: courses(new Course[numCourses]) { for(unsigned short i = 0; i < numcourses; i++) { courses[i] = original.courses[i]; } } 9
Τελεστής εκχώρησης της Student Student& Student::operator=(const Student& right) { if(this = = &right) return *this; Person::operator=(right); // Τελεστής εκχώρησης της βασικής. // Ως όρισμα χρησιμοποιείται το // κομμάτι Person του right. } code = right.code; if(numcourses!= right.numcourses) { delete []courses; numcourses = right.numcourses; courses = new Course[numCourses]; } for(unsigned short i = 0; i < numcourses; i++) { courses[i] = right.courses[i]; } return *this; 10
Εντοπισμός ανεπιθύμητων μηνυμάτων παραδείγματα επιθυμητών και ανεπιθύμητων μηνυμάτων + σωστές απαντήσεις εκπαίδευση InstancePool με ένα Instance για κάθε μήνυμα εκπαίδευσης προεπεξεργασία προεπεξεργασία αλγόριθμος μάθησης 3 η εργασία συνάρτηση ταξινόμησης ταξινομητής νεοεισερχόμενο μήνυμα απόφαση: επιθυμητό ή ανεπιθύμητο ένα Instance με άγνωστη κατηγορία χρήση 11
Ταξινομητής k κοντινότερων γειτόνων Μάθηση: απλά αποθηκεύει το InstancePool των μηνυμάτων εκπαίδευσης. Όταν φτάνει καινούριο μήνυμα (το Instance?) άγνωστης κατηγορίας, βρίσκει τα k πιο παρόμοια Instance των παραδειγμάτων εκπαίδευσης (k κοντινότεροι γείτονες). Κατατάσσει το καινούριο Instance στην κατηγορία που πλειοψηφεί μεταξύ των k κοντινότερων γειτόνων. InstancePool με μηνύματα εκπαίδευσης + + + - νέο μήνυμα +? - + - + - - - k (εδώ k=3) κοντινότεροι γείτονες 12
Τι σημαίνει «κοντινότεροι»; Ευκλείδεια απόσταση: d x, y = x 1 y 1 2 + x 2 y 2 2 + όπου x, y δύο Instance, x 1, x 2, τα TF-IDF (1 η εργασία) των λέξεωνκλειδιών (features) με κωδικούς (id) 1, 2, στο x, y 1, y 2, τα TF-IDF (1 η εργασία) των λέξεωνκλειδιών (features) με κωδικούς (id) 1, 2, στο y. Κοντινότεροι γείτονες: τα Instance των μηνυμάτων εκπαίδευσης με τις μικρότερες αποστάσεις από το προς κατάταξη Instance. 13
Αφελής ταξινομητής Bayes ( Bernoulli (πολυμεταβλητή μορφή P(spam) = ποσοστό spam μηνυμάτων στα μηνύματα εκπαίδευσης. P(ham) = ποσοστό επιθυμητών μηνυμάτων στα μηνύματα εκπαίδευσης. Για κάθε λέξη-κλειδί (feature) t: P(t spam) = [1 + M(t, spam)] / [2 + M(spam)] P(t ham) = [1 + M(t, ham)] / [2 + M(ham)] όπου M(t, c) ο συνολικός αριθμός μηνυμάτων κατηγορίας c που περιέχουν την t, και M(c) ο συνολικός αριθμός μηνυμάτων κατηγορίας c. 14
Aφελής ταξινομητής Bayes ( Bernoulli (πολυμεταβλητή μορφή Κατατάσσουμε ως spam αν και μόνο αν ο λόγος: m logp spam + i=1 log P t i spam x i + log [1 P t i spam ] 1 x i m > logp ham + i=1 log P t i ham x i + log [1 P t i ham ] 1 x i > θ, όπου t 1,..., t m είναι όλες οι λέξεις-κλειδιά, x i = 1 αν το μήνυμα περιέχει την t i, διαφορετικά x i = 0 και θ είναι ένα κατώφλι (π.χ. 0.5). 15
Περισσότερα για τον αφελή ταξινομητή Bayes Μπορείτε να δείτε πώς προκύπτουν οι τύποι διαβάζοντας το άρθρο: «Spam Filtering with Naive Bayes Which Naive Bayes?» των Β. Μέτση, Ι. Ανδρουτσόπουλου και Γ. Παλιούρα. Βλ. http://nlp.cs.aueb.gr/publications.html. Μπορείτε αν θέλετε να υλοποιήσετε προαιρετικά και την πολυωνυμική μορφή του αφελούς ταξινομητή Bayes. Εξετάζει και τις συχνότητες εμφάνισης των λέξεωνκλειδιών στο κάθε μήνυμα, ενώ η πολυμεταβλητή μορφή Bernoulli αγνοεί τις συχνότητες.