Algoritm DE Discriminare A Sensului Cuvintelor

UNIVERSITATEA „LUCIAN BLAGA” SIBIU

FACULTATEA DE INGINERIE

DEPARTAMENTUL DE CALCULATOARE ȘI INGINERIE ELECTRICĂ

PROIECT DE DIPLOMĂ

ABSOLVENT : Ciprian MIHAIU

SPECIALIZAREA : Calculatoare

– Sibiu, 2016 –

UNIVERSITATEA „LUCIAN BLAGA” SIBIU

FACULTATEA DE INGINERIE

DEPARTAMENTUL DE CALCULATOARE ȘI INGINERIE ELECTRICĂ

ALGORITM DE DISCRIMINARE A SENSULUI CUVINTELOR

COORDONATOR ȘTIINȚIFIC :

Șef lucr. dr. mat. Radu CREȚULESCU

ABSOLVENT : Ciprian MIHAIU

SPECIALIZAREA : Calculatoare

– Sibiu, 2016 –

Cuprins

INTRODUCERE

Tema acestei lucrări de licență este “Word Sense Discrimination”, adică dizambiguizarea sensurilor cuvintelor fără un antrenament anterior, algoritmul utilizând cuvintele vecine cuvântului evaluat pentru a determina contextul și ulterior sensul potrivit. Lucrarea are ca scop dezvoltarea unei aplicații care să poată determina sensul cuvintelor utilizând ca dicționar baza de date WordNet, un proiect lansat la universitatea Princeton în 1985.

În cadrul dezvoltării acestei lucrări de licență am reușit să combin mai multe domenii de studii din cadrul specializării pe care am urmat-o. Pe lângă programarea orientată pe obiecte am reușit să utilizez anumite design pattern-uri și am aplicat concepte prezentate în cartea “Clean Code” scrisă de Robert Cecil Martin pentru a oferi o posibilitate de reutilizare a codului și respectiv de a asigura o mentenanță mai bună aplicației. Tema lucrării se încadrează în subdomeniul “Data Mining”, subdomeniu aflat la intersecția domeniului “Artificial Intelligence” cu domeniile “Machine Learning”, “Statistics” și “Database Systems”. Scopul general al domeniului de “Data Mining” este de a extrage informații utile dintr-un set de date și transformarea acestora într-o structură ușor de înțeles pentru o utilizare ulterioară.

Obiectivele principale ale acestei lucrări de diplomă sunt:

Implementarea algoritmului lui Lesk într-un mod diferit față de cel original cu scopul de a discrimina sensul cuvintelor într-un anumit context

Utilizarea bazei de date WordNet, aplicația putând să discrimineze doar cuvinte din limba engleză

Eliminarea pluralului cuvintelor, litera ‘s’ de la sfârșitul unui cuvânt

Dezvoltarea aplicației folosind principii de “Clean Code” și design pattern-uri (ca singleton pattern sau repository pattern) realizând o aplicație ce poate fii dezvoltată cu ușurință în viitor

Lucrarea este impărtită în trei părți principale după cum urmează:

În prima parte, “Consideratii teoretice”, sunt prezentate aspecte teoretice cu privire la subdomeniul “Data Mining”, domeniul “Artificial Intelligence”, conceptele programării orientate pe obiecte (încapsularea, moștenirea, polimorfismul, compoziția, cuplarea, coeziunea) și șabloanele de proiectare – design pattern-uri folosite (Singleton pattern și Repository pattern).

A doua parte a lucrării, “Dezvoltarea aplicatiei” prezintă structura aplicației, descriind conceptele folosite în dezvoltarea sa. Sunt prezentate clasele implementate prin diagrame de clase și pseudocod pentru funcțiile mai importante. La final se prezintă și câteva diagrame de interacțiune între aceste clase și se prezintă pe scurt interfața aplicației cu utilizatorul.

Ultima parte, “Concluzii și dezvoltări ulterioare”, prezintă concluziile aferente și sugerează cateva dezvoltării ulterioare posibile.

CAPITOLUL 1. CONSIDERAȚII TEORETICE

1.1 Inteligența artificială

1.1.1 Noțiuni introductive

Inteligența artificială este acea partea a științei calculatoarelor care se ocupă cu realizarea unor sisteme de calcul capabile să simuleze comportamente inteligente. Aceasta mai este definită și ca domeniul care se ocupă cu realizarea de sisteme „inteligente”. În știința calculatoarelor, o mașină "inteligentă" ideală este un agent rațional flexibil care percepe mediul său inconjurător și ia măsuri care să maximizeze șansa sa de succes la un obiectiv arbitrar. [WikiAI]

Inteligența artificială este un domeniu foarte utilizat, in foarte multe domenii cotidiene sau pe calculator. Câteva exemple:

mașini autonome

rezolvarea de probleme complexe în mai multe domenii precum chimie, biologie, inginerie, medicină ș.a.m.d.

în cadrul motoarelor de căutare web

robotică

procesare de limbaj natural

traduceri lingvistice

recunoaștere vocală

procesare de imagini

jocuri

Scopul principal al inteligenței artificiale este acela de a rezolva probleme. Inițial au fost dezvoltați algoritmi care imitau pas cu pas comportamentul pe care îl au oamenii atunci când rezolvă un puzzle sau când fac o deducție logică. Prin cercetări ulterioare s-au descoperit metode de a trata informații incerte sau incomplete, folosind concepte din economie si probabilități. În cazul problemelor dificile, majoritatea acestor algoritmi pot să necesite resurse enorme de calcul, majoritatea ducând la o explozie combinatorială (cantitatea de memorie sau timpul de calcul necesare devin astronomice atunci când problema depășește un anumit prag). O mare prioritate a inteligenței artificiale o constituie găsirea unor algoritmi cât mai eficienți pentru rezolvarea problemelor.

Problemele centrale (sau scopurile) cercetării inteligenței artificiale includ raționamentul, cunoștiințele, planificarea, învățarea, procesarea limbajului natural (comunicarea), percepția și capacitatea de a muta și manipula obiecte.

Pe lângă rezolvarea problemelor mai există și reprezentarea cunoașterii care este aproape la fel de importantă. Majoritatea problemelor pe care o mașină trebuie să le rezolve necesită o cunoaștere amplă a lumii. Printre lucrurile care ar trebui să fie reprezentate se numără: obiecte, proprietăți, situații, evenimente etc.

Programele care folosesc inteligența artificială realizează o căutare într-un spațiu al stărilor. De exemplu, în cazul unui joc cu cel puțin 2 jucători, spațiul stărilor reprezintă totalitatea mutărilor posibile. Un program care folosește căutarea exhaustivă, ia în considerare toate aceste mutări, apoi toate mutările posibile pe care adversarul le poate face ca răspuns. Avantajul major al acestui program este puterea de calcul mult mai mare decât a adversarului (jucător uman), putând astfel să ia in calcul mult mai multe mutări. Dezavantajul este că acest program verifică toate mutările, chiar dacă unele dintre ele nu duc la câștig, lucru care pentru un jucător uman ar putea fi vizibil.

După cum am specificat anterior una dintre problemele centrale cu care se preocupă inteligență artificială este procesarea limbajului natural (Natural Language Processing – NLP). Procesarea limbajului natural oferă unei mașini “inteligente” capacitatea de a citi și de a înțelege limbile vorbite de oameni. Un sistem suficient de puternic de procesare a limbajului natural ar putea pune la dispoziția utilizatorilor interfețe scrise în limbaj natural și ar permite dobândirea de cunoștințe direct din surse scrise de oameni, cum ar fi texte de știri de ultimă oră sau actualizări dee pe piața financiară. Unele aplicații simple de procesare a limbajului natural includ extragerea de informații, posibilitatea de raspundere automata a unor întrebări sau traducerea automată a unor texte. [WikiAI]

1.1.2 Natural Language Processing

Va putea vreodată o aplicație pe calculator să convertească o bucată de text, fie ea scrisă în orice limbă, într-o structură de date, utilă unui programator, care să descrie semnificația textului? Din păcate nu s-a ajuns la nici un consens cu privire la existența unei astfel de structuri de date. Până în momentul când aceste probleme fundamentale ale inteligenței arficiale vor fi rezolvate, oamenii de știință în calculatoare trebuie să se mulțumească cu o modalitate redusă de extragere a unor simple reprezentări care descriu aspecte limitate ale informațiilor textuale.

Aceste reprezentări mai simple sunt adesea motivate de aplicații specifice (de exemplu, variante de tip “bag-of-words” pentru extragerea de informații), sau prin convingerea noastră că acestea captează ceva mai general despre limbajul natural. Ele pot descrie informații sintactice (de exemplu, marcarea pârtiilor de vorbire, împărțirea textului și parsarea lui) sau informații semantice (de exemplu, dezambiguizarea sensurilor cuvintelor, etichetarea rolului semantic, extragerea entităților numite și rezoluția anaforei). Corpusuri de text au fost adnotate manual, cu ajutorul unor astfel de structuri de date, în scopul de a compara performanța diferitelor sisteme. Disponibilitatea de referintă standard a stimulat cercetarea în procesarea limbajului natural (NLP) și sisteme eficiente au fost proiectate pentru toate aceste sarcini. Astfel de sisteme sunt adesea privite ca componente software pentru construirea de soluții reale NLP. [Callobert11]

Așadar procesarea limbajului natural (NLP) este un domeniu al științei calculatoarelor, face parte din domeniul inteligenței artificiale și al lingvisticii computaționale preocupată cu interactiuniile dintre calculatoare și limbajele umane (naturale), deci putem spune că NLP este un domeniu aflat în strânsă legătură cu domeniul de interacțiune om-mașină.[WikiNLP] Multe provocări în NLP implică: înțelegerea limbajului natural, care să permită calculatoarelor să sustragă înțelesul inputului dintr-o limbă umană/naturală, iar altele implică generarea de limbaj uman/natural.

Acum putem împărții NLP în două componente:

Înțelegerea limbajului natural – Natural Language Understanding (NLU)

Generarea limbajului natural – Natural Language Generation (NLG)

Figura 1-1. Schema NLP [BarCol05]

1.1.2.1 Natural Language Understanding (NLU)

Înțelegerea limbajului natural implică mai multe procese:

Maparea datelor de intrare (input reprezentat în limbaj natural) în reprezentări utile.

Analiza diferitelor aspecte ale limbii. [TutsPointNLP]

1.1.2.2 Natural Language Generation (NLG)

Este procesul de generare de expresii și fraze semnificative în forma limbajului natural de la o anumită reprezentare internă.

Implică:

Planificare de texte – include achiziționarea conținutului relevant din baza de cunoștiințe.

Planificare de propoziții – include alegerea cuvintelor necesare, formând fraze semnificative, stabilind contextul propoziției.

Realizarea de texte – vizează ordonarea propozițiilor generate în texte contextuale.

Procesul de înțelegere a limbajului natural este mai complicat decât cel de generare al limbajului natural. [TutsPointNLP]

1.1.3 Dificultăți în procesul NLU

Limbajul natural prezintă o structură complexă și o formă extrem de bogată, pe scurt este foarte ambiguu. Există niveluri diferite de ambiguitate cum ar fi:

Ambiguitate lexicală-este un nivel primitiv aflat nivel de cuvânt (sensuri multiple ale cuvintelor-“mare” ca și adjectiv sau “mare” ca și substantiv).

Ambiguitate la nivel de sintaxă – o propoziție poate fi analizată în mai multe moduri (exemplu din limba engleză – “He lifted the beetle with red cap”. Propoziția poate fi analizată în două moduri și anume: a ridicat gândacul folosind capacul roșu sau a ridicat gândacul care avea un capac roșu).

Ambiguitate referențială – găsită în cazuri când referința se face folosind pronume (“Elena a mers la Ana. Ea a spus, sunt obosită.” – Care dintre cele două fete este obosită mai exact?).

