Π Π Σ Τ Π Ε Τ Ψ Σ Δομές Δεδομένων 2016-2017 2η Εργασία Χρήστος Δουλκερίδης Ορέστης Τελέλης 1 Περιγραφή Η ομαδοποίηση εγγράφων (document clustering) με βάση τα περιεχόμενά τους είναι ένα πολύ ενδιαφέρον πρόβλημα με πολλές εφαρμογές σε συστήματα συστάσεων, σε αυτοματοποιημένη ϑεματική οργάνωση συλλογών εγγράφων, κ.ά.. Για τον υπολογισμό της ομοιότητας δύο εγγράφων, ένας συνηθισμένος τρόπος είναι η αναπαράσταση του κάθε εγγράφου ως διάνυσμα σε έναν πολυδιάστατο χώρο, και ο υπολογισμός της γωνίας που σχηματίζουν τα δύο διανύσματα. Οσο μικρότερη είναι η γωνία των δύο διανυσμάτων τόσο ομοιότερα τα αντίστοιχα έγγραφα. Ο πολυδιάστατος χώρος ορίζεται ως ένας N-διάστατος χώρος όπου κάθε διάσταση αντιστοιχεί σε μια από τις N λέξεις που υπάρχουν στο λεξικό της συλλογής, ενώ οι τιμές που παίρνει ένα έγγραφο σε κάθε διάσταση αντιστοιχούν στο πλήθος εμφανίσεων της λέξης (που αντιστοιχεί στη συγκεκριμένη διάσταση) εντός του εγγράφου. Ο υπολογισμός της γωνίας θ δύο διανυσμάτων A = (A 1, A 2,..., A n ) και B = (B 1, B 2,..., B n ) γίνεται με υπολογισμό του συνημιτόνου (cosine) cos θ από τη φόρμουλα: cos θ = A B A B = n n A i B i n A 2 i B 2 i όπου A B συμβολίζει το εσωτερικό γινόμενο των διανυσμάτων A και B, και A (αντίστοιχα B ) συμβολίζει το μέτρο του διανύσματος A (αντίστοιχα B). Δεδομένου ότι κάθε έγγραφο αναπαρίσταται ως διάνυσμα με ϑετικές συντεταγμένες, η γωνία θ είναι μεταξύ 90 και 0 μοιρών, και αντίστοιχα το συνημίτονο παίρνει τιμές από 0 ως 1. Πιο συγκεκριμένα, μικρές τιμές της γωνίας θ (κοντά στις 0 μοίρες) αντιστοιχούν σε μεγάλες τιμές συνημιτόνου (κοντά στο 1), ενώ όσο η γωνία αυξάνεται το συνημίτονο μειώνεται, ώσπου τελικά για γωνία 90 μοιρών το συνημίτονο ισούται με 0. 1
Στην παρούσα εργασία καλείστε να αναπτύξετε ένα τμήμα μιας εφαρμογής που ομαδοποιεί μια συλλογή εγγράφων με βάση την ομοιότητά τους. Συγκεκριμένα, ζητείται: Ι. Να υλοποιήσετε δύο (εναλλακτικές) δομές δεδομένων που μπορούν να αναπαριστούν έγγραφα κειμένου, η πρώτη με χρήση απλού πίνακα και η δεύτερη με χρήση πίνακα κατακερματισμού. ΙΙ. Να εφοδιάσετε καθεμιά από τις δομές σας με: (α) μια συνάρτηση που δοθέντων δύο εγγράφων κειμένου ϑα υπολογίζει το συνημίτονο της γωνίας που σχηματίζουν, και (β) μια συνάρτηση που υπολογίζει το μέτρο του διανύσματος που αναπαρίσταται από την εκάστοτε δομή. ΙΙΙ. Να υλοποιήσετε έναν απλοϊκό αλγόριθμο (για καθεμιά από τις δομές σας) ο οποίος ομαδοποιεί τα έγγραφα σε k ομάδες. 1.1 Δομές Δεδομένων: Εγγραφο Για την αναπαράσταση ενός εγγράφου κειμένου ϑα υλοποιήσετε δύο εναλλακτικές δομές δεδομένων. Η πρώτη δομή δεδομένων είναι ένας απλός πίνακας μήκους όσο το λεξικό της συλλογής (λεξικό = σύνολο διακριτών λέξεων σε όλα τα έγγραφα της συλλογής). Στην πράξη, ϑα υ- λοποιήσετε μια κλάση MyArray η οποία περιέχει δύο πίνακες ίσου μήκους: έναν πίνακα που καταχωρεί τις λέξεις τις συλλογής (String[] arwords), και έναν πίνακα που καταχωρεί τη συχνότητα εμφάνισης (double) της αντίστοιχης λέξης στο έγγραφο (double[] arfreq). Ως συχνότητα εμφάνισης ορίζεται το πλήθος εμφανίσεων μιας λέξης σε ένα έγγραφο. Για την υλοποίηση ϑα ακολουθήσετε την προδιαγραφή που δίνεται στην Τεκμηρίωση. Η δεύτερη δομή δεδομένων ϑα υλοποιεί έναν πίνακα κατακερματισμού M ϑέσεων (ListNode[] arr), που ϑα χρησιμοποιεί τη μέθοδο ξεχωριστής αλυσίδας (separate chaining). Κάθε κελί του πίνακα κατακερματισμού περιέχει αναφορά σε κόμβο ListNode. Μια λέξη (οποιουδήποτε εγγράφου) αντιστοιχίζεται με μοναδικό τρόπο σε ένα από τα M 1 κελιά του πίνακα, μέσω μιας συνάρτησης κατακερματισμού. Για παράδειγμα, στο παρακάτω σχήμα, η λέξη πάπια πάντα αντιστοιχίζεται στο κελί 0. Ο πίνακας κατακερματισμού ϑα υλοποιηθεί ως κλάση MyHashtable με βάση την προδιαγραφή που δίνεται στην Τεκμηρίωση. 2
1.2 Μέθοδος: Υπολογισμός Συνημιτόνου Για τον υπολογισμό συνημιτόνου, ϑα εφοδιάσετε τις κλάσεις MyArray και MyHashtable με μια μέθοδο double computecosine(myarray a) και double computecosine(myhashtable h) αντίστοιχα, που ϑα επιστρέφει το συνημίτονο (ως double) της γωνίας που σχηματίζουν τα έγγραφα. Επίσης, ζητείται να εφοδιάσετε καθεμιά από τις παραπάνω κλάσεις με μια μέθοδο double computenorm() που επιστρέφει το μέτρο του διανύσματος. 1.3 Αλγόριθμος Ομαδοποίησης Εγγράφων Για να υλοποιήσετε την ομαδοποίηση εγγράφων, ϑα υλοποιήσετε στις κλάσεις GroupingArray και GroupingHash τη μέθοδο void run(), με βάση την προδιαγραφή της Τεκμηρίωσης. Η βασική ιδέα της ομαδοποίησης είναι ότι δοθέντων E εγγράφων κειμένου τα οποία επιθυμούμε να ομαδοποι- ήσουμε σε k ομάδες, επιλέγονται αρχικά k από τα E έγγραφα ως «κέντρα» (με κάποιον τρόπο, π.χ. τυχαία), και στη συνέχεια το καθένα από τα υπόλοιπα E k έγγραφα ανατίθεται στο πιο όμοιο κέντρο με βάση την ομοιότητα συνημιτόνου. Ο αλγόριθμος που ϑα αναπτύξετε στη μέθοδο run() ϑα χρησιμοποιεί τις ακόλουθες μεταβλητές: MyArray[] objects (αντίστοιχα MyHashtable[] objects) που είναι ένας πίνακας που περιέχει τα έγγραφα κειμένου που ϑα ομαδοποιηθούν. int k που δηλώνει το πλήθος των κέντρων. int[] centroids που είναι ένας πίνακας μεγέθους k που περιέχει τις ϑέσεις του πίνακα objects όπου βρίσκονται τα έγγραφα «κέντρα». int[] groupedobjects που είναι ένας πίνακας μεγέθους όσο και ο objects, που περιέχει για κάθε έγγραφο τη ϑέση του πίνακα objects όπου βρίσκεται το «κέντρο» στο οποίο έχει ανατεθεί. Η παρακάτω εικόνα δείχνει ένα παράδειγμα των παραπάνω πινάκων για 6 έγγραφα κειμένου o i, για k = 3, όπου έχουν επιλεγεί ως κέντρα (centroids) τα έγγραφα στις ϑέσεις 2, 3 και 5 του objects. Ο groupedobjects δείχνει το αποτέλεσμα μιας ομαδοποίησης όπου έχουν σχηματιστεί 3 ομάδες εγγράφων: (0, 2), (1, 5) και (3, 4). 2 Τεκμηρίωση 2.1 Αρχείο Πηγαίου Κώδικα MyArray.java Περιέχει την κλάση MyArray, που είναι η πρώτη δομή δεδομένων που ϑα αναπτύξετε (Πίνακας), και συγκεκριμένα τις μεθόδους: void add(string sword, double dfreq): αν η λέξη sword υπάρχει ήδη στη δομή, αυξάνει τη συχνότητά της κατά dfreq. Εάν η λέξη δεν υπάρχει, ϑέτει τη συχνότητά της ίση με dfreq. double computecosine(myarray a): υπολογίζει και επιστρέφει το συνημίτονο της γωνίας που σχηματίζουν τα εξής δύο διανύσματα εγγράφων: το αντικείμενο τύπου MyArray από το οποίο καλείται η μέθοδος και το αντικείμενο τύπου MyArray a που δίνεται σαν παράμετρος. double computenorm(): υπολογίζει και επιστρέφει το μέτρο του διανύσματος εγγράφου που αναπαρίσταται από το αντικείμενο τύπου MyArray, από το οποίο καλείται η μέθοδος. 3
Σημειώνεται ότι υπάρχουν δύο πίνακες String[] arwords και double[] arfreq, τους οποίους μπορείτε να χρησιμοποιείτε εντός της κλάσης MyArray. Δεν πρέπει να δηλώσετε δικές σας καθολικές μεταβλητές στην κλάση MyArray. 2.2 Αρχείο Πηγαίου Κώδικα MyHashTable.java Περιέχει την κλάση MyHashtable που είναι η δεύτερη δομή δεδομένων που ϑα αναπτύξετε (Πίνακας Κατακερματισμού) και συγκεκριμένα τις μεθόδους: void add(string sword, double dfreq): εφόσον η λέξη sword υπάρχει ήδη στη δομή, αυξάνει τη συχνότητά της κατά dfreq. Εάν η λέξη δεν υπάρχει, ϑέτει τη συχνότητά της ίση με dfreq. double get(string sword): επιστρέφει τη συχνότητα της λέξης sword. double computecosine(myhashtable h): υπολογίζει και επιστρέφει το συνημίτονο της γωνίας που σχηματίζουν τα εξής δύο διανύσματα εγγράφων: το αντικείμενο τύπου MyHashTable από το οποίο καλείται η μέθοδος και το αντικείμενο τύπου MyHashTable h που δίνεται σαν παράμετρος. double computenorm(): υπολογίζει και επιστρέφει το μέτρο του διανύσματος εγγράφου που αναπαρίσταται από το αντικείμενο τύπου MyHashTable, από το οποίο καλείται η μέθοδος. Σημειώνεται ότι υπαρχει πίνακας ListNode[] arr που μπορείτε να χρησιμοποιείτε εντός της κλάσης MyHashtable. Ο πίνακας αυτός είναι μήκους size (= M). Κάθε κελί του περιέχει αναφορά σε αντικείμενο τύπου ListNode. Το αντικείμενο ListNode αποτελεί τον κόμβο λίστας και περιέχει τις ακόλουθες public μεταβλητές: String sword: η λέξη που αποθηκεύεται στον κόμβο. Double dfreq: το πλήθος εμφανίσεων της λέξης στο έγγραφο. ListNode next: αναφορά στον επόμενο κόμβο της λίστας. και τις ακόλουθες public μεθόδους: ListNode(String s, double d): Κατασκευαστής αντικειμένων τύπου ListNode. display(): εκτυπώνει σε μια γραμμή τα περιεχόμενα του κόμβου. Μπορείτε να δημιουργείτε αντικείμενα ListNode για να αποθηκεύετε νέες λέξεις και τις συχνότητες αυτών, και να τα συνδέετε μεταξύ τους (με τη next), για να υλοποιήσετε τις αλυσίδες που απαιτεί ο πίνακας κατακερματισμού. Μπορείτε επίσης να καλείτε τη μέθοδο int hashfunc(string s) η οποία σας επιστρέφει τη ϑέση του πίνακα όπου κατακερματίζεται η λέξη s. Δεν πρέπει να δηλώσετε δικές σας καθολικές μεταβλητές στην κλάση MyHashtable. 2.3 Αρχείο Πηγαίου Κώδικα GroupingArray.java Περιέχει την κλάση GroupingArray που υλοποιεί τη διαδικασία ομαδοποίησης για έγγραφα που αναπαριστώνται ως MyArray, και συγκεκριμένα τη μέθοδο: void run(): εξετάζει κάθε αντικείμενο objects[i] του πίνακα objects ως προς καθένα από τα k αντικείμενα του objects που έχουν επιλεγεί ως κέντρα (centroids), και «αναθέτει» το objects[i] στο κέντρο με τη μέγιστη ομοιότητα συνημιτόνου: ϑέτει το groupedobjects[i] ίσο με το index της ϑέσης του πίνακα objects, όπου περιέχεται το κέντρο στο οποίο ανατέθηκε το objects[i]. 2.4 Αρχείου Πηγαίου Κώδικα GroupingHash.java Περιέχει την κλάση GroupingHash που υλοποιεί τη διαδικασία ομαδοποίησης για έγγραφα που αναπαριστώνται ως MyHashtable, και συγκεκριμένα τη μέθοδο: void run(): εξετάζει κάθε αντικείμενο objects[i] του πίνακα objects ως προς καθένα από τα k αντικείμενα του objects που έχουν επιλεγεί ως κέντρα (centroids), και «αναθέτει» το objects[i] στο κέντρο με τη μέγιστη ομοιότητα συνημιτόνου: ϑέτει το groupedobjects[i] ίσο με το index της ϑέσης του πίνακα objects, όπου περιέχεται το κέντρο στο οποίο ανατέθηκε το objects[i]. 4
2.5 Αρχείο Πηγαίου Κώδικα Runner.java Περιέχει την κλάση Runner με μία main μέθοδο, που εκτελεί τις εξής εργασίες: 1: Φορτώνει μια συλλογή εγγράφων από το δίσκο στη μνήμη. 2: Γεμίζει δομές τύπου MyArray και MyHashtable στη μνήμη, μία για κάθε έγγραφο. 3: Επιλέγει k τυχαία κέντρα (centroids) από τα έγγραφα, και καλεί τις μεθόδους ομαδοποίησης (run) των κλάσεων GroupingArray και GroupingHash. 4: Εκτυπώνει στην οθόνη το χρόνο εκτέλεσης της ομαδοποίησης με χρήση Πίνακα και Πίνακα Κατακερματισμού, καθώς και το πόσα έγγραφα περιέχει η κάθε ομάδα. ΜΕΤΑΓΛΩΤΤΙΣΗ: ΕΚΤΕΛΕΣΗ: C:\> javac -cp ergasia2.jar.java C:\> java -cp ergasia2.jar;. Runner 3 Ζητούμενα (1) Θα υλοποιήσετε τις κενές μεθόδους στα αρχεία πηγαίου κώδικα των κλάσεων MyArray, MyHashtable, GroupingArray, GroupingHash. (2) Θα συντάξετε τεχνική αναφορά που ϑα περιλαμβάνει: (α) σύγκριση του χρόνου εκτέλεσης συσταδοποίησης με χρήση Πίνακα και Πίνακα Κατακερματισμού, και να αιτιολογήσετε το αποτέλεσμα με βάση την πολυπλοκότητα του αλγόριθμου που υλοποιήσατε, (β) γραφική παράσταση που απεικονίζει το μέγεθος των ομάδων εγγράφων που σχηματίστηκαν (X-άξονας: ομάδες 1 έως K, Y-άξονας: πλήθος εγγράφων). 4 Διαδικαστικά Θέματα ΠΑΡΑΔΟΤΕΑ Θα πρέπει να παραδώσετε ένα αρχείο ΑΜ_Επώνυμο_ Ονομα.zip (όπου ΑΜ ο αριθμός μητρώου) που ϑα περιλαμβάνει ακριβώς πέντε (5) αρχεία: 1. Τα αρχεία πηγαίου κώδικα: MyArray.java, MyHashtable.java, GroupingArray.java, GroupingHash.java, επαρκώς σχολιασμένα. Προσοχή: σχόλια στα ελληνικά, μόνο σε κωδικοποίηση UTF-8. Άλλες κωδικοποιήσεις (ISO-8859-7, Windows-1253) απορρίπτονται από τον Java Compiler. Eclipse/Netbeans: δεξί click στο Project, επιλογή Properties και στην ιδιότητα «Encoding» επιλέγετε UTF-8. 2. Την τεχνική αναφορά σας σε μορφή pdf. ΘΑ ΑΓΝΟΗΘΕΙ κάθε άλλη μορφή εγγράφου. ΠΑΡΑΔΟΣΗ αποκλειστικά μέσω της πλατφόρμας «ΕΥΔΟΞΟΣ» του τμήματος, έως και την 15 Ιανουαρίου 2017, 23:59. Ανεβάστε το ΑΜ_Επώνυμο_ Ονομα.zip στην περιοχή «Εργασίες». ΕΡΩΤΗΣΕΙΣ/ΑΠΟΡΙΕΣ/ΔΙΕΥΚΡΙΝΙΣΕΙΣ δίνονται αποκλειστικά μέσα από την Περιοχή Συζήτησης «ΕΡΓΑΣΙΑ 2» της πλατφόρμας «ΕΥΔΟΞΟΣ». Δε ϑα απαντηθούν Email με απορίες. ΔΕ ΘΑ ΑΞΙΟΛΟΓΗΘΟΥΝ: Εργασίες που ϑα παραδοθούν εκπρόθεσμα ή με άλλο τρόπο (email, CD κ.λ.π.) Εργασίες που παραδίδονται σε μορφή συμπίεσης διαφορετική από.zip. Εργασίες που περιλαμβάνουν μέσα άσχετα αρχεία. ΒΑΘΜΟΛΟΓΗΣΗ Η εργασία μετρά 20% στον τελικό βαθμό (εφόσον το γραπτό σας βαθμολογηθεί με τουλάχιστον 4). Φτωχή / Δυσανάγνωστη τεκμηρίωση ή έλλειψη αυτής στην αναφορά για κάποια λειτουργία, επιφέρει άμεση απώλεια 50% του μέγιστου δυνατού βαθμού για τη λειτουργία αυτή. Η τεχνική αναφορά ή τμήματα αυτής δε ϑα ληφθούν υπόψην στη βαθμολόγηση αν δε συνοδεύονται από κώδικα που μεταγλωττίζεται και εκτελείται. Η εργασία είναι αυστηρά ατομική. Αντιγραφή στον κώδικα και/ή στην τεχνική αναφορά επιφέρει άμεσο μηδενισμό της εργασίας. Οι εργασίες ϑα ελεγχθούν (όλες ανά ζεύγη). Καλή Επιτυχία! 5