En stemmer för svenska ord Laborationsuppgift i Sprνakteknologi 2D1418, NADA, KTH av Johan Hanson (750921-0113) HT 2004
Syfte och krav Laborationsuppgift Uppgiften är att skriva en stemmer för svenska sprνaket som bör hantera substantiv och verb. Uppgiften tillät mig att själv välja verktyg och regler. Mina regler och erfarenheter ska redovisas. Jag tar mig friheten att översätta ordet stemmer till avstammare i Svenska, därför att en svensk översättningen saknas. Ordet avstamning pνaminner om ordet avstavning vilket är en liknande operation. Man kan se stemming som att man tar av stammen frνan ordet. Användningsomrνade Förutom som en ren laboration, sνa har jag som syfte att använda stemmern i ett dialogbaserat ordliste-program 1 som ska kunna hantera ett litet antal sprνak i nuläget och flera sprνak ska kunna läggas till. Ordstammarna som stemmern producerar ska användas som söknycklar. Varje sökning fνar ge mer än ett svar, men det bör helst inte ge nνagot svar som inte är relaterat till sökordets betydelse. Syftet medför ett krav pνa att stemmern ska skrivas pνa ett generellt sätt, där källkod för stemmern och sprνakspecifik kod är separata. Algoritmer Porters Algoritm Uppgiftsanvisningarna föreslνar Porters algoritm [Porter] där regler för suffixsubstitution tillämpas pνa mνalordet i ordning efter varandra. I vänsterledet stνar ett suffix och eventuellt ocksνa ett test som om det finns utförs pνa det motsvarande prefixet. Om vänsterledet matchar mνalordet sνa byts suffixet ut mot suffixet i högerledet (vilket för mνanga regler är en tom sträng). Högerledet kan ocksνaspecificera en enkel transformation pνa prefixet. En generell syntax och prefixtester visas i figur 2 resp 3. Suffixreglerna är grupperade i steg där högst en regel fνar matcha - den med längst matchande suffix - sedan gνar ordet vidare till nästa steg. Ett undantag är att ett steg kan ha ett städningssteg som tillämpas endast om en regel i det förstnämnda steget matchar. Porters algoritm utvecklades för amerikansk engelska. I [Fuller, Zobel] testades den mot ett par andra suffixsubstituerande algoritmer pνa en engelsk textmängd och visade sig dνa ha en god kombination av täckning och precision med en engelsk testmängd. Algoritmen har använts med gott resultat för liknande sprνak, men har ofta behövt modifieras. I [Kraaij, Pohlmann] beskrivs en Porter-stemmer för holländska där en ny prefix-transformation har behövt läggas in för att hantera substantiv som har dubbelvokal i singular och enkelvokal i plural (plus suffix). I grundutförandet sνa tar den inte hänsyn till att 1 Syftet med programmet är att hjälpa inlärning av sprνaken quenya och sindarin. Dessa sprνak skapades av J.R.R Tolkien för sin fantasi-värld i bl.a. böckerna om Sagan om ringen. Bνade quenya och sindarin skapades med verkliga sprνak som förebilder och har icketrivial morfologi och ickeregelbundna böjningsformer. En enklare form av quenya talas idag av ett hundratal svenska entuasiaster under levande rollspel. Programmet ska fungera som en tjänst i ett publikt chatrum pνa IRC. 2
prefix-test suffix! transform suffix Figur 1: Syntax för Porter-regler prefix-test ::= ( test-expr ) j ffl test-expr ::= test-expr j test-expr j test-expr & test-expr j!test-expr j (test-expr ) j condition condition ::= v j d j o j C j m operator integer transform ::= ( d ) j ffl Figur 2: Porters prefix-test syntax betydelse v prefixet innehνaller en vokal d prefixet slutar pνa en dubbelkonsonant C prefixet slutar pνa tecknet C o prefixet slutar pνa konsonant-vokal-konsonant &!(W j X j Y) m operator n m=measure, grovt räknat antal stavelser - 1, n heltal > 0 3
vissa engelska ord stavas olika i olika engelsktalande länder - t.ex. colouring och coloring fνar inte samma stam. Ordlistebaserad avstamning Ett alternativ till suffixsubstituering vore att använda en ordlista med en god representation av sprνaket och vilka suffix som fungerar till vilka ord. Sνadana alternativ ger större precision pνa bekostnad av täckning och snabbhet. Ordlistan riskerar ocksνa att bli rätt stor om den ska innehνalla suffix, men algoritmen behöver inte modifieras för olika sprνak. Det finns ocksνa varianter som t.ex. [Krovetz] där man använder suffixsubstituering som ett första steg innan en ordlista. 1 Programkod 1.1 Algoritmval Jag har valt att använda Porters algoritm tillsammans med en ordlista för undantag för avstamningsreglerna. Varje post i ordlistan bestνar av tvνa ord: ett undantagsord och en stam. Om mνalordet har matchat vänsterledet i en regel sνa testas ordet mot undantagsorden i ordlistan. Om ordet är ett undantagsord sνa svarar funktionen med ordlistepostens stam. Annars utförs regelns högerled. Om ett undantagsord inte matchar nνagon regel sνa behöver den inte läggas in i ordlistan, och det görs inte heller. Den första operation som sker med mνalordet är dock att versaler görs om till gemener och att accenter och andra diakretiska tecken tas bort (förutom för νa,ä och ö). 1.2 Programmeringsgränssnitt Användaren fνar skapa ett Stemmer-objekt som matas med regler och undantagsord innan det används. Ett mer elegant gränssnitt hade varit att lνata skapa strukturer av regler och undantagsord och sedan skapa ett objekt men jag tycker att det skulle ha blivit alltför omständigt. Avstammaren är skriven i C. Se appendix B. 1.3 Begränsningar och rum för framtida förbättringar Avstamningen saknar prefix-transformationer specifika för svenska ord. De inkluderar typen händer!hand där prefixet ändrar vokal. Regelparsern tillνater högst ett test pνa prefixet per regel. En riktig generell implementation av Porters algoritm ska kunna hantera booleska uttryck av flera test med infix notation. Testet o har ännu lämnats oimplementerad därför att det är specifikt för engelska. Den nuvarande implementationen sparar undantagsordlistan i en enda hashtabell. Ordlistan skulle kunna delas upp över reglerna sνa att varje regel fνar en separat ordlista där alla ord matchar regelns vänsterled. Jag förväntar mig att endast ett litet antal regler dνa skulle fνa nνagra undantagsord tilldelade sig. 4
Figur 3: Regelgrupper för svenska verb och substantiv Substantiv - kasus, Verb - diates Substantiv - numerus, bestämdhet Substantiv - avledningar av verb Verb - tempus/verbform Verb - övriga ändelser Substantiv - avledningar av substantiv och adjektiv Städning Pνa det sättet skulle avstammaren kunna fνa en mätbart högre precision utan att vara vara signifikant lνangsammare än en avstammare utan ordlista, men detta νaterstνar att visas. 1.4 Svenska 1.4.1 Regler Uppgiftsanvisningarna föreslνar att man begränsar sig till ett antal ordklasser som t.ex. substantiv och verb. Jag begränsade mig därför till de tvνa ordklasserna. Till min hjälp använde jag [Thorell]. Jag skrev 55 regler. 2 Ett grovt schema över reglerna visas i figur 3 och reglerna själva i Appendix A. Jag valde att avstamma ord sνa pass lνangt som det gνar. Helst skulle jag vilja ha skrivit reglerna sνa att de producerat grundformer, men det var enklare att producera stammar. Jag valde dock att avstamming av avledningar skulle producera riktiga svenska ord som skulle kunna avstammas av regler i senare steg i fall att det är möjligt. En svνarighet var att ordna och anpassa reglerna sνa att de inte avstammer alltför mycket fel. Ett av problemen var att ord i flera ordklasser slutar pνa 'a'. Jag tror att reglerna kan förbättras ytterligare. 1.4.2 Ordlista Jag har inte populerat ordlistan med nνagra undantag, eftersom tid och tillgνang till en svensk ordlista har varit begränsad. 1.4.3 Test Jag har testat avstammaren med ett litet antal texter frνan KTH och Project Runeberg. Avstammaren har stammat av substantiv och verb fel endast i ett fνatal fall som skulle kunna ha hanterats av undantagsordlistan, om den hade varit populerad. 2 Porters skrev bara 60 regler... men det är engelska det 5
2 Diskussion och slutsats Jag har skrivit en aggressiv avstammare för svenska substantiv och verb som är snabb och som borde vara tillräcklig för min applikation när ovan nämnda förbättringar har införts. Jag tyckte det var knepigare att skriva avstamningsregler än det var att skriva programkoden. Jag tror att en graf-baserad stemmer (gärna med backtracking) skulle göra det lättare att skriva regler och ge bättre precision eftersom regler som matchar olika ordklasser dνa inte behöver skrivas för att ta hänsyn till varandra i lika hög grad. Jag tror att givet en ordinär ordlista och en uppsättning regler sνa skulle det vara möjligt att skapa en undantagsordlista pνa ett (semi-)automatiskt sätt. Jag tror att användning av undantagsordlista vore en bättre lösning än att inkorporera undantag i regelmängden. Referenser [Porter] M.F.Porter: An algorithm for suffix stripping, 1980. Frνan http: //www.tartarus.org/~martin/porterstemmer/. Först publicerad i Program, 14(3) sidor 130-137. [Thorell] Olof Thorell: Svensk ordbildningslära, 1981. ISBN 91-24-30652-5 [Fuller, Zobel] Michael Fuller, Justin Zobel: Conflation-based Comparison of Stemming Algorithms, 1998. [Kraaij, Pohlmann] Wessel Kraaij, Renee Pohlmann: Porter's stemming algorithm for Dutch [Krovetz] What is Krovetz Stemming: http://www.comp.lancs.ac.uk/ computing/research/stemming/general/krovetz.htm (Krovetz rapport Viewing morphology as an inference process kunde inte och behövde inte heller införskaffas). 6
A Suffixregler Steg 1: Substantiv - kasus, Verb - diates (m > 1) as! a (m > 1) s! ffl Steg 2: Substantiv - numerus, bestämdhet, (m > 1) orna! ffl (m > 1) an! ffl (m > 0) er! ffl (m > 1) or! ffl (m > 1) erna! ffl (m > 1) et! (d) ffl (m > 1) en! (d) ffl (L) n! ffl (m > 1) arna! ffl (m > 1) ar! ffl Steg 3: Substantiv - avledningar av verb (m > 0) ande! a (L) ing! a (R) ing! a (m > 0) ning! a (m > 0) eri! a (m > 0) an! a (m > 0) else! a (m > 0) sel! as (m > 0) ad! era (m > 0) age! era (m > 0) ans! era (m > 0) ens! era (m > 0) are! a (m > 0) ant! era (m > 0) ator! era (m > 0) arinna! ffl (m > 0) inna! ffl Steg 4: Verbform (m > 0) de! ffl (K) t! ffl (G) d! ffl (m > 0) ad! a (m > 0) at! a (m > 0) ar! a 7
Steg 5: Verb (m > 0) isera! ffl (m > 0) ificera! ffl (m > 0) iga! ffl (m > 0) ga! ffl (m > 0) era! ffl (m > 0) ra! ffl (m > 0) ja! ffl (m > 0) ka! ffl (m > 0) na! ffl (m > 0) a! ffl Steg 6: Substantiv avledda av substantiv och adjektiv (m > 0) ist! ffl (m > 0) ism! ffl (m > 0) het! ffl (m > 0) itet! ffl (m > 0) dom! ffl (m > 0) skap! ffl (m > 0) lek! ffl (m > 0) ur! ffl (m > 0) yr! ffl Steg 7: Övrigt (m > 0) mm! m (m > 0) el! l 8
B Programmeringsgränssnittet i stemmer.h / A word stemmer using a modified version of Porter's algorithm. Copyright (C) 2004 Johan Hanson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. / ifndef STEMMER_H define STEMMER_H ifdef cplusplus extern "C" endif / cplusplus / include <sys/types.h> / The type Stemmer Users of this type should be acquainted with Porter's algorithm and able to feed the stemmer proper rules for the target language. See the documentation for additional rules and limitations. It allows a dictionary with words that are exceptions to the rules. You can also make the stemmer produce words that are only in the dictionary, if you assign each dictionary word a non-null user_data and test it on return from stemmer_stem(). / typedef struct _Stemmer Stemmer; Stemmer stemmer_new (); void stemmer_destroy (Stemmer stemmer); 9
/ Stem "word" and put into "stem_buffer". Will return user data if it matches a dictionary word. / void stemmer_stem (Stemmer stemmer, const char word, char stem_buffer, size_t stem_buffer_size); / Populating the stemmer with rules. Returns a non-zero value if success. / int stemmer_add_rule (Stemmer stemmer, int step,/ starting at 0 / const char condition,/ can be null / const char transform,/ can be null / const char old_suffix,/ not null, will be copied / const char new_suffix); / not null, will be copied / / Specify that the step is a cleanup step to the previous / int stemmer_set_cleanup (Stemmer stemmer, int step); / Populating the stemmer dictionary. The dictionary is used for catching words that are exceptions to the rules. A word that passes through the stemmer will not actually be stored in it unless it has a user_data that is not null. Do not add the same word twice. Returns a non-zero value if success. There is no callback mechanism for recovering user data when the stemmer is destro / int stemmer_add_exception (Stemmer stemmer, const char word,/ not null, copied / const char stem,/ not null, copied / void user_data); / if not null, will always be remembered / ifdef cplusplus } endif / cplusplus / endif / STEMMER_H / 10