O singură intrare poate avea mai multe sensuri.

Mai multe intrări pot avea un singur sens.

1.1.4 Pași în realizarea NLP

Există cinci pași generali în realizarea procesării limbajului natural: [TutsPointNLP]

Analiza Lexicală – Implică identificarea și analiza structurii cuvintelor. Lexiconul unei limbi înseamnă totalitatea cuvintelor și frazelor dintr-o anumită limbă naturală. Analiza lexicală împarte întregul text în paragrafe, propoziții și cuvinte.

Analiza Sintactică (Parsarea) – Presupune analiza cuvintelor dintr-o propoziție din punct de vedere grammatical și rearanjarea cuvintelor în așa fel încât să se evidențieze relațiile dintre cuvinte. Propoziții ca “The school goes to boy” sunt respinse de către analizatorul sintactic englezesc.

Analiza Semantică – Extrage sensul exact sau sensul din dicționar din cadrul textului. Textul este verificat pentru a afla înțelesul acestuia. Acest lucru este făcut prin maparea structurilor sintactice și a obiectelor în domeniul de activitate. Analizatorul semantic nu ține cont de propoziții ca “hot ice-cream” – propoziții lipsite de sens.

Integrarea Contextului – Sensul oricărei propoziții depinde de sensul propoziției anterioare. De asemenea sensul propoziției curente poate sugera sensul propozițiilor care urmează imediat ulterior.

Analiza Pragmatică – În cadrul acestei etape se reinterpretează ceea ce s-a spus cu adevăratul sens transmis. Etapa implică derivarea acelor aspecte de limbaj folosind cunoștiințe reale.

Figura 1-2. Pași in realizarea NLP [TutsPointNLP]

1.2 Data mining

1.2.1 Noțiuni introductive

Data mining sau „mineritul”(extragerea) de date este un subdomeniu în cadrul științei calculatoarelor. Este procesul computațional de descoperire a modelelor în cadrul unor seturi mari de date care implică metode aflate la intersecția inteligenței artificiale, învățare automată, statistică și sisteme de baze de date. Scopul general al procesului de extragere a datelor este de a extrage informații dintr-un set de date și transformarea acestora într-o structură ușor de înțeles pentru o utilizare ulterioară. [WikiDM]

Exploatarea datelor are ca sarcină analiza automată sau semi-automată a unor cantități mari de date pentru a extrage modele interesante, necunoscute anterior, cum ar fi grupuri de înregistrări de date (cluster analysis), înregistrări neobișnuite (detectarea anomaliilor – anomaly detection) și dependențe (association rule mining). Acest lucru implică, de obicei, folosirea unor tehnici de baze de date, cum ar fi indicii spațiali. Aceste modele pot fi apoi văzute ca un fel de rezumat al datelor de intrare și pot fi utilizate în analize ulterioare sau, de exemplu, în cadrul domeniului de învățare automată (machine learning) și în cadrul analizei predictive.

Cum poate extragerea de date să furnizeze informații importante, necunoscute, iar în același timp să poată prezice ceea ce va urma să se întâmple? Tehnica utilizată pentru a efectua aceste lucruri se numește modelare („modeling”). Modelarea este pur și simplu actul de construire a unui model într-o situație în care se știe răspunsul, iar apoi se aplică acest model într-o altă situație a cărei răspuns este necunoscut. Acesta tehnică de construire a unui model este o tehnică folosită de către oameni de foarte mult timp, cu siguranță, înainte de apariția calculatoarelor sau a tehnologiei de extragere a datelor. Cu toate acestea ceea ce se întâmplă cu adevărat pe calculator nu este cu mult diferit de modul în care oamenii construiesc modele. Calculatoarele sunt încărcate cu o mulțime de informații cu privire la o varietate de situații în care un răspuns este cunoscut, iar apoi un program software de extragere a datelor trebuie să ruleze prin acele informații și să filtreze caracteristicile datelor care v-or alcătui modelul. Odată ce modelul este construit acesta poate fi apoi utilizat în situații similare, în cazul în care răspunsul nu este cunoscut. [TheArling]

Ultimii ani au cunoscut o creștere dramatică a datelelor de tip text scris în limbajul natural, inclusiv pagini web, articole de știri, literatură științifică, email-uri, documente și „social media”, cum ar fi articole de tip blog, mesaje, recenzii și „tweet-uri”. Datele de tip text sunt unice, în sensul că acestea sunt, de obicei, generate în mod direct de către un om și nu de către un sistem informatic sau senzori de stări, și astfel sunt date deosebit de valoroase în descoperirea unor cunostiite despre opiniile și preferințele oamenilor, în plus față de numeroase alte tipuri de cunostiinte pe care le codificăm în texte. [CoursEra]

Așadar „mineritul” de texte, de asemenea, menționat ca și extragerea de date din cadrul textelor, se referă la procesul de obținere a informațiilor de înaltă calitate din cadrul textelor. Această informație cu caracter special este desprinsă din cadrul textelor prin conceperea de modele și tendințe prin mijloace, cum ar fi modele de învățare statistică. „Mineritul” de text implică, de obicei, procesul de structurare a textului de intrare (parsare, împreună cu adăugarea unor caracteristici lingvistice derivate și cu eliminarea altora, alături de inserarea ulterioară într-o bază de date), derivând modele în cadrul datelor structurate, și în final evaluarea și interpretarea textului de ieșire (output). [WikiTM]

1.3 Word Sense Disambiguation

Word Sense Disambiguation (dizambiguizarea sensului unui cuvânt) a prins contur ca și problemă computațională distinctă în primele faze ale domeniului de “Machine Translation”, făcându-l unul dintre cele mai vechi probleme în lingvistica computațională.

Dizambiguizarea sensului unui cuvânt (word sense disambiguation) se referă la procesul de clasificare automată al sensului unui cuvânt într-un anumit context. Un exemplu ar fi cuvântul “contact” (în limbă engleză) care poate avea nouă sensuri diferite ca și substantiv și două sensuri ca și verb. Dizambiguizarea sensului unui cuvânt a fost parte a procesării limbajului natural aproape de la apariția acestui domeniu de cercetare. În cadrul procesării limbajului natural, dizambiguizarea sensului unui cuvânt (Word Sense Disambiguation-WSD) este problema de a determina care sens al unui cuvânt este folosit într-un anumit context. WSD este de fapt o problemă de clasificare naturală: având ca și input un cuvânt cu toate sensurile lui provenite dintr-un dicționar, în care se clasifică o apariție a cuvântului în context, într-una sau mai multe dintre sensurile acelui cuvânt. Caracteristicile contextului (cum ar fi cuvintele învecinate) furnizează dovezi pentru clasificare.

Procesul de dizambiguizare a sensurilor cuvintelor a acaparat mai multă atenție în ultimul deceniu și ca urmare rezultatele s-au îmbunătățit. Acest proces poate fi folosit în cadrul mai multor aplicații, ca de exemplu aplicații de extragere de informații sau clasificare automată. O clasificare succintă a acestui proces poate fii împărțită în două tipuri de algoritmi, supervizati și nesupervizati. Un algoritm supervizat se bazează pe un set de date de antrenament pe care să le învețe sau cu care să își compare informațiile, marind acuratețea găsirii informațiilor utile, dorite. Un algoritm nesupervizat nu are nevoie de date de antrenament însă algoritmii supervizati prezintă o acuratețe mai mare dacă au la dispoziție un set de date de antrenament. [Creț15]

Acest proces poate fii abordat în mai multe moduri. Multe abordări se bazează pe diferite tehnici statistice, altele au nevoie de texte de antrenament, iar unele abordează metode de învățare nesupervizata. În cadrul lucrării de diplomă am ales să abordez algoritmul lui Lesk, modificat față de cel original, pentru a rezolva problema dizambiguizarii sensurilor cuvintelor. Folosirea algoritmului lui Lesk implică folosirea unui dicționar de cuvinte (în acest caz WordNet-ul englezesc) din care se preiau toate sensurile unui cuvânt care trebuie dizambiguizat, iar pentru a stabili un sens potrivit contextului se verifică cuvintele aflate într-o vecinătate în cadrul sensurilor cuvântului evaluat alegând sensul ce conține cele mai multe instanțe ale vecinilor. [EkeGol]

1.4 Word Sense Discrimination

În lingvistica computațională, discriminarea (sau inducția) sensului unui cuvânt este o problemă din cadrul procesării limbajului natural, care se referă la identificarea automată a sensurilor unui cuvânt. Având în vedere că rezultatul procesului de inducție a sensurilor unui cuvânt este un set de sensuri pentru cuvântul evaluat („sense inventory”), acest proces se află în strânsă legătură cu procesul de dizambiguizare al sensurilor unui cuvânt (WSD), proces care se bazează pe un set de sensuri predefinit în rezolvarea ambiguității cuvintelor într-un context anume [WikiWSI]. Este foarte bine cunoscut faptul că cea mai iritantă problemă pentru procesul de dizambiguizare al sensurilor unui cuvânt este determinarea definițiilor care dau sens acelui cuvânt. La bază, problema este una filozofică și lingvistică, care este departe de a fi rezolvată. Cu toate acestea, lucrul din domeniul procesării automate a limbajului a condus la mijloace practice în distingerea sensurilor unui cuvânt, cel puțin în măsura în care aceste mijloace sunt utile în procesarea de limbaj natural. [IdeErjTuf02]

1.5 Lesk algorithm

Algoritmul lui Lesk a apărut pentru prima data în anul 1986 în lucrarea “Automatic Sense Disambiguation Using Machine Readable Dictionaries: How to Tell a pine Cone from an Ice Cream Cone” scrisă de către Michael Lesk [Creț15]. Autorul a încercat să rezolve într-un mod automat, prin intermediul unui algoritm, problema sensurilor multiple ale cuvintelor, folosind contextul în care se află acel cuvânt. Deci algoritmul lui Lesk este folosit pentru a determina sensul unui cuvînt într-o vecinătate. Pentru a determina sensul unui cuvânt utilizând algoritmul lui Lesk se compară definițiile din dicționar a cuvântului respectiv cu toate definițiile celorlalte cuvinte din vecinătate. Definiția care este atribuită unui cuvânt este acea definiție care are cele mai multe cuvinte în comun cu celalalte definiții ale cuvintelor vecine. Algoritmul nu ține cont de definițiile atribuite anterior cuvintelor verificând de fiecare dată definițiile cuvântului cu definițiile cuvintelor vecine.

Pentru a demonstra funcționarea acestui algoritm se folosește ca exemplu fraza “pine cone” și se aplică algoritmul lui Lesk pentru a afla sensul cuvantelor din frază.

Cuvântul “pine” are 2 sensuri, conform dicționarului “Advanced Learner”:

Sens 1: “kind of evergreen tree with needle–shaped leaves”

Sens 2: “waste away through sorrow or illness”

Cuvântul “cone” are 3 sensuri:

Sens 1: “solid body which narrows to a point”

Sens 2: “something of this shape whether solid or hollow”

Sens 3: “fruit of certain evergreen tree”

Algoritmul lui Lesk presupune verificarea fiecărui sens al cuvântului “pine” cu fiecare sens al cuvântului “cone”. În urma verificării se constată că grupul de cuvinte “evergreen tree” apare într-unul din sensurile celor două cuvinte ”pine” și “cone”, ca urmare sensul 1 al cuvântului “pine” și sensul 3 al cuvântului “cone” sunt declarate ca fiind cele mai potrivite sensuri în contextul “pine cone”.

Analizând exemplu anterior putem spune că algoritmul pleacă de la premiza că un cuvânt poate fi dizambiguizat pe baza cuvintelor aflate în vecinătatea lui. Lesk pleacă de la ideea că definițiile din dicționar ale unui cuvânt împarte cuvinte comune cu definițiile unui alt cuvânt aflat în același context, iar în urma unor comparații de definiți putem determina sensul potrivit contextului.

