Klassificering av homonymer Inlämningsuppgift språkteknologi 2013-01-10 Kurskod: DD2418 Författare Gustav Ribom 910326-0593 Erik Aalto 861108-0212 Kontaktperson Johan Boye
Abstract Ordet fil har flera olika betydelser såsom ett verktyg, filmjölk, körfil osv. och tillhör därmed ordkategorin homonymer. Att klassificera dessas betydelser är ett intressant språkteknologiskt problem, för vilket vi prövat både nyckelordsmatchning och två olika maskininlärningsmetoder. I rapporten framgår hur vi gick tillväga för att genomföra vår undersökning. Resultaten från undersökningen pekar på att nyckelordsmatchning, givet en liten mängd data, är den bästa metoden. En trolig anledning till detta är att mängden data vi använde oss av var så pass liten, vilket ger metoderna som använder sig av maskininlärning ett sämre resultat. Innehåll Abstract... 2 Inledning... 3 Metod med motiveringar... 3 Resultat... 4 Slutsats och Diskussion... 5 Referenser... 7 Böcker... 7 Nätreferenser... 7 Bilagor... 8 Nyckelordsprogram... 8 J48-träd... 10 2
Inledning Homonymer är ord som har flera betydelser men samma stavning och uttal, som t.ex. ordet mask vilket kan vara både ett djur och en ansiktsförklädnad. Vi människor förstår nog oftast vilken innebörd en homonym har när det förkommer i en viss kontext. Men inom språkteknologi, t.ex. för programvara som översätter texter från ett språk till ett annat kan homonymer bli ett problem. Därför är undersökandet av olika metoders effektivitet för att hitta homonymers betydelse intressant. Vår frågeställning blev alltså att hitta den metod som ger bäst resultat vid klassificering av homonymer som förekommer i kortare kontexter. För att undersökningen skulle hålla sig inom tidsplanen avgränsade vi vår undersökning till en specifik homonym, ordet fil. Vi bestämde även att vi skulle pröva tre olika metoder. En metod med naiv ansats och två metoder som använder maskininlärning. Metod med motiveringar Vi började med att samla in data. Detta gjordes genom att i Språkbankens korpus 1 söka på ordet fil och ta fram totalt 95 meningar där detta ord förekom. Dessa meningar togs fram på måfå, dvs. detta skedde inte slumpmässigt. Det fanns alltså ingen representativitet av varje betydelse gentemot språkbankens korpus heller. Av dessa 95 meningar valde vi 65 som träningsdata och 30 som testdata. Vi valde medvetet att ha separata tränings- och testmängder för att inte överträna varken nyckelordsmatchningen eller någon av maskininlärningsmetoderna. Här avgränsade vi medvetet mängden data för vår jämförande undersökning för att inte behöva kompromissa med tiden för att analysera resultat. I den naiva ansatsen, vilken byggde på nyckelordsmatchning, valde vi manuellt ut ord ur de 65 meningarna som utgjorde träningsdata som vi tyckte kunde särskilja de olika betydelserna av fil i olika kategorier. 2 Valet av nyckelord var vad vi personligen tyckte verkade relevant. Därefter skrev vi ett enklare java-program 3 som utifrån de olika betydelserna av fil skapade en vektor. För testmeningarna utökade varje förekomst av ett nyckelord, i respektive kategori, meningens vektor med ett i den dimensionen. Ordet frukost var t.ex. en klassificerare för kategorin filmjölk och därmed hade ord såsom frukost, lyxfrukost, frukosthumör och lyxfrukosthumör vardera lagt på ett i dimensionen filmjölk. Varje klassificerande ord kunde med andra ord fungera i form av ordet själv, prefix, suffix och infix. Vi sökte alltså efter delsträngar. Den dimension en mening viktade mest mot fick vara den troligaste betydelsen. Skulle en mening vikta lika mycket mot två eller flera dimensioner klassificerades den som icke-klassificerbar. För att testa homonymers betydelse med hjälp av maskininlärning valde vi att använda oss av Weka som är ett öppet verktyg under GNU GPL med en uppsättning av olika maskininlärningsalgoritmer. 4 Att själva försöka göra ett maskininlärningsprogram hade, givet 1 http://spraakbanken.gu.se/korp/# 2 Se bilaga för kategoriseringen av nyckelord 3 Se bilaga för källkod 4 http://www.cs.waikato.ac.nz/~ml/weka/ 3
vår uppgift, varit orimligt mycket och redundant arbete då Weka redan är ett väl fungerande verktyg. Vi använde oss av maskininlärningsmetoden som kallas supervised machine learning dvs. övervakad maskininlärning. Vi tränade alltså programmet på den träningsmängd som vi manuellt skapat utifrån Språkbankens korpus. För var och en av de 65 träningsmeningarna taggades vilken kategori meningen tillhörde manuellt, och samma för testdata. I Weka klippte vi först in tränings- och testdata i en gemensam fil för att skapa en Bag of Words som gällde för både tränings- och testdata. Sedan lät vi Weka analysera träningsmeningarna efter vald algoritm, för att därefter testa på testmeningarna. Vi använde oss av två olika inlärningsalgoritmer: J48-träd, som är en metod som bygger beslutsträd, och Naïve Bayes vilket är en statistisk metod som bygger på betingade sannolikheter. Anledningen till att vi inte inkluderade oövervakad inlärning utöver de redan beskriva metoderna var att det skulle blivit väldigt komplicerat och vi kände redan till vilka kategorier vår homonym kan tillhöra. Resultat Vi gjorde totalt tre olika undersökningar, två av dessa var baserade på övervakad maskininlärning och en på nyckelordsmatchning. Varje resultat från respektive test vi utförde redovisas på bästa sätt i en så kallad Confusion matrix. Nedan finns matriserna från varje test utritade. I varje ruta syns hur många av ordets riktiga betydelse (rad) som klassificerats som en viss betydelse (kolumn). Detta betyder att de rätta klassificeringar programmet åstadkommit finns längs diagonalen, alltså positionerna (a,a), (b,b) osv. Nyckelordsmatchning Summan från diagonalen i nyckelordmatchningens matris är lika med 17. Detta betyder att programmet klassificerade 17 av 30 ord korrekt. Korrekthetsgrad: 56.7 % J48-träd Det bör noteras att denna algoritm betecknade i stort sett alla ord med betydelsen datafil. Summan av diagonalen är 9. Alltså klassificerades 9 av 30 ord korrekt. Korrekthetsgrad: 30.0 % 4
Naïve Bayes Även algoritmen Naïve Bayes betecknade större delen av ord som datafil, men den hade lite bättre spridning än j48-träden. 13 av 30 ord klassificerades korrekt. Korrekthetsgrad: 43.3 % I testerna vi utfört visade det sig att nyckelordsmatchningen klarade att placera flest ord i rätt kategori, och den bästa maskininlärningsmetoden var den som byggde på Naïve Bayes. Slutsats och Diskussion Resultaten vi fått pekar på att nyckelordsmatchning ger en högre korrekhet jämfört med maskininlärning, då testerna utförs med en liten tränings- och testmängd. Naïve Bayes som i detta fall var den bästa maskininlärningsalgoritmen hade en korrekthetsgrad på 43.3% att jämföra med 56.7% för nyckelordsmatchningen. Då ska man även ha i åtanke ordet te som skulle peka på kategorin filmjölk också kan fungera som infix. Exempelvis som en del av ordet material vilket förekom med större frekvens i meningar där fil tillhörde kategorin verktyg. När vi lade till ett mellanslag efter ordet, så att vi fick te istället, ökade korrekthetsgraden till 73.3%. Detta är en markant förbättring jämfört med det tidigare resultatet. En slutsats vi kan dra av detta är att vid nyckelordsmatchning där nyckelord tillåts vara delsträngar bör man akta sig för att använda korta och vanligt förekommande n-gram, såsom bigram och trigram. Det är möjligt att vi kunnat öka nyckelordsmatchningens korrekthetsgrad ännu mer med fler små och enkla modifikationer. En fortsättning, och mer avancerad version, av nyckelordsmatchningen hade varit att stemma eller lemmatisera orden i varje mening innan nyckelordsmatchningen görs. Detta för att slippa problem med delsträngar och kortare n- gram. Att genomföra detta hade dock varit utanför tidsramen för vår uppgift. En annan slutsats som vi kan dra från resultaten är att när man använder små mängder tränings- och testdata, vilket vi använt, ger det bättre resultat att hitta på egna nyckelord än att använda maskininlärning. Det tyder på att när man bara har tillgång små träningsmängder är det ingen vidare idé att använda maskininlärning. Vi vet däremot från t.ex. exemplet med Telias telefonsupport 5 att om man får möjlighet att träna ett bra program på en stor mängd data så kan maskininlärningen ge ett bättre resultat än vad ett program skrivet av experter inom området ger. Detta pekar på att ju mer data som finns tillgänglig att träna ett maskininlärningsprogram på desto bättre resultat blir det. Alltså hade våra resultat från maskininlärningstesterna sannolikt blivit bättre med en större mängd träningsdata. 5 Föreläsning 6, (12-11-01), Johan Boye 5
Vi såg också att metoden Naïve Bayes var noterbart mycket bättre än J48-träd på att klassificera ord. I vårt fall var anledningen till detta framförallt att trädet som skapades av algoritmen gav ordet sig, som fanns med i många av meningarna, en pekare mot betydelsen datafil. 6 På grund av detta blev i stort sett alla orden klassade som datafiler och resultatet blev inte bra. Vi valde att utelämna övriga metoder för maskininlärning då Naïve Bayes är bland de bästa metoderna för kategorisering. 7 Intressant är också vilka resultat vi erhållit om vi lagt in en stopplista för att ta bort vanligt förekommande ord, s.k. funktionsord, såsom är, var, i, på, och givet vår lilla mängd träningsdata. Med en större mängd träningsdata hade troligtvis stoppordlistan fått mindre betydelse då de olika stopporden bör förekomma med i stort sett samma frekvens för de olika kategorierna. Skulle stopporden inte förekomma med samma frekvens vore det ju bara bra eftersom det då skulle tyda på särdrag för en specifik kategori. Man kan också argumentera för att våra resultat från maskininlärningsmetoderna hade blivit bättre om vi med samma mängd träningsdata manuellt tagit bort ord som av maskininlärningsalgoritmerna klassats som signifikanta för en viss kategori. Men som vi människor lätt kan se inte är det. Vidare kan man argumentera för att vi med maskininlärning på en större träningsmängd skulle nå kategoriseringsvektorer som konvergerar mot de vektorer vi skulle få om man manuellt tog bort irrelevanta ord. Eller ifall de inte konvergerar mot just dessa skulle de ändå uppnå samma funktion. När en liten mängd testdata tillämpas kan ord bedömas vara relevanta av programmet trots att de inte är det, men dessa försvinner då mängden testdata ökar. Det beror på att de ord som inte är relevanta för homonymens innebörd statistiskt sett inte förekommer ofta tillsammans med homonymen. Alltså återigen, givet vår relativt lilla mängd träningsdata är det troligt att markanta resultatförbättringar uppnås med större mängd data att träna på. Sammanfattningsvis kan sägas att skulle vi stå inför ett nytt klassificeringsproblem av homonymer med endast en mindre mängd träningsdata tillgänglig skulle vi använda oss av nyckelordsmatchning. Men denna gång skulle vi stemma orden i meningarna och matcha mot ordens stammar istället för att söka efter delsträngar. För samma problem med en stor mängd träningsdata är sannolikt att Naïve Bayes skulle ge bäst resultat. 6 Se J48-träd i Bilagor 7 S.154 Tom.M.Mitchell (1997) 6
Referenser Johan Boye, Föreläsning i Språkteknologi (12-11-01) Maskininlärning i språkteknologiska applikationer. Böcker Tom.M.Mitchell (1997) Machine Learning McGraw-Hill, USA. Nätreferenser Språkbankens korpus, 12-12-03: http://spraakbanken.gu.se/korp/# Weka, 13-01-10: http://www.cs.waikato.ac.nz/~ml/weka/ 7
Bilagor Nyckelordsprogram import java.io.*; import java.util.arraylist; import java.util.hashset; import java.util.set; public class FilTest { public static void main(string[] args) throws IOException{ FileInputStream in = new FileInputStream(new File("input.txt")); BufferedReader r = new BufferedReader(new InputStreamReader(in)); ArrayList<Integer> samma = new ArrayList(); String[] filmjolk = {"äta", "smör", "grädde", "mjölk", "fet", "frukost", "ägg", "lite", "smoothie", "keso", "te ", "flingor", "müsli", "äggröra", "kaffe", "juice", "juicer", "yoghurt", "ost", "ostar", "käka", "frukost", "kvällsmat", "skål"; String[] verktyg = {"naglar", "nagel", "garage", "fingrar", "hand", "grov", "finare", "fin", "jämna", "blank", "yta", "händer", "hand", "fila", "fixa", "forma", "trimmade", "sax", "rosa", "tjej", "rakhyveln"; String[] korfalt = {"stänger", "kör", "trafik", "rondell", "taxi", "bil", "olycka", "byt", "buss", "hastighet", "påkörd", "tränga", "gata", "parker", "stanna", "hinder", "sakta", "ombyggnad"; String[] datafil = {"katalog","virus", "heter", "office", "crack", "ny", "skapa", "skriv", "text", "album", "innehåller", "representerar", "smart", "it", "tekniker", "överblick", "anti", "program", "reagerar", "ladda", "upp", "analyseras", "kryssa", "spara", "välj", "kör", "granska", "gps", "lägga", "exportera", "kalender", "höra", "namn", "rapport", "pdf", "mp3", "skicka", "minne", "krascha", "film", "märkt", "installera", "adobe", "flash", "windows", "klicka", "google", "gedit", "mapp", "skapa", "skydd", "internet", "skada", "dator", "klistra", "besök"; String[] titel = {"kand", "lic", "dr", "ledning", "forskare", "universitet", "skrivning", "psykologi", "social", "artikel", "docent", "läkare", "biokemi"; int typ[] = new int[5]; while (r.ready()){ //for(int j=0; j<2; j++){ for(int i=0; i<5; i++){ typ[i]=0; String s = r.readline(); for(string st : filmjolk){ if(s.contains(st)){ typ[0] += 1; for(string st : verktyg){ if(s.contains(st)){ typ[1] += 1; 8
for(string st : korfalt){ if(s.contains(st)){ typ[2] += 1; for(string st : datafil){ if(s.contains(st)){ typ[3] += 1; for(string st : titel){ if(s.contains(st)){ typ[4] += 1; /*for(int i=0; i<5; i++){ Set<Integer> unique = new HashSet<Integer>(); unique.add(typ[0]); unique.add(typ[1]); unique.add(typ[2]); unique.add(typ[3]); unique.add(typ[4]); if( unique.size()!= 5){ System.out.println("Kunde inte avgöra vilken betydelse ordet har"); break; if(typ[i] > typ[i+1]){ int temp = i; */ int temp=0; for(int i=0; i<5; i++){ if(typ[i]==temp){//är de två betydelserna lika sannolika föreslår vi båda samma.add(i); else if(typ[i]>temp){//är denna betydelse mer sannolik temp=typ[i]; samma.clear(); samma.add(i); for(int t: samma){ if(t==0){ System.out.print("filmjölk "); else if(t==1){ System.out.print("verktyg "); else if(t==2){ 9
System.out.print("körfält "); else if(t==3){ System.out.print("datafil "); else if(t==4){ System.out.print("titel "); System.out.print("har klassificerats för meningen: \" "+s); System.out.println("."); System.out.println("SLUT"); J48-träd 10