Michael Lesk precizează că rezultatele obținute cu acest algoritm sunt între 20-70% în condițiile în care folosește propoziții scurte pentru input, pe baza a trei dicționare diferite: Webster’s 7th Collegiate, the Collins English Dictionary și the Oxford Advanced Learner’s Dictionary of Current English.

1.5.1 Implementarea algoritmului

În continuare prezentăm pseudocodul algoritmului original al lui Lesk:

for every word w[i] in the phrase

let BEST_SCORE = 0

let BEST_SENSE = null

for every sense sense[j] of w[i]

let SCORE = 0

for every other word w[k] in the phrase, k != i

for every sense sense[l] of w[k]

SCORE = SCORE + number of words that occur in the gloss of both sense[j] and sense[l]

end for

end for

if SCORE > BEST_SCORE

BEST_SCORE = SCORE

BEST_SENSE = w[i]

end if

end for

if BEST_SCORE > 0

output BEST_SENSE

else

output “Could not disambiguate w[i]”

end if

end for

După cum se poate observa în cadrul pseudocodului descris mai sus, logica acestui algoritm de dizambiguizare a sensurilor cuvintelor este:

se compară fiecare sens al cuvântului țintă cu toate sensurile cuvintelor din fereastra de context

pentru fiecare comparație de sensuri se atribuie un scor în funcție de numărul de suprapuneri dintre cuvinte

în final sensurile care au cele mai mari scoruri sunt atribuite cuvântului țintă și în acest fel se reușește dizambiguizarea sensurilor cuvintelor

1.5.2 Modificări ale algoritmului lui Lesk

Abordarea noastră asupra algoritmului lui Lesk diferă de implementarea originală prin faptul că pentru a determina sensul cuvintelor se folosește o fereastră de n cuvinte la stânga și n cuvinte la dreapta aflate în jurul cuvântului care trebuie evaluat. Algoritmul folosește la bază WordNet-ul englezesc ca și dicționar, ignorând cuvintele care nu apar în cadrul acestui dicționar, ca de exemplu (‘the’, ‘of’, ‘an’ etc. și de asemenea toate pronumele personale). [Baner02]

Algoritmul analizează dacă cuvintele învecinate cuvântului evaluat se regăsesc în cadrul definițiilor returnate de către dicționarul WordNet pentru cuvântul evaluat. În cazul în care cuvântul evaluat nu are decât o singură definiție în cadrul dicționarului WordNet atunci programul returnează acea definiție deoarece nu mai are rost să se analizeze acel cuvânt, având doar un singur sens. În caz contrar se verifică dacă în cadrul definițiilor cuvântului se regăsesc cuvintele învecinate, iar în cazul în care un cuvânt vecin apare într-una din definițiile cuvântului analizat acea definiție este considerată ca fiind cea care dă sensul cuvântului analizat. În cadrul programului se verifică dacă un cuvânt are definiții în cadrul dicționarului, în cazul în care un cuvânt nu are definiții se verifică ultima literă a cuvântului, iar în cazul în care aceasta este ‘s’ se elimină reluând din nou căutările, acest lucru elimină pluralul cuvintelor (în limba engleză pluralul este dat de litera ‘s’ plasată la sfârșitul cuvântului).

1.6 Programarea orientată pe obiecte

1.6.1 Încapsularea

Încapsularea este unul dintre cele patru fundamente ale programării orientate-obiect. Încapsularea se referă la gruparea datelor cu metode care operează acele date, păstrând datele în siguranță împotriva interferențelor și utilizărilor exterioare. Acest concept de încapsulare a datelor a condus la ideea importantă din cadrul programării orientate-obiect de ascundere a datelor. “Proprietatea unui membru de a fi privat este cea care stă la baza conceptului de încapsulare. Aceasta se referă la posibilitatea de a crea obiecte încapsulate, obiecte la care nu se pot accesa anumiți membri.” [Breazu02]

În limbajele de programare, încapsularea este folosită ca referință pentru una din două noțiuni similare, dar distincte, și câteodată folosite în combinație:

un mecanism de limbaj de restricționare a accesului direct la unele dintre componentele obiectului

o construcție de limbaj care facilitează gruparea datelor cu metodele (sau alte funcții) care operează pe acele date

Figura 1-3 – este un exemplu scris în limbajul C# care arată modul în care accesul la un câmp de date poate fi limitat prin utilizarea unui cuvânt cheie „private”.

Figura 1-3. Încapsularea [WikiOOP]

1.6.2 Moștenirea

În programarea orientată pe obiecte, moștenirea permite noilor obiecte să preia proprietățile obiectelor existente. O clasă care este folosită ca bază pentru moștenire se numește clasă de bază sau superclasă, iar clasa care moștenește o clasă de bază se numește clasă derivată. Moștenirea, încapsularea, abstractizarea și polimorfismul sunt cele patru concepte fundamentale ale programării orientate pe obiecte. [AdobeOOP]

Moștenirea este o alegere bună atunci când:

aveți posibilitatea să reutilizați codul din clasele potențial de bază

aveți nevoie să se aplice aceeași clasă și metode pentru diferite tipuri de date

vreți să modificați la nivel global clasele derivate prin schimbarea unei clase de bază

1.6.3 Polimorfismul

În programarea orientată pe obiecte, polimorfismul se referă la abilitatea unui limbaj de programare de a procesa obiecte în moduri diferite, în funcție de tipul lor de date sau de clasă. Mai precis, este abilitatea de a redefini metode pentru clasele derivate. Cuvântul „polymorphism” înseamnă a avea mai multe forme. În paradigma programării orientate-obiect, polimorfismul este adesea exprimat ca „o singură interfață, funcții multiple”. [TutsPointOOP]

Figura 1-4 exemplifică o tehnică de implementare a polimorfismului static și anume „Supraîncarcarea funcțiilor”. Tehnică ce permite existența mai multor definiții pentru o singură funcție în același domeniu de vizibilitate. Definițiile funcției trebuie să difere una de alta prin tipurile și/sau numărul de argumente.

Figura 1-4. Exemplu de supraîncărcare a unei funcții [CodeProjOOP]

1.6.4 Abstractizarea

Abstractizarea se referă la acțiunea de a lucra cu ceva ce știm cum se folosește, fără să știm cum anume funcționează în interior. Abstractizarea este ceva ce folosim în fiecare zi, este o acțiune care maschează toate detaliile unui anumit obiect care nu ne privesc și folosește numai detaliile, care sunt relevante pentru problema la care lucrăm. În cadrul programării orietate-obiect prin procesul de abstractizare, un programator ascunde toate datele irelevante despre un obiect, în scopul de a reduce complexitatea și de a crește eficiența. Abstractizarea se află în strânsă legătură cu ideea de ascundere a datelor din cadrul încapsulării. [WhatIsOOP]

Abstractizarea permite să se scrie cod, care lucrează cu structuri abstracte de date (dicționare, liste, tablouri etc). Putem lucra cu aceste structuri abstracte de date prin utilizarea interfețelor lor, fără a ne preocupa cu detaliile de implementare.

Figura 1-5 exemplifică un caz în care putem avea mai multe tipuri de lei, dar toate tipurile pot fii folosite ulterior într-un mod abstract prin tipul „Felidae”. Această abstractizare nu se referă la detaliile tuturor tipurilor de lei.

Figura 1-5. Exemplu de abstractizare [IntroOOP]

1.7 Mediu de dezvoltare (IDE)

Pentru dezvoltarea părții practice a acestei lucrări de diplomă am ales mediul de dezvoltare (IDE) Visual Studio oferit de cei de la Microsoft. Acest IDE oferă soluții de dezvoltare pentru mai multe tipuri de aplicații cum ar fi aplicații web, servicii web, windows forms, windows store sau windows API. Visual Studio permite scrierea de cod prin folosirea editorului integrat, care conține printre extensiile sale și o componentă „IntelliSense” (componentă ce ajută la completarea codului), precum și o componentă de restructurare a codului. IDE-ul Visual Studio suportă dezvoltarea unor aplicații scrise în mai multe limbaje de programare cum ar fi: C, C++, VB .NET, C# sau F#.

1.7.1 Limbajul de programare

În cadrul IDE-ului ales pentru dezvoltarea aplicației de diplomă am ales să folosesc limbajul C#. C# este un limbaj de programare dezvoltat de către Microsoft în cadrul inițiativei .NET condusă de către Anders Hejlsberg și este un limbaj de programare modern orientat-obiect care se bazează foarte mult pe limbajele de programare C și C++. Deoarece este un limbaj orientat-obiect, C# sprijină conceptele de încapsulare, moștenire și polimorfism. De asemenea toate variabilele și metodele, inclusiv metoda principală, punctul de intrare al aplicației, sunt încapsulate în definițiile de clasă. O clasă poate moșteni direct dintr-o singură clasă părinte, dar poate implementa oricâte interfețe. C# este proiectat să lucreze cu platforma Microsoft .NET cu scopul de a facilita schimbul de informații și de servicii pe web, precum și de a permite dezvoltatorilor să creeze aplicații extrem de portabile.

1.7.2 Telerik UI pentru WinForms

Am ales să folosesc colecția de controale UI (user interface) furnizată de către cei de la Telerik, deoarece oferă o gamă foarte variată de controale care dau un stil unic și aparte unei aplicații de tip WinForms. Telerik UI pentru WinForms include peste 110 controale UI care sunt disponibile pentru a construi cu ușurință o aplicație unică și cu un aspect vizual impresionant și diferit față de soluțiile oferite de către Visual Studio 2012.

1.8 ADO .NET

ActiveX Data Object .NET sau pe scurt ADO .NET este o bibliotecă software din cadrul arhitecturii .NET, formată din componente software care furnizează servicii de acces la date. ADO .NET oferă acces la o conexiune la baza de date folosind metode oferite de arhitectura .NET, aplicațiile utilizând conexiunea de date numai în timpul de achiziționare a datelor sau pentru actualizarea lor. ADO .NET oferă o punte de legătură între comenzile de front-end și baza de date. Obiectele de tip ADO .NET încapsulează operatiiunile de acces la date și controalele intereactioneaza cu aceste obiecte pentru a afișa date, ascunzându-se astfel detaliile privind demersul datelor. Deci putem spune că ADO .NET separă accesul la date de la manipularea datelor în componente discrete, care pot fi folosite separat sau împreună. În lucrul cu bazele de date ADO .NET folosește limbajul SQL, executând declarații SQL, ADO .NET poate efectua comenzii de tip SELECT, UPDATE, INSERT sau DELETE pentru citirea sau scrierea unei baze de date. ADO .NET încapsulează declarațiile SQL în comenzi de date sau proceduri. În cadrul unui proces de execuție al unei comenzi SQL, ADO .NET deschide o conexiune cu baza de date, execută comanda, iar în final închide conexiunea activă, creată înaintea execuție, cu bază de date, în acest fel oferind acces activ la o bază de date doar în momentul utilizării acesteia.

1.9 Sistemul de gestionare al bazelor de date (SGBD)

Deoarece în cadrul dezvoltării lucrării de diplomă a fost nevoie de suportul unei baze de date, am ales să folosesc un sistem de gestionare a bazelor de date oferit de către cei de la Microsoft ce poartă denumirea „Microsoft SQL Server” (MSSQL Server). Ca server de baze de date, acesta este un produs software ce are ca și principală funcție, stocarea și extragerea de date solicitată de către alte aplicații software, care pot rula fie pe același sistem informatic sau pe un alt sistem aflat într-o rețea oarecare (în acest caz utilizând servicii web). Am ales să folosesc versiunea MSSQL Server 2012 deoarece este considerată ca fiind cea mai stabilă versiune disponibilă în momentul redactării acestei lucrări.

1.9.1 SQL (Structured Query Language)

Limbajul SQL este un limbaj de interogare structurat care este folosit pentru a comunica cu o bază de date. În conformitate cu ANSI (institutul național american de standarde), este limbajul standard pentru sistemele de management al bazelor de date relaționale. Instrucțiuni SQL sunt utilizate pentru a efectua sarcini, cum ar fi actualizarea sau achiziționarea de date pe o bază de date. Limbajul SQL este folosit de un număr mare de SGBD-uri, cum ar fi: Oracle, Sybase, Microsoft SQL Server, Access, Ingres, etc. Deși majoritatea sistemelor de baze de date utilizează SQL, cele mai multe dintre ele au, de asemenea, propriile extensii care sunt de obicei utilizate doar pe sistemul respectiv. Cu toate acestea comenzile SQL standard, cum ar fi „SELECT”, „INSERT”, „UPDATE”, „DELETE”, „CREATE” și „DROP” pot fi folosite pentru a realiza tot ceea ce este nevoie în utilizarea unei baze de date.

1.10 GIT (sistem de control al versiunii)

Git este un sistem de control al versiunii, care este utilizat pe scară largă pentru dezvoltarea de software și alte sarcini de control al versiunii. Este un sistem de control distribuit de revizuire cu accent pe viteză, integritatea datelor, și suport pentru fluxurile de lucru distribuite, non-lineare. La fel ca și celelalte sisteme de control al versiunii distribuite, și spre deosebire de cele mai multe sisteme client-server, fiecare director de lucru GIT este ca și un „depozit”(repository) cu drepturi depline și cu o istorie completă de versiuni cu capacități de urmărire a versiunii, independent de accesul la rețeaua de internet sau de un server central. Am folosit GIT pentru a ține o evidență a aplicației dezvoltate, structurând aplicația pe versiuni, și în același timp folosind GIT am asigurat și o copie de rezervă pentru orice eventualitate. [WikiGIT]

1.11 Design Patterns

În ingineria software, un design pattern („model de proiectare”) este o soluție repetabilă generală a unei probleme care apare frecvent în proiectarea de aplicații software. Acest model nu este un model finit, care poate fi transformat direct în cod, mai degrabă este o descriere sau un șablon pentru modul de rezolvare a unei probleme, și poate fi folosit în mai multe situații diferite. Aceste modele sunt standardizate, fiind considerate cele mai bune practici pe care un programator le poate utiliza pentru a rezolva probleme comune în proiectarea aplicațiilor sau sistemelor software. Aceste modele/sablone de proiectare pot fi văzute ca și o abordare structurată pentru programarea calculatoarelor, aflate între nivelurile unei paradigme de programare și un algoritm concret.

Să presupunem că întâmpinăm o problemă de programare, cu siguranță, odată cu evoluția industriei software, cu aceeași problemă mulți alții sau confruntat deja, deci putem presupune că există un model de proiectare care ne arată cel mai bun mod posibil de rezolvare a problemei în cauză.

Aceste modele de proiectare sunt clasificate în 3 categorii:

modele creaționale: aceste modele vizează instantierea de clase. Această categorie poate fi împărțită în două subcategorii: modele de creare a claselor și modele de creare a obiectelor. În timp ce modelele de creare a claselor folosesc moștenirea într-un mod eficient, modelele de creare a obiectelor se bazează pe delegați.

modele structurale: această categorie se referă la compoziția claselor și a obiectelor. Modelele structurale de creație a claselor folosesc moștenirea pentru a construi interfețe, iar cele de creație a obiectelor definesc moduri pentru a compune noi obiecte în scopul obținerii de noi funcționalități.

modele comportamentale: în această categorie se vizează comunicarea obiectelor dintr-o clasă. Modelele comportamentale sunt acele modele care sunt preocupate cu comunicarea dintre obiecte.

1.11.1 Modelul Singleton

În ingineria software, modelul Singleton este un model de proiectare creational care restricționează instantierea unei clase la un singur obiect. Accest lucru este util atunci când este nevoie de exact un obiect pentru a coordona acțiuniile în cadrul sistemului. Conceptul este uneori generalizat la sisteme care funcționează mai eficient atunci când există un singur obiect, sau care limitează instantierea unui anumit număr de obiecte. Termenul de „Singleton” provine din conceptul matematic de sigleton, care se referă la un set cu exact un singur element.

Acest model are ca scop:

să asigure că o anume clasă are doar o singură instanță, și să furnizeze un punct global de acces la aceasta

să încapsuleze conceptele de inițializare „just-in-time” sau „first-use”

Constructorul clasei care se dorește a fi de tip Singleton trebuie să fie declarat privat, neapărat, aceasta având ca rezultat apelarea doar din cadrul clasei.

Modelul Singleton are la bază o metodă publică ce asigură crearea unei noi instanțe în cazul în care aceasta nu există deja. Dacă deja există o instanță, atunci această metodă returnează o referintă către acel obiect existent.

Figura 1-15 prezintă diagrama unei clase de tip Singleton. Variabila membru de tipul clasei Singleton și metoda de acces publică getInstance() sunt statice.

Figura 1-5. Diagrama unei clase de tip Singleton

Acest model prezintă o problemă în cazul în care aplicația rulează mai multe fire de execuție simultan ceea ce poate duce la mai multe instanțieri ale clasei de tip singleton. O soluție la această problemă ar fi ca obiectul să fie instanțiat la declarare și nu în corpul metodei publice de acces.

Acest șablon este folosit pentru a stoca variabile globale cum ar fi setări globale ale aplicației, un fel de clasă „MasterModel”. Toate celelalte clase vor putea folosi aceasta clasa „MasterModel”.

1.11.2 Modelul Repository

Modelul „Repository” a câștigat destul de multă popularitate de la momentul apariție lui, fiind introdus pentru prima dată în cadrul modelului „Domain-Driven” în 2004. În esența, acest model oferă o abstracție a datelor, astfel încât aplicația să poată lucra cu o simplă abstracție care are o interfață aproximativ ca ceea a colecțiilor. Adăugarea, eliminarea, actualizarea și selectarea elementelor din această colecție se face printr-o serie de metode simple, fără a avea de a face cu preocupările legate de a bază de date, cum ar fi conexiuni, comenzi, cursoare sau cititori. Cu toate că modelul este foarte popular (sau poate chiar din această cauză), este, de asemenea, în mod frecvent înțeles și utilizat în mod greșit. [DeviqDesignP]

În cadrul dezvoltării de aplicații software, logica de business a aplicație accesează locații de memorie a datelor, cum ar fi baze de date sau servicii web. În cazul în care aplicația oferă acces direct la date pot rezulta următoarele:

cod dublicat

expunere ridicată la apariția erorilor de programare

dificultate în centralizarea politicilor legate de date, cum ar fi procesul de cache-ing

incapacitatea de a testa cu ușurință logica de business într-un mod izolat de dependințele externe

Acest model, modelul „Repository”, se utilizează pentru a realiza unul sau mai multe din următoarele obiective:

se dorește să se maximizeze cantitatea de cod ce poate fi testată automat și pentru a izola stratul de date cu scopul de a sprijini procesul de testare

se dorește aplicarea unor reguli de acces coerente gestionate la nivel central în cazul accesului multiplu la nivelul de date

se dorește să se îmbunătățească mentenabilitatea și lizibilitatea codului prin separarea logicii de business de logica datelor

se dorește simplificarea logicii de business prin aplicarea unui model de domeniu

se dorește asocierea unui comportament cu datele aferente

Figura 1-6. Interacțiuni în cazul unui model „Repository” [MsdnDesignP]

1.12 Dicționarul WordNet

Este un vis, în cadrul domeniului de inteligență artificială, de a avea algoritmi de citit și de obținere a unor cunostiinte dintr-un text în mod automat. Prin aplicarea unui algoritm de învățare a textului, oamenii au reușit să dezvolte metode care pot identifica într-un mod automat conceptele și relațiile dintre ele din cadrul unui text.

WordNet este o bază mare de date lexicală a limbii engleze. Substantive, verbe, adjective și adverbe sunt grupate în seturi de sinonime cognitive (synset-uri), fiecare exprimând un concept distinct. Synset-urile sunt interconectate prin intermediul unor relații conceptuale-semantice și lexicale. WordNet-ul a fost creat în laboratorul de știință cognitivă de la universitatea Princeton, sub îndrumarea profesorului de psihologie George Miller Armitage, începând din 1985 și a fost sub indrumarea lui Christiane Fellbaum în ultimii ani.

Principala relație dintre cuvintele din WordNet este sinonimia, ca de exemplu între cuvintele „shut” și „close” sau „car” și „automobile”. Sinonimele – cuvinte care denotă același concept și care sunt interschimbabile în mai multe contexte – sunt grupate în seturi neordonate (synset). Fiecare din cele 117.000 de synset-uri este legat de alte synset-uri prin intermediul unui număr mic de „relatii conceptuale”. În plus, fiecare synset conține o scurtă definiție (gloss) și, în cele mai multe cazuri, una sau mai multe fraze scurte care ilustrează utilizarea membrilor synset-ului. Cuvintele care au mai multe sensuri sunt grupate în cât mai multe synset-uri distincte, astfel fiecare pereche în cadrul dicționarului WordNet este unică. [WordNetP]

CAPITOLUL 2. DEZVOLTAREA APLICAȚIEI

2.1 Descrierea generală a aplicației

Aplicația „WordSenseDiscrimination” pe care am dezvoltat-o în cadrul lucrării de licență are ca și obiectiv principal implementarea unui program, care să fie capabil să dizambiguizeze sensul cuvintelor din limba engleză în funcție de context. Aplicația folosește la bază dicționarul englezesc WordNet, din care extrage definițiile cuvântului evaluat. Folosind o adaptare a algoritmului lui Lesk aplicația verifică prezența a n cuvinte vecine cuvântului evaluat în cadrul definițiilor acestuia, iar în cazul în care un cuvânt vecin se află în cadrul unei definiții atunci acea definiție este considerată a fii cea potrivită pentru a da sens acelui cuvânt.

Pe lângă inputul standard al aplicație, în care inputul este o propoziție, iar cuvântul care se dorește a fi dizambiguizat este specificat manual de către utilizator, rezultatele fiind afișate pe interfața grafică, aplicația mai poate primi ca și input și un fișier text pe care îl va citi și din care va extrage toate cuvintele prezente și ulterior va încerca să le dizambiguizeze, returnând rezultatele într-un alt fișier text.

După cum am specificat anterior, în dezvoltarea aplicației practice pentru lucrarea de diplomă am folosit următoarele:

Mediul de dezvoltare Visual Studio 2012

Limbajul de programare C#

Controale Telerik pentru interfața grafică a aplicației

Microsoft SQL Server 2012 pentru lucrul cu baza de date

GIT ca și sistem de control a verisunii aplicației

Figura 2-1. Principala fereastră grafică a aplicației „WordSenseDiscrimination”

În momentul pornirii aplicației, utilizatorului îi este prezentată fereastra grafică care se poate observa mai sus. În cadrul ferestrei sunt prezente mai multe controale pe care utilizatorul le poate folosi. Primul control, în dreptul etichetei „Enter sentence: ”, este un text box în care utilizatorul are posibilitatea de a introduce o propoziție, în limba engleză, pentru a fi folosită în determinarea contextului. Cel de al doilea control, de lângă eticheta „Enter word: ”, este de asemea un text box care permite introducerea unui cuvânt din cadrul propoziției furnizate mai sus, cu scopul de a dizambiguiza respectivul cuvânt în cadrul contextului determinat cu ajutorul propoziției curente. După introducerea propoziției și a cuvântului care se dorește a fi dizambiguizat, utilizatorul trebuie să apese pe butonul „Search” pentru a începe procesul de dizambiguizare. După apăsarea butonului de „Search” aplicația va returna toate definițiile cuvântului introdus de către utilizator, pe care le va afișa folosind controlul list view aflat sub eticheta „Definitions: ”, iar ulterior după terminarea procesului de dizambiguizare, toate potențialele definiții ale cuvântului vor fi afișate, folosind de asemea un control de tip list view, sub eticheta „Possible definitions for the entered word in this context: ”. Butonul „File” permite utilizatorului să încarce un fișier de tip text din care aplicația va extrage și dizambiguiza fiecare cuvânt salvând rezultatele într-un alt fișier de tip text.

2.2 Actors and UseCases

Aplicația „WordSenseDiscrimination”, în cadrul versiunii curente, prezintă un singur actor care participă la buna desfășurare a flow-ului, acesta fiind utilizatorul care poate folosi aplicația.

Acest actor, utilizatorul, are stabilite niște cazuri de folosință (sau „UseCases”) specifice:

Utilizatorul poate să folosească integral aplicația, prin pornirea acesteia și utilizând controalele puse la dispoziția lui.

Utilizatorul poate dizambiguiza un cuvânt oarecare aflat într-un anume context.

Precondiții: orice text sau cuvânt introdus de către utilizator trebuie să fie în limba engleză.

Scenariul ideal: utilizatorul introduce o propoziție în câmpul din dreptul etichetei „Enter Sentence: ”, un cuvânt pe care dorește să îl dizambiguizeze din cadrul propoziției furnizatate, cuvântul fiind introdus în câmpul din dreptul etichetei „Enter word: ”, iar in urma apăsării butonului „Search” va începe procesul de dizambiguizare. Rezultatele procesului de dizambiguizare vor fi afișate pe interfața grafica a aplicației sub eticheta „Possible definitions for the entered word in this context: ”.

Excepții: dacă textul inserat de către utilizator este în altă limbă decât limba engleză atunci nu vor exista rezultate.

Utilizatorul poate opta să dizambiguizeze un fișier de tip text.

Precondiții: conținutul fișierului trebuie să fie scris în limba engleză.

Scenariul ideal: pentru a utiliza modul de dizambiguizare al fișierelor de tip text din cadrul aplicației „WordSenseDiscrimination”, utilizatorul trebuie să apese butonul „File”. După apăsarea butonului „File” utilizatorul are posibilitatea de a alege orice fișier de tip text pe care dorește să îl dizambiguizeze. După încărcarea fișierului în aplicație utilizatorul trebuie să apese butonul „Search” pentru a începe procesul de dizambiguizare al fișierului ales. Rezultatele vor fi disponibile sub forma unui fișier de tip text generat de către aplicație.

Excepții: în cazul în care aplicația nu va putea dizambiguiza un cuvânt din cadrul fișierul acesta va lipsi din cadrul fișierul rezultat în urma dizambiguizarii.

2.3 Arhitectura aplicației

Pentru dezvoltarea părtii practice a acestei lucrări de diplomă am ales mediul de dezvoltare (IDE) Visual Studio oferit de cei de la Microsoft. Acest IDE oferă soluții de dezvoltare pentru mai multe tipuri de aplicații cum ar fii aplicații web, servicii web, windows forms, windows store sau windows API. Acest mediu de dezvoltare este foarte cunoscut pentru soluțiile puternice de dezvoltare oferite pentru crearea de aplicații windows forms, lucru ce m-a îndemnat să aleg această soluție pentru dezvoltarea aplicație „WordSenseDiscrimination”. Deși aplicațiile web au acaparat foarte multă atenție în ultimul timp, aplicațiile windows încă sunt în topul celor mai utile aplicații software.

Calitatea aplicațiilor software, în general, este influențată de aspectele arhitecturale folosite în dezvoltarea acestora. Lipsa acestor aspecte influențează negativ calitatea aplicațiilor. De multe ori performanța scăzută sau problemele de funcționare ale unei aplicații software sunt cauzate de folosirea unei arhitecturi neadcvate.

Astfel pentru a evita o dezvoltare eronată, din punct de vedere arhitectural, am ales să aplic principiul de design „Separation of Concerns”, principiu care oferă posibilitatea de a divide aplicația în mai multe module, fiecare având un rol bine definit și care adresează un anumit set de informații. Aplicațiile care adoptă acest principiu poartă denumirea de aplicații modulare. Modularitatea acestor aplicații provine din încapsularea sectiuniilor, astfel ascunzând informațiile cuprinse de acele secțiuni.

Modelul software arhitectural care aplică acest principiu de design, „Separation of Concerns”, este Model-View-Controller (sau MVC). Acest model arhitectural permite separarea funcționalității unei aplicații software de interfața grafică a acesteia, permițând o dezvoltare modulară rezultând într-o mai bună întreținere și testare a aplicației.

Figura 2-2. MVC – relațiile structurale între cele trei părți componente ale arhitecturii MVC

Model – această componentă gestionează datele sistemul, satisface toate cererile solicitate de componenta view cu privire la starea sistemului și realizează operații de modificare a datelor, dictate de către componenta controller. Componenta model din cadrul aplicație „WordSenseDiscrimination” este reprezentată cu ajutorul mai multor clase aflate în directorul „Models” din cadrul aplicației. În continuare voi prezenta una dintre aceste clase, și anume clasa „PossibleDefinitionEntity.cs”.

Figura 2-3. Clasa „PossibleDefinitionEntity.cs”

În cadrul exemplului, primul lucru care se poate remarca, este modul abordat de scriere a codului, și anume modul de scriere a clasei și a membrilor și metodelor ei folosind conceptul de „CamelCase”. Acest stil de scriere a codului este recomandat deoarece utilizând acest stil de scriere, codul redactat devine mai lizibil și mai ușor de citit de persoane externe.

Al doilea aspect care se deprinde din cadrul exemplului de mai sus este faptul că această clasă se află în directorul „Models” din cadrul proiectului, iar dacă se analizează denumire acestei clase putem observa că se finalizează folosind cuvântul „Entity”, fapt ce sugerează rolul clasei, care este un model/entitate în cadrul aplicației. Acest aspect este relevant deoarece sugerează oarecum rolul claselor în cadrul proiectului.

Un alt aspect important ce se poate observa, din exemplul anterior, este legat de proprietatiile clasei care sunt de formă „getter” și „setter”. Acest lucru permite modelului/entității de a furniza informații cu privire la conținutul modelului și permite setarea proprietatiilor modelului.

Membrii acestei entități sunt relevanți pentru aplicația „WordSenseDiscrimination” deoarece acești membrii sunt esențiali în procesul de dizambiguizare, aceștia reprezentând proprietăți ale unei entități care reprezintă o definiție posibilă a unui cuvânt într-un context anume. Câmpurile „definition” și „matchCounter” din cadrul entității „PossibleDefinitionEntity” reprezintă proprietăți specifice în cadrul aplicației. În timpul procesului de dizambiguizare această entitate reprezintă o posibilă definiție, câmpul „definition” reprezentând definiția din dicționar a cuvântului care poate da sensul acelui cuvânt, iar câmpul „matchCounter” reprezintă numărul de instanțe ale cuvintelor vecine regăsite în cadrul unei definiții ale cuvântului, ulterior acest contor generează procentul de potrivire al unei definiții pentru un cuvânt într-un anume context.

View – este componenta care se ocupă cu redarea modelului într-o fereastră grafică de interacțiune cu utilizatorul. În cadrul aplicațiilor windows forms view-urile sunt clase derivate din clasa „Form”, moștenind clasa „Form” aceste clase devin ferestre grafice care permit interacțiunea utilizatorului cu aplicația.

Figura 2-4. View-ul aplicației „WordSenseDiscrimination”

În cadrul view-ul prezentat anterior, se poate observa că utilizatorul a completat câmpul „Enter sentence: ”, în acest fel furnizând aplicației o propoziție care sugerează contextul, iar în câmpul „Enter word: ” a introdus cuvântul din cadrul contextului pe care dorește să îl dizambiguizeze. După completarea celor două câmpuri utilizatorul apasă butonul „Search”, iar aplicația returnează toate definițiile din dicționar ale cuvântului care trebuie dizambiguizat, iar ulterior va afișa definițiile care dau cel mai bine sensul acelui cuvânt.

Controller – această componentă este preocupată cu recepționarea acțiuniilor unui utilizator și căruia îi răspunde interogând modelul sistemului. În următorul exemplu voi prezenta o metodă care manipulează datele noastre.

Figura 2-5. Funcția „UseLeskAlgorithm”

După cum se poate observa în Figura 2-5 avem funcția „UseLeskAlgorithm” care are rolul de a prelua de pe interfața grafica a aplicație informațiile furnizate de către utilizator cu scopul de a dizambiguiza cuvântul furnizat de către utilizator. Această funcție primește ca și parametrii propoziția și cuvântul furnizate de către utilizator, obține toate definițiile cuvântului după care crează un obiect de tip „LeskAlgorithm” care este construit în funcție de contextul furnizat (și anume propoziția), cuvântul care trebuie dizambiguizat și definițiile acelui cuvânt. După crearea obiectului, funcția apelează metoda „ResolveLeskAlgorithm” a obiectului în scopul de a obține posibilele sensuri ale cuvântului, iar în final returnează toate definițiile care pot da sens cuvântului într-un anume context.

Acestea sunt cele trei componente ale arhitecturii MVC. Fiecare dintre aceste trei componente are un rol bine stabilit care împreună construiesc o arhitectură simplă, însă adoptând această arhitectură se pot dezvolta aplicații complexe și foarte bine optimizate.

Pe lângă arhitectura prezentată anterior, o altă componentă esențială în dezvoltarea unei aplicații serioase este prezența unei baze de date.

Primul pas în utilizarea unei baze de date în cadrul aplicație a fost alegerea unei tehnologii, iar alegerea mea a fost una dintre soluțiile Microsoft și anume Microsoft SQL Server. După alegerea tehnologiei a fost nevoie de un sistem de management al bazelor de date, iar în acest caz am instalat SQL Server Management 2012. După instalarea mediul de lucru cu baza de date, am creat o instanță a dicționarului englezesc WordNet.

După importarea dicționarului WordNet sub formă de bază de date, a fost nevoie de stabilirea unei legături între partea de cod a aplicației și baza de date, iar pentru realizarea acestei legături am ales una din componentele bibliotecii .NET și anume ADO. Utilizând pachetul de librării ADO.NET am reușit să realizez o conectare simplă între baza de date și aplicație. Primul pas a fost stabilirea unei conexiuni cu baza de date, lucru realizat prin intermediul clasei „SqlConnection”, folosind ca și parametru connectionString-ul (sau strîng-ul de conectare) de la baza de date.

Figura 2-6. Funcția „ConnectToDatabase”

Manipularea conexiunii cu baza de date în orice aplicație este un proces delicat. În dezvoltarea conexiunii cu baza de date am ales să aplic un model de proiectare cunoscut ca și „Singleton”. Acest model oferă posibilitatea de menținere a unei singure conexiuni deschise cu baza de date pe tot parcursul rulării aplicației, reducând astfel traficul cu baza de date. La terminarea ciclului de viață al aplicației, conexiunea cu baza de date se încheie.

În urma stabilirii conexiunii cu baza de date, toate comenziile SQL pe care dorim să le executăm le scriem sub formă de string pe care cu ajutorul lui ADO putem să le transmitem ca și parametrii la o clasă de tip SQLCommand, astfel reușind să executăm comenzii SQL într-un mod simplu și ușor.

Deasemenea, în realizarea unei arhitecturi optime pentru aplicația „WordSenseDiscrimination”, am ales să folosesc și modelul „Repository” cu scopul de a abstractiza pe module părțile funcționale ale aplicației. Una dintre părțile funcționale ale aplicației este baza de date. Toate informațiile din cadrul bazei de date sunt reprezentate sub formă de tabele, iar pentru a interacționa cu aceste informații trebuie să le mapam în modelele aplicației de la nivelul codului. În realizarea acestui lucru am introdus partea de „Services” care are rolul de mapare a informațiilor din cadrul bazei de date. Prin aplicarea acestor principii am reușit să mă asigur că toate informațiile persistă, iar în cazul în care avem nevoie de a citi sau de a scrie informații putem realiza acest lucru printr-o simplă interogare.

CAPITOLUL 3. DETALII DE IMPLEMENTARE

3.1 Introducere

Aplicația „WordSenseDiscrimination” este structurată în două părți principale, și anume partea de rezolvare a procesului de discriminare a sensurilor cuvintelor folosind algoritmul lui Lesk, iar cealaltă componentă este partea de interacțiune cu un utilizator în scopul dizambiguizării sensurilor cuvintelor aflate într-un context anume. Fiecare componentă este independentă una de cealaltă, oferind o posibilitate de modificare a fiecăruia în parte.

3.2 Procesul de discriminare folosind algoritmul lui Lesk

Pentru început țin să menționez că scopul principal al aplicației „WordSenseDiscrimination” este de a discrimina sensul unui cuvânt aflat într-un context specific utilizând un dicționar englezesc, și anume WordNet. Acest fapt face ca procesul de discriminare folosind algoritmul lui Lesk să stea la baza aplicației, fiind cel mai important proces.

Acest proces nu este „vizibil” unui utilizator, însă este un proces pe care un utilizator îl folosește implicit atunci când utilizează aplicația în scopul de a discrimina un cuvânt. Utilizatorul are la dispoziție toate controalele disponibile pe interfața grafică a aplicației „WordSenseDiscrimination”.

Figura 3-1. Funcția „UseLeskAlgorithm”

În momentul în care un utilizator pornește aplicația „WordSenseDiscrimination” acestuia îi este prezentat pe ecran fereastra grafică a aplicației, punându-i la dispoziție o serie de controale pe care le poate folosi în scopul de a dizambiguiza un cuvânt. Este de menționat faptul că aplicația funcționează doar în cazul în care limba pe care o folosește utilizatorul, în scopul utilizării aplicației, este limba engleză. Am ales limbă engleză deoarece la baza aplicației am folosit un dicționar englezesc, și anume WordNet-ul englezesc.

După interacțiunea utilizatorului cu aplicația, și anume completarea câmpurilor în scopul dizambiguizarii unui cuvânt într-o propoziție/frază, intră în acțiune procesul de dizambiguizare prin funcția, prezentată mai sus „UseLeskAlgorithm”. După cum am prezentat-o și anterior ca și „Controller” această funcție primește ca și parametrii propoziția și cuvântul furnizate de către utilizator, obține toate definițiile cuvântului prin apelarea serviciului „GetDefinitionForEnteredWord”, după care crează un obiect de tip „LeskAlgorithm” care este construit în funcție de contextul furnizat (și anume propoziția), cuvântul care trebuie dizambiguizat și definițiile acelui cuvânt.

Figura 3-2. Funcția „GetDefinitionForEnteredWord”

Dacă analizăm funcția „GetDefinitionForEnteredWord” putem observa că această funcție primește că și parametru cuvântul care se dorește a fii dizambiguizat de către utilizator. Funcția salvează într-o structură de date de tip lista de stringuri rezultatele returnate de către funcția apelată, și anume „GetDefinitionsFromWordNet” căruia îi transmitem cuvântul ca și parametru.

Figura 3-3. Funcția „GetDefinitionsFromWordNet”

Funcția „GetDefinitionsFromWordNet” preia cuvântul venit ca și parametru și obține id-ul acelui cuvânt în cadrul dicționarului WordNet prin apelarea funcției „GetWordId”, iar în final returnează toate definițiile cuvântului evaluat prin apelul funcției „GetDefinitions” cu parametrul wordId care semnifică id-ul cuvântului în cadrul dicționarului WordNet.

Figura 3-4. Funcția „GetWordId”

Figura 3-5. Funcția „GetDefinitions”

Funcția „GetWordId” și funcția „GetDefinitions” sunt de fapt bucăți de cod (funcții) care execută comenzi SQL cu un scop bine definit, și anume „GetWordId” interoghează tabela „Words” din cadrul bazei de date WordNet (denumită WN3 – versiunea de WordNet utilizată) cu scopul de a obține „WordId”-ul unui cuvânt („Lemma”), iar funcția „GetDefinitions” interoghează tabela „Senses” cu scopul de a obține toate definițiile unui cuvânt anume, utilizând id-ul acelui cuvânt ca și reper de căutare.

După maparea tuturor definițiilor a acelui cuvânt într-o lista de stringuri, și anume „definitionsFromWordNet”, funcția „GetDefinitionForEnteredWord” verifică dacă există măcar o definiție a acelui cuvânt, iar în cazul în nu există nici măcar o singură definiție a cuvântului returnată de către dicționarul WordNet atunci începe un proces de eliminare a pluralului cuvintelor din limbă engleză. Acest proces începe prin extragerea ultimei litere a cuvântului (char lastLetter = word[word.Length – 1];), după care verifică dacă ultima literă este egală cu litera ‚s’, iar în cazul în care condiția este îndeplinită atunci se elimină ultima literă și se reiau căutările.

După executarea funcției „GetDefinitionForEnteredWord” și crearea obiectului „wordSenseDiscrimination”, de tip „LeskAlgorithm”, se apelează metoda „ResolveLeskAlgorithm”, metodă disponibilă obiectelor de tip „LeskAlgorithm”. Rezultatul acestui apel se mapeaza într-o structură de date de tip lista de entități, și anume „PossibleDefinitionEntity”. Această entitate este o clasă de tip „setter” și „getter” care poate furniza sau modifica informații despre un anumit tip de date, în cazul nostru informații despre o definiție a cuvântului și despre câte instanțe de cuvinte vecine se regăsesc în acea definiție.

Figura 3-6. Funcția „ResolveLeskAlgorithm”

Prin apelul acestei metode se apelează intern metoda privată „GetPossibleDefinitionsForTheEnteredWord” cu parametrul „this.definitionsForTheEnteredWord” care este de fapt lista de definiții a obiectului creat de tip „LeskAlgorithm”, care cuprinde toate definițiile cuvântului din cadrul dicționarului WordNet, returnând rezultatul acestui apel sub formă de lista de entități de tip „PossibleDefinitionEntity”.

Figura 3-7. Funcția „GetPossibleDefinitionsForTheEnteredWord”

În momentul în care se apelează funcția „GetPossibleDefinitionsForTheEnteredWord” se crează mai întâi o listă de entități de tipul „PossibleDefinitionEntity”. După crearea listei „possibleDefinitions” se crează o variabilă booleană, și anume „definitionFound” care se inițializează cu false. Ulterior se crează o variabilă de tip integer, denumită „wordPositionInSentence”, care este inițializată cu rezultatul returnat din apelul funcției „GetWordPositionInSentence” cu parametrul 0.

Figura 3-8. Funcția „GetWordPositionInSentence”

În cadrul funcției „GetWordPositionInSentence”, în scopul aflării poziției cuvântului evaluat în cadrul propoziției contextuale, se verifică fiecare cuvânt din propoziție dacă este cuvântul care trebuie evaluat, prin apelarea unei metode din clasa „MasterModel”, și anume „ContainsWord” apelat cu parametrii word și this.wordToDiscriminate, care reprezintă cuvânt curent din cadrul propoziție și cuvântul de bază care trebuie evaluat. În urma execuției, „GetWordPositionInSentence” returneza poziția cuvântului care trebuie evaluat în cadrul propoziției contextuale.

Figura 3-9. Funcția „ContainsWord”

Funcția „ContainsWord” verifică printr-un regex dacă două cuvinte coincid, indiferent dacă sunt scrise diferit, și anume unul este scris cu litere mari, iar celălalt este scris doar cu litere mici, ignorând astfel problemele de sintaxă ale cuvintelor. După verificare, funcția returnează true sau false în funcție de rezultatul expresiei, dacă coincid sau nu cuvintele evaluate.

Revenind în funcția „GetPossibleDefinitionsForTheEnteredWord”, după aflarea poziției cuvântului în cadrul propoziției contextuale, se trece la o verificare a numărului de definiții ale cuvântului extrase din WordNet, iar în cazul în care există doar o singură definiție returnată de către dicționarul WordNet atunci considerăm că acea definiție este unica definiție care poate da sens cuvântului și o adăugăm în lista de entități creată, și anume „possibleDefinitions” prin apelarea metodei „AddPossibleDefinitionToList”, după care funcția returnează lista „possibleDefinitions” deoarece fiind o singură definiție disponibilă de analizat, procesul se încheie.

Figura 3-10. Funcția „AddPossibleDefinitionToList”

Funcția „AddPossibleDefinitionToList” primește ca și parametrii o listă de entități destinație și un string care reprezintă o definiție a cuvântului returnată de către WordNet. Intern metoda crează un obiect de tipul „PossibleDefinitionEntity” la care adaugă definiția cuvântului și atribuie contorului de potrivire, „MatchCounter”, valoarea 1 deoarece s-a găsit o instanță a vecinilor în cadrul definiției. După toate atribuirile efectuate pe câmpurile obiectului, acesta se adaugă în lista destinație, și anume în cazul nostru „possibleDefinitions”.

În cazul în care numărul definițiilor cuvântului sunt într-un număr mai mare decât 1 atunci se începe procesarea propoziției contextuale ale obiectului de tip „LeskAlgorithm”. În cadrul aplicației „WordSenseDiscrimination” în scopul dizambiguizarii cuvintelor am fost nevoit să folosesc algoritmul lui Lesk care presupune utilizarea unei „ferestre” de n cuvinte la stânga și n cuvinte la dreapta cuvântului evaluat în scopul determinării contextului. Așadar în cadrul clasei „LeskAlgorithm” am declarat o variabilă privată de tip integer, denumită „leskWindow” pe care am initializato cu valoarea 2. Această valoare a variabilei „leskWindow” sugerează dimensiunea „ferestrei” de cuvinte utilizată în procesul de dizambiguizare, și anume valoarea 2 semnifică faptul că vor fi analizate două cuvinte la stânga și două cuvinte la dreapta cuvântului care trebuie evaluat. În cadrul procesului de dizambiguizare, efectuat de către funcția „GetPossibleDefinitionsForTheEnteredWord” începe prin parcurgerea cuvintelor din cadrul propoziției de la 2 poziții la stânga față de poziția cuvântului care trebuie evaluat și oprinde-se la două poziții la dreapta față de poziția cuvântului (exemplu: să presupunem că poziția cuvântului „well” este 2 în cadrul propoziției „I feel well” – acest lucru înseamnă că vor fii analizate cuvintele „I” și „feel” fiind cuvintele aflate la stânga cuvântului evaluat și în cadrul ferestrei leskWindow). La prima iterație, în primul rând se verifică dacă cuvântul curent evaluat din cadrul propoziție este exact cuvântul care trebuie dizambiguizat, iar în cazul în care acest lucru este adevărat atunci se trece la următoarea iterație.

Figura 3-11. O parte din codul funcției „GetPossibleDefinitionsForTheEnteredWord”

În cazul în care cuvântul curent nu este cuvântul care trebuie dizambiguizat se continuă procesul de dizambiguizare. În următorul pas se verifică dacă pe poziția curentă, în cadrul propoziției, se află un element/cuvânt valid pentru a putea fi evaluat (if (this.sentenceWords.ElementAtOrDefault(i) != null)). În cazul în care, în urma verificării se constată că nu există un cuvânt valid pe poziția curentă atunci se trece la următoarea iterație, iar în caz contrar se continuă procesul de dizambiguizare.

În momentul în care există un cuvânt de evaluat, funcția extrage fiecare definiție din cadrul listei de definiții „definitionsForTheEnteredWord” disponibilă a cuvântului de dizambiguizat. Pentru fiecare definiție în parte se verifică dacă, definiția conține cuvântul învecinat cuvântului de dizambiguizat, aflat la poziția curentă în propoziție, utilizând funcția „ContainsWord”.

Figura 3-12. O parte din codul funcției „GetPossibleDefinitionsForTheEnteredWord”

În cazul în care cuvântul vecin nu se regăsește în cadrul definiției atunci se trece la următoarea definiție, iar în cazul în care cuvântul vecin, aflat pe poziția curentă se regăsește în cadrul definiției atunci se continuă procesul de dizambiguizare după cum urmează.

Figura 3-13. O parte din codul funcției „GetPossibleDefinitionsForTheEnteredWord”

Mai întâi se verifică conținutul listei „possibleDefinitions” pentru a ne asigura că nu există în cadrul acestei liste definiția analizată curent. În cazul în care în cadrul listei „possibleDefinitions” se regăsește definiția curentă atunci se incrementează contorul definiției respective, sugerând că s-a mai găsit o instanță a unui cuvânt vecin în cadrul aceleași definiții, mărind procentajul care sugerează că acea definiție ar da sensul corect cuvântului de dizambiguizat. După incrementarea contorului se setează variabilă booleană „definitionFound” pe true sugerând că definiția curentă există deja în cadrul listei de definiții posibile „possibleDefinitions”. În cazul în care definiția analizată nu există deja în cadrul listei de definiții „possibleDefinitions” atunci se adaugă definiția în lista „possibleDefinitions” prin apelul metodei „AddPossibleDefinitionToList”, iar după adăugarea definiției la lista de definiții „possibleDefinitions” se setează variabila „definitionFound” pe false pentru a sugera că s-a produs o adăugare nouă la lista de definiții „possibleDefinitions”. În urma realizării întregului proces de dizambiguizare funcția „GetPossibleDefinitionsForTheEnteredWord” returnează lista de definiții posibile ale cuvântului de dizambiguizat, și anume lista „possibleDefinitions”.

După execuția metodei „ResolveLeskAlgorithm” și atribuirea rezultatului returnat de această metodă la lista de definiții „possibleDefinitions” din cadrul funcției „UseLeskAlgorithm” se trece la următorul pas. Următorul pas implică apelarea metodei „ResolveLeskPercent” a obiectului „wordSenseDiscrimination”, apelată cu parametrul „possibleDefinitions”, care semnifică lista de definiții posibile ale cuvântului care trebuie dizambiguizat obținută anterior din apelul funcției „ResolveLeskAlgorithm”.

Figura 3-14. Funcția „ResolveLeskPercent”

În cadrul funcției „ResolveLeskPercent” se definesc două variabile de tip integer, și anume „maxPercent” și „matchOccurance”. Variabila „maxPercent” este inițializată cu valoarea 100 și semnifică procentul total maxim de potrivire al definițiilor pentru un cuvânt care trebuie dizambiguizat. Variabila „matchOccurance” este inițializată cu valoarea 0 deoarece plecăm de la premiza că nu există nici o instanță a cuvintelor vecine în cadrul definițiilor cuvântului principal, care trebuie dizambiguizat. Ulterior funcția parcurge toate entitățile din cadrul listei „possibleDefinitions” și pentru fiecare entitate în parte, adaugă la variabila „matchOccurance” contorul „MatchCounter”, obținând astfel toate instanțele cuvintelor vecine în cadrul definițiilor cuvântului principal. După ce s-a parcurs întreaga lista se verifică dacă variabila „matchOccurance” este diferită de 0, iar în cazul în care aceasta este într-adevăr diferită de 0 atunci se împarte „maxPercent” la „matchOccurance”, astfel împărțind procentul total de 100% la numărul total de instanțe găsite ale cuvintelor vecine în cadrul definițiilor cuvântului principal. La final se parcurge încă o data toată lista de entități „possibleDefinitions” și pentru fiecare entitate în parte, câmpul „MatchCounter” este înmulțit cu variabila „maxPercent” stabilind procentul de corectitudine al unei definiții.

După apelul funcției „ResolveLeskPercent”, funcția „UseLeskAlgorithm” returnează lista de entități „possibleDefinitions” care este ulterior folosită pentru a afișa toate definițiile care au un procent mai mare decât 0 de a da sensul corect al cuvântului principal într-un context anume.

Acesta este întregul proces de dizambiguizare al unui cuvânt aflat într-un anume context, care poate sau nu să dizambiguizeze corect un cuvânt, acest lucru depinzând de propoziția furnizată de către utilizator și de dicționarul englezesc WordNet, care poate sau nu să furnizeze informațiile necesare procesului de dizambiguizare.

3.3 Interacțiunea utilizatorului cu aplicația „WordSenseDiscrimination”

După cum am specificat anterior, pe lângă procesul de discriminare al cuvintelor folosind algoritmul lui Lesk care este componenta de bază a aplicației „WordSenseDiscrimination”, mai există încă o componentă importantă, și anume partea de interacțiune a aplicației cu un utilizator în scopul dizambiguizării sensului unui cuvânt aflat într-un context anume.

În momentul în care aplicația „WordSenseDiscrimination” pornește, pe ecranul utilizatorului apare fereastra principală a aplicației (Figura 2-1), utilizatorul putând să utilizeze setul de controale pus la dispoziție pentru a începe procesul de dizambiguizare a unui cuvânt sau al unui fișier de tip text.

Figura 3-15. Partea de input a aplicației

Partea de input a aplicației „WordSenseDiscrimination” constă din două controale de introducere de text, din partea utilizatorului, și dintr-un buton, și anume „File” care permite utilizatorului introducerea unui fișier de tip text pe care dorește să îl dizambiguizeze.

Utilizatorul introduce o propoziție în limba engleză, pentru a determina un context de dizambiguizare, iar ulterior introduce un cuvânt din cadrul propoziție pe care dorește să îl dizambiguizeze.

Figura 3-16. Exemplu de input

După introducerea propoziție și a cuvântului, bineînțeles în limba engleză, utilizatorul trebuie să apese be butonul „Search” de pe interfața aplicației „WordSenseDiscrimination”.

Figura 3-17. Butonul „Search”

În momentul când utilizatorul apasă butonul „Search” aplicația „WordSenseDiscrimination” apelează funcția „SearchButton_Click”. În cadrul acestei funcții, mai întâi se verifică dacă utilizatorul a încărcat un fișier de tip text. În cazul în care utilizatorul nu a optat pentru dizambiguizarea unui fișier atunci funcția extrage cuvintele din propoziția utilizatorului și le stochează pe fiecare în parte în cadrul unei liste de stringuri, denumită „contextSentence” (List<string> contextSentence = SentenceTextBox.Text.Split(MasterModel.stringDelimiters, StringSplitOptions.RemoveEmptyEntries).ToList();). După maparea cuvintelor din cadrul propoziției în lista „contextSentence” funcția elimină toate cuvintele redundante din cadrul listei „contextSentence” prin apelul metodei „RemoveRedundantWords” care primește ca și parametru referința listei „contextSentence”.

Figura 3-18. Funcția „RemoveRedundantWords”

În cadrul funcției „RemoveRedundantWords” se inițializează o variabilă booleană cu valoarea false, denumită „foundRedundantWord”, apoi se parcurge lista primită ca și parametru, iar fiecare cuvânt în parte este comparat cu fiecare cuvânt redundant din cadrul listei „redundantWords” definită în cadrul clasei MasterModel. În cazul în care un cuvânt din cadrul propoziție este de fapt un cuvânt care este definit în cadrul listei „redundantWords” atunci cuvântul respectiv este considerat redundant și este eliminat din cadrul propoziției/context. După execuția funcției „RemoveRedundantWords” și eliminarea tuturor cuvintelor redundante din context se apelează funcția „UseLeskAlgorithm”, iar rezultatul returnat este mapat într-o lista de entități, denumită „possibleDefinitions”. După obținerea listei de entități „possibleDefinitions”, obținută în urma executații procesul e dizambiguizare explicat anterior, pe interfața cu utilizatorul se vor afișa toate definițiile cuvântului extrase din cadrul dicționarului WordNet (DisplayDefinitionsForTheEnteredWord(WordSenseDiscriminationServices.GetDefinitionForEnteredWord(WordTextBox.Text));) și toate definițiile extrase care pot da sensul cuvântului (DisplayPossibleDefinitionsForTheEnteredWord(possibleDefinitions);).

Figura 3-19. Afișarea rezultatelor pe interfața grafică

În cazul în care utilizatorul dorește să dizambiguizeze un fișier atunci trebuie să apese pe butonul „File”. În momentul când utilizatorul apasă butonul „File” acestuia îi este permis să aleagă un fișier de tip txt din hard disk-ul personal. Odată ce a selectat fișierul, pe interfața grafică va apărea un mesaj care confirmă ca fișierul a fost încărcat cu succes urmând ca utilizatorul să apase butonul „Search” pentru a începe procesul de dizambiguizare al fișierului respectiv.

Figura 3-20. Mesajul de confirmare al încărcării fișierului cu succes

După ce utilizatorul apasă butonul „Search” aplicația „WordSenseDiscrimination” începe procesul de dizambiguizare al fișierului introdus de către utilizator. Tot conținutul fișierul, toate cuvintele conținute au fost mapate în cadrul listei de stringuri „fileContentList” în momentul încărcării fișierului. În primul rând, în cazul dizambiguizarii unui fișier, funcția „SearchButton_Click” elimină toate cuvintele redundante prin apelarea metodei „RemoveRedundantWords” cu referința listei „fileContentList” ca și parametru (MasterModel.RemoveRedundantWords(ref fileContentList);).

După încheierea procesului de eliminare a cuvintelor redundante din cadrul listei de cuvinte preluate din cadrul fișierului, funcția deschide o conexiunde de scriere într-un fișier de tip txt, în care va scrie toate rezultatele și care este denumit „SavedList.txt”. După deschiderea conexiunii cu fișierul „SavedList.txt” se preia fiecare cuvânt în parte, din cadrul listei „fileContentList”, iar pentru fiecare se rulează algoritmul de dizambiguizare având ca și context întreaga lista de cuvinte „fileContentList”. După maparea rezultatelor, obținute în urmă executării procesului de dizambiguizare, se parcurge lista de entități „possibleDefinitions”, iar fiecare posibilă definiție a unui cuvânt din cadrul fișierului se scrie în cadrul fișierului „SavedList.txt”.

Figura 3-21. Parcurgerea listei de cuvinte „fileContentList”

După parcurgerea tuturor cuvintelor și dizambiguizarea fiecăruia se închide conexiunea cu fișierul „SavedList.txt”. În urma închiderii conexiunii, utilizatorul va fii informat că aplicația „WordSenseDiscrimination” a finalizat procesul de dizambiguizare al tuturor cuvintelor din cadrul fișierului furnizat, prin afișarea unui mesaj pe interfața grafică a aplicației.

Figura 3-22. Mesajul de confirmare al finalizării procesului de dizambiguizare

Un exemplu de dizambiguizare a unui fișier, denumit „Test.txt” a produs următoarele rezultate:

Figura 3-23. Conținutul fișierului „Test.txt”

Figura 3-24. Conținutul fișierului „SavedList.txt” pentru fișierul „Test.txt”

După cum se poate observa nu toate cuvintele au putut fii dizambiguizate, iar altele au fost eliminate fiind cuvinte redundante. Există cuvinte care au primit mai multe sensuri în contextul curent însă sunt și cuvinte care au un singur sens, astfel reușindu-se o dizambiguizare în proporție de 100% pentru acele cuvinte.

CAPITOLUL 4. CONCLUZII ȘI DEZVOLTĂRI VIITOARE

4.1 Concluzii

În cele din urmă am reușit să dezvolt o aplicație, folosind limbajul C#, capabilă să dizambiguizeze în mod automat sensul cuvintelor folosindu-se de un context anume ca și reper. În scopul dizambiguizarii am ales să folosesc un dicționar englezesc, și anume dicționarul WordNet. Deși aplicația nu garantează o rată de succes de 100% în cazul tuturor cuvintelor, indiferent de context, dar pot spune că în momentul acesta aplicația reușește în mare parte să determine un sens corect al cuvintelor, sau în unele cazuri mai multe sensuri reducând astfel din numărul de sensuri al cuvintelor disponibile în cadrul dicționarului.

În dezvoltarea aplicației „WordSenseDiscrimination” am încercat să separ pe componente logica de bază, astfel am împărțit întreaga aplicație în două componente de bază, și anume procesul de dizambiguizare al cuvintelor folosind algoritmul lui Lesk (3.2) și procesul de interacțiune al aplicației cu un utilizator (3.3). Împărțind aplicația în două componente separate, am reușit să asigur o structură adecvată și susceptibilă unor schimbări ulterioare.

În ultimul timp cererea de aplicații scalabile și ușor mentenabile a devenit din ce în ce mai mare, iar în cadrul dezvoltării aplicației „WordSenseDiscrimination” am încercat să țin cont de aceste lucruri. Este foarte important să respectăm anumite tehnici de „best practices” pentru a realiza o aplicației ușor de întreținut și ușor de dezvoltat ulterior.

După cum am precizat anterior, scopul principal al aplicației este dizambiguizarea sensului cuvintelor într-un mod automat, fără un antrenament anterior, oferind posibilitatea de a dizambiguiza un cuvânt aflat într-un context anume la un moment dat. În realizarea acestui scop am ales să folosesc o adaptare diferită a algoritmului lui Lesk, și anume am ales să analizez o fereastră de n cuvinte vecine cuvântului de dizambiguizat în schimbul analizei întregului text, care este modul de funcționare al algoritmului lui Lesk implementat inițial. Adaptarea algoritmului lui Lesk abordată nu compară toate definițiile cuvintelor vecine cu toate definițiile cuvântului principal, în schimb algoritmul caută instanțe ale cuvintelor vecine în cadrul definițiilor cuvântului principal. În dezvoltarea aplicației am încercat să dezvolt o interfață cu utilizatorii (user interface – UI) cât mai ușor folosibilă și să oferă o experiență cât mai plăcută utilizatorului în folosirea aplicației (user experience – UX). În final consider că aplicația „WordSenseDiscrimination”, pe care am dezvoltat-o, își îndeplinește scopul, și anume dizambiguizarea sensului unui cuvânt aflat într-un anume context, însă mai există părți care ar putea fii îmbunătățite sau adăugate în cadrul dezvoltărilor ulterioare.

4.2 Dezvoltări viitoare

Aplicația „WordSenseDiscrimination” poate fii dezvoltată și îmbunătățită cu ușurință în cadrul dezvoltărilor ulterioare, fiind concepută de la început pe componente principale de funcționare.

În primul rând se poate îmbunătăți procesul de discriminare prin implementarea unui mecanism de învățare automată a sensurilor cuvintelor în contexte specifice (de exemplu – în cazul unui context „I feel well” în care se încearcă dizambiguizarea cuvântului „well”, aplicația „WordSenseDiscrimination” va determina un singur sens ca fiind cel corect, astfel putem salva contextul în care s-a regăsit cuvântul „well” și la următoarea analiză a acestui cuvânt, aflat într-un context similar, definiția va fi deja învățată de către aplicație).

O altă îmbunătățire a aplicației „WordSenseDiscrimination” ar putea fii implementarea mai multor dicționare, în diferite limbi, deci asigurarea unei aplicații de dizambiguizare a cuvintelor în diferite limbaje naturale, într-un mod automat. Deși în starea curentă aplicația „WordSenseDiscrimination” nu suportă decât limba engleză, implementarea unui nou limbaj natural ar face ca aplicația să fie disponibilă unui public mai larg decât cel pe care îl vizează acum, și anume vorbitorii de limba engleză.

În cele din urmă aplicația ar putea fii transformată într-un serviciu web (sau API) care să poată fii integrat cu ușurință în alte aplicații care au nevoie de funcționalitățile oferite de către aplicația „WordSenseDiscrimination”.

BIBLIOGRAFIE și WEBLIOGRAFIE

Inteligență artificială

[WikiAI]~https://en.wikipedia.org/wiki/Artificial_intelligence

Procesarea limbajului natural

[Callobert11]~http://www.jmlr.org/papers/volume12/collobert11a/collobert11a.pdf

[WikiNLP]~https://en.wikipedia.org/wiki/Natural_language_processing

[BarCol05]~http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-864-advanced-natural-language-processing-fall-2005/lecture-notes/lec01.pdf

[TutsPointNLP]~http://www.tutorialspoint.com/artificial_intelligence/artificial_intelligence_natural_language_processing.htm

Data mining

[WikiDM]~https://en.wikipedia.org/wiki/Data_mining

[TheArling]~http://www.thearling.com/text/dmwhite/dmwhite.htm

[CoursEra]~https://www.coursera.org/specializations/data-mining

[WikiTM]~https://en.wikipedia.org/wiki/Text_mining

Word sense disambiguation

[EkeGol]~Jonas Ekedahl & Koraljka Golub, Word sense disambiguation using WordNet and the Lesk algorithm

[Creț15]~Radu Crețulescu, Utilizarea tehnicilor de Natural Language Processing pentru îmbunătățirea reprezentării documentelor în algoritmi de învățare automată, Editura Universității ”Lucian Blaga” din Sibiu, 2015

Word sense discrimination (induction)

[WikiWSI]~https://en.wikipedia.org/wiki/Word-sense_induction

[IdeErjTuf02]~Nancy Ide, Tomaz Erjavec, Dan Tufis, Sense Discrimination with Parallel Corpora, 2002

Lesk algorithm

[Baner02]~Satanjeev Banerjee, Adapting the Lesk Algorithm for Word Sense Disambiguation to WordNet, 2002

Programare orientată pe obiecte

[Breazu02]~Macarie Breazu, Programare orientată pe obiecte. Principii, Editura Universității ”Lucian Blaga” din Sibiu, 2002

[WikiOOP]~https://en.wikipedia.org/wiki/Encapsulation_(computer_programming), https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)

[TutsPointOOP]~http://www.tutorialspoint.com/cplusplus/cpp_data_encapsulation.htm, http://www.tutorialspoint.com/csharp/csharp_polymorphism.htm

[AdobeOOP]~http://www.adobe.com/devnet/actionscript/learning/oop-concepts/inheritance.html

[MsdnOOP]~https://msdn.microsoft.com/en-us/library/27db6csx(v=vs.90).aspx

[CodeProjOOP]~http://www.codeproject.com/Articles/602141/Polymorphism-in-NET

[IntroOOP]~http://www.introprogramming.info/english-intro-csharp-book/read-online/chapter-20-object-oriented-programming-principles/#_Toc362296567

[WhatIsOOP]~http://whatis.techtarget.com/definition/abstraction

Mediul de dezvoltare și limbajul de programare în cauză

[WikiIDE]~https://en.wikipedia.org/wiki/Microsoft_Visual_Studio

[TutsPointC#]~http://www.tutorialspoint.com/csharp/

[WikiC#]~https://en.wikipedia.org/wiki/C_Sharp_(programming_language)

[MsdnC#]~https://msdn.microsoft.com/en-us/library/z1zx9t92.aspx

[WhatIsC#]~http://searchwindevelopment.techtarget.com/definition/C

ADO .NET

[TechoADO]~https://www.techopedia.com/definition/24703/activex-data-object-net-ado-net

[TutsPointADO]~http://www.tutorialspoint.com/asp.net/asp.net_ado_net.htm

[MsdnADO]~https://msdn.microsoft.com/en-us/library/h43ks021(v=vs.110).aspx

SGBD

[WikiSGBD]~https://en.wikipedia.org/wiki/Microsoft_SQL_Server

[SQLCourse]~http://www.sqlcourse.com/intro.html

GIT

[WikiGIT]~https://en.wikipedia.org/wiki/Git_(software)

Design Patterns

[WikiDesignP]~https://en.wikipedia.org/wiki/Software_design_pattern, https://en.wikipedia.org/wiki/Singleton_pattern

[SourceDesignP]~https://sourcemaking.com/design_patterns, https://sourcemaking.com/design_patterns/singleton

[MsdnDesignP]~https://msdn.microsoft.com/en-us/library/ff649690.aspx

[DeviqDesignP]~http://deviq.com/repository-pattern/

WordNet

[WordNetP]~https://wordnet.princeton.edu/

[MillerWN95]~George A. Miller (1995). WordNet: A Lexical Database for English. Communications of the ACM Vol. 38, No. 11: 39-41.

[FellbaumWN98]~Christiane Fellbaum (1998, ed.) WordNet: An Electronic Lexical Database. Cambridge, MA: MIT Press.

FIGURI

Figura 1-1. Schema NLP

Figura 1-2. Pași in realizarea NLP

Figura 1-3. Încapsularea

Figura 1-4. Exemplu de supraîncărcare a unei funcții

Figura 1-5. Diagrama unei clase de tip Singleton

Figura 1-6. Interacțiuni în cazul unui model „Repository”

Figura 2-1. Principala fereastră grafică a aplicației „WordSenseDiscrimination”

Figura 2-2. MVC – relațiile structurale între cele trei părți componente ale arhitecturii MVC

Figura 2-3. Clasa „PossibleDefinitionEntity.cs”

Figura 2-4. View-ul aplicației „WordSenseDiscrimination”

Figura 2-5. Funcția „UseLeskAlgorithm”

Figura 2-6. Funcția „ConnectToDatabase”

Figura 3-1. Funcția „UseLeskAlgorithm”

Figura 3-2. Funcția „GetDefinitionForEnteredWord”

Figura 3-3. Funcția „GetDefinitionsFromWordNet”

Figura 3-4. Funcția „GetWordId”

Figura 3-5. Funcția „GetDefinitions”

Figura 3-6. Funcția „ResolveLeskAlgorithm”

Figura 3-7. Funcția „GetPossibleDefinitionsForTheEnteredWord”

Figura 3-8. Funcția „GetWordPositionInSentence”

Figura 3-9. Funcția „ContainsWord”

Figura 3-10. Funcția „AddPossibleDefinitionToList”

Figura 3-11. O parte din codul funcției „GetPossibleDefinitionsForTheEnteredWord”

Figura 3-12. O parte din codul funcției „GetPossibleDefinitionsForTheEnteredWord”

Figura 3-13. O parte din codul funcției „GetPossibleDefinitionsForTheEnteredWord”

Figura 3-14. Funcția „ResolveLeskPercent”

Figura 3-15. Partea de input a aplicației

Figura 3-16. Exemplu de input

Figura 3-17. Butonul „Search”

Figura 3-18. Funcția „RemoveRedundantWords”

Figura 3-19. Afișarea rezultatelor pe interfața grafică

Figura 3-20. Mesajul de confirmare al încărcării fișierului cu succes

Figura 3-21. Parcurgerea listei de cuvinte „fileContentList”

Figura 3-22. Mesajul de confirmare al finalizării procesului de dizambiguizare

Figura 3-23. Conținutul fișierului „Test.txt”

Figura 3-24. Conținutul fișierului „SavedList.txt” pentru fișierul „Test.txt”

ANEXE

Funcția pentru încărcarea unui fișier, apelată în momentul când un utilizator apasă butonul „File”

Diagrama de clase

Similar Posts