R-ohjelmointi.org

Tilastotieteellistä ohjelmointia R-kielellä

Lisätoiminnallisuuksia tekstinlouhintaan: entiteettien tunnistaminen ja ontologioiden käyttö

Olen useasti aiemminkin kirjoittanut suomenkielisen tekstin tekstinlouhinnasta R:ää käyttäen. Aiemmat funktioni on julkaistu GitHub-repositoryssä TextMining, mutta päätin muuttaa funktiot toimimaan merkkijonovektoreilla, ja uudet funktiot löytyvät repositorystä TextMining2. Mukana on suurin osa aiemman funktiokokoelman toiminnallisuuksista, mutta uusiakin on tullut mukaan. Nykyisillä funktioilla voi tehdä suomenkieliselle tekstille stemmauksen lisäksi myös lemmatisointia (preprocessText()-funktion argumentti lemmatization) ja tunnistaa lauseenjäseniä (funktio postag()). Uusimpia vielä kehityksen alla olevia toiminnallisuuksia on entiteettien tunnistaminen suomenkielisestä tekstistä ja ontologioiden käyttö tekstimateriaalien luokittelemiseen. Katsahdetaanpa seuraavassa molempiin toiminnallisuuksiin.

Ontologioiden käyttö

Ontologia on kuvaus jonkin aihealueen termeistä tai käsitteistä ja niiden välisistä suhteista. Ontologia muodostaa usein termeistä ja niiden suhteista suunnatun asyklisen graafin. Suomalainen sanasto- ja ontologiapalvelu Finto julkaisee sanastoja ja ontologioita. TextMining2-repositoryssä olevalla skriptillä parse_KOKO-ontology.R on parsittu KOKO-niminen ontologia, joka on kokoelma erilaisia suomalaisia ydinontologioita. Tätä parsittua ontologiaa voidaan käyttää tekstimateriaalien tyypittelemiseen. Parsinnassa on säilytetty ontologian hierarkkinen rakenne, muttei viitteitä muiden ontologioiden samankaltaisiin termeihin.

Tarvittavien funktioiden ja aineistojen lataaminen GitHubista onnistuu seuraavasti:

source("https://raw.githubusercontent.com/jtuimala/TextMining2/master/tm-functions_V3.R")
load(url("https://github.com/jtuimala/TextMining/raw/master/fintm-data.RData"))
load(url("https://github.com/jtuimala/TextMining2/raw/master/ontologiat/KOKO-ontologia.RData"))

Latauksen jälkeen R:n muistista pitäisi löytyä objektit stopwords ja KOKO sekä funktio assign2ontology(). Näitä tarvitaan seuraavissa vaiheissa.

Ladataan ensin esimerkiksi Yle Uutisten sivuilta artikkeli, joka käsittelee ICT:n ja perinteisen teknologian suhdetta nyky-yhteiskunnassa. Artikkelin hakeminen ruudunkaavinnalla onnistuu helposti vaikkapa rvest-pakettia käyttäen.

library(rvest)
yle <- read_html("https://yle.fi/uutiset/3-9702852")
leipäteksti <- yle %>%
  html_nodes(".yle__article__content") %>%
  html_text()

Tämän jälkeen R:n muistissa pitäisi olla objekti leipäteksti, joka sisältää artikkelin leipätekstin. Kun teksti on R:n muistissa, sen yhdistäminen ontologian mukaisiin luokkiin onnistuu vaikkapa seuraavasti: Ensin tekstille tehdään stemming (preprocessText), jolla poistetaan sanojen taivutuspäätteet, ja tämän jälkeen stemmattu teksti yhdistetään ontologian kanssa (assign2ontology). Tuloksena syntyy JSON-muotoinen taulukko, joka voidaan lopuksi muuttaa data frameksi (json2df).

leipäteksti2<-preprocessText(leipäteksti, stemming=T, lemmatization=F)
leipäteksti3<-assign2ontology(leipäteksti2, KOKO, onscreen=FALSE)
leipäteksti4<-json2df(leipäteksti3)

Objektin leipäteksti4 sisältö näyttää seuraavalta:

                                                Var1 Freq
1                                              oliot   40
2                                       ominaisuudet   14
3                             tapahtumat ja toiminta   14
4                                  fyysiset objektit   13
5                                       järjestelmät   10
6                                          prosessit   10
7                                    rooli (tehtävä)   10
8                                         tapahtumat   10
9                                           toiminta   10
10                         toimintaan liittyvä rooli    8
11                    yhteiskunnalliset järjestelmät    8
12                                              aine    7
13                                elottomat objektit    4
14                                            ilmiöt    4
15             muuttaminen (muutoksen aiheuttaminen)    4
16                             tieteet (erikoisalat)    4
17                      organisaatiot (järjestelmät)    3
18                           tekniikka (erikoisalat)    3
19                                           ammatit    2
20                              keskinäinen toiminta    2
21                             koulutusorganisaatiot    2
22                                       materiaalit    2
23                            omistuksen siirtäminen    2
24                               orgaaniset objektit    2
25                                            paikka    2
26                          yhteiskunnalliset ilmiöt    2
27                            ylläpitävä muuttaminen    2
28                               abstraktit objektit    1
29                                          aistimet    1
30                                      aitotumaiset    1
31                                       alihankinta    1
32        alueelliseen identiteettiin liittyvä rooli    1
33                                            alueet    1
34                                            apinat    1
35                                              arvo    1
36                                     asiantuntijat    1
37                                             eliöt    1
38                                           eläimet    1
39                                    energialähteet    1
40                          fossiiliset polttoaineet    1
41                                          fysiikka    1
42                             fyysiset ominaisuudet    1
43                                          hallinta    1
44                                              halu    1
45                                          hankinta    1
46                                       ihmisapinat    1
47                        ihmisen määrittämät alueet    1
48                        ihmisen määrittämät paikat    1
49                                           ihmiset    1
50                                           isojako    1
51  johtajat (ammatit, organisaatiot (järjestelmät))    1
52                            järjestävä muuttaminen    1
53                                         kalusteet    1
54                                            kauppa    1
55                                         kehitteet    1
56                              kemialliset reaktiot    1
57                             kemialliset yhdisteet    1
58                                        kemikaalit    1
59                                          kertojat    1
60                                       kone-elimet    1
61                                     konetekniikka    1
62                                      korkeakoulut    1
63                                        kädelliset    1
64                                         käsitteet    1
65                                       laitteistot    1
66                                    liikennealueet    1
67                                          lisäarvo    1
68                                    luonnontieteet    1
69                                            luonti    1
70                                           maailma    1
71                                         maallikot    1
72                                          maanjako    1
73                                        mekaniikka    1
74                              mentaalinen toiminta    1
75                          mentaaliset ominaisuudet    1
76                                     meritekniikka    1
77                                 muut järjestelmät    1
78                                            muutos    1
79                                    nautintoaineet    1
80                                         nisäkkäät    1
81                                     oppilaitokset    1
82                              orgaaniset yhdisteet    1
83                                           osaajat    1
84                                         osaaminen    1
85                                        oululaiset    1
86                           paikkaan liittyvä rooli    1
87                                          panostus    1
88                                            pelkat    1
89                                 perinteentaitajat    1
90                                             pitsi    1
91                                      polttoaineet    1
92                                       professorit    1
93                                             puute    1
94                                         päättäjät    1
95                                rakennustarvikkeet    1
96                                             raski    1
97                                          reaktiot    1
98                            ruoanvalmistusvälineet    1
99                                       ruumiinosat    1
100                                          satamat    1
101                                   selkäjänteiset    1
102                                   selkärankaiset    1
103                                           silmät    1
104                                          suureet    1
105                                          säästöt    1
106                          taloudelliset tuotokset    1
107                                          tarpeet    1
108                                       tarvikkeet    1
109                                             taso    1
110                                            tasot    1
111                                              tee    1
112                            tekniset järjestelmät    1
113            tekniset objektit (fyysiset objektit)    1
114                             tekstiilimateriaalit    1
115                                            terät    1
116                                      tiedekunnat    1
117                                            tieto    1
118                                       tiivisteet    1
119                                             tila    1
120                                            tilat    1
121                                 toimitusjohtajat    1
122                       toisenlaiseksi muuttaminen    1
123                                         torjunta    1
124                                       tukitoimet    1
125                                             tuli    1
126                                          tunteet    1
127                                tuotantotekniikka    1
128                                              työ    1
129                                         ulkomaat    1
130                             valokuvauskemikaalit    1
131                                         välineet    1
132                       yhteiskunnalliset objektit    1
133                                      yhteiskunta    1
134                                        yhteistyö    1
135                               yhteistyökumppanit    1
136                                       yliopistot    1
137                    ympäristö (muut järjestelmät)    1
138                                        yritykset    1
139                                             öljy    1
140                                            öljyt    1

Ontologia on vielä muodoltaan sellainen, että tavallisestakin tekstistä syntyy monia luokkia, joista osa on melko hyödyttömiä. Esimerkiksi tästä tekstistä löytyvä yleisin ontologialuokka on ”oliot”, johon kuuluu suuri määrä erillisiä, muita termejä.

Entiteettien tunnistaminen

Entiteettien tunnistamisella pyritään päättelemään tekstistä, mitkä siinä esiintyvät sanat ovat esimerkiksi ihmisten nimiä, sähköpostiosoitteita tai vaikkapa valtioiden nimiä. Laatimani funktiot osaavat tunnistaa suomenkielisestä tekstistä esimerkiksi suomalaisten nimiä, mutta toiminta ei ole vielä kovin vahvalla pohjalla ja huteja saattaa tulla paljon.

Esimerkiksi edellä olevalle tekstille voidaan ensin tehdä lauseenjäsenten etsintä ja stemmaus:

tmp2<-postag(gsub("\\.", ". ", leipäteksti))
tmp2$stemmed<-stemDocument(removePunctuation(as.character(tmp2$word)), language="finnish")

minkä jälkeen parsitusta tekstistä pyritään löytämään vaikkapa suomenkielisiä nimiä:

load(url("https://github.com/jtuimala/TextMining2/raw/master/sanastot/nimet.RData"))
tmp2$miehet<-findNames(tmp2$word, etunimet_miehet)
tmp2$miehet2<-findNames(tmp2$stemmed, etunimet_miehet)
tmp2$naiset<-findNames(tmp2$word, etunimet_naiset)
tmp2$naiset2<-findNames(tmp2$stemmed, etunimet_naiset)
tmp2$sukunimi<-findNames(tmp2$word, sukunimet)
tmp2$sukunimi2<-findNames(tmp2$stemmed, sukunimet)

Pieni pätkä tuloksen keskivaiheilta poimittuna näyttää seuraavalta:

    sentence.id word.id                    word word.type               stemmed miehet miehet2 naiset naiset2 sukunimi sukunimi2
82            1      82              Professori      NOUN             Professor      0       0      0       0        0         0
83            1      83                   Jukka     PROPN                   Juk      1       0      0       0        1         0
84            1      84                    Kömi      NOUN                  Kömi      0       0      0       0        1         1
85            1      85                    tuli      VERB                  tuli      1       1      1       1        1         1
86            1      86                   Oulun     PROPN                  Oulu      0       0      0       0        0         0
87            1      87              yliopiston      NOUN             yliopisto      0       0      0       0        0         0
88            1      88             materiaali-      NOUN             materiaal      0       0      0       0        0         0
89            1      89                      ja      CONJ                    ja      0       0      0       0        0         0
90            1      90       tuotantotekniikan      NOUN       tuotantotekniik      0       0      0       0        0         0
91            1      91           professoriksi      NOUN             professor      0       0      0       0        0         0
92            1      92               SSAB:sta.     PROPN               SSABsta      0       0      0       0        0         0

Funktiot tunnistavat esimerkiksi artikkelista löytyvät Jukan ja Markon etunimiksi, mutta hutejakin on. Esimerkiksi verbi ole tunnistuu tässä etunimeksi, koska se on myös etunimi muodossa ”Ole”. Vääristä osumista voidaan tiettyyn rajaan saakka päästä eroon suodattamalla tulos lauseenjäsenen tyypin perusteella:

tmp2[tmp2$word.type=="PROPN" & rowSums(tmp2[,6:11])>0,]
    sentence.id word.id    word word.type stemmed miehet miehet2 naiset naiset2 sukunimi sukunimi2
35            1      35   Suomi     PROPN   Suomi      0       0      0       0        1         1
44            1      44   Marko     PROPN   Marko      1       1      0       0        0         0
45            1      45 Jokinen     PROPN   Jokin      0       0      0       0        1         0
83            1      83   Jukka     PROPN     Juk      1       0      0       0        1         0
193           1     193 Jokinen     PROPN   Jokin      0       0      0       0        1         0
206           1     206  Riitta     PROPN    Riit      0       0      1       0        0         0
275           1     275   Teräs     PROPN   Teräs      0       0      0       0        1         1
317           1     317  Riitta     PROPN    Riit      0       0      1       0        0         0
321           1     321  Sipilä     PROPN   Sipil      0       0      0       0        1         0
330           1     330   Marko     PROPN   Marko      1       1      0       0        0         0
416           1     416  Sipilä     PROPN   Sipil      0       0      0       0        1         0
472           1     472   Suomi     PROPN   Suomi      0       0      0       0        1         1

Tällöin tosin osa nimistä, etenkin sukunimistä, jää löytymättä. Kuten sanottu, funktioiden optimoinnissa on vielä hieman tekemistä.

Seuraava kuvitteellinen esimerkki käyttää suurinta osaa nyt saatavilla olevista entiteettien tunnistusfunktioista:

load(url("https://github.com/jtuimala/TextMining2/raw/master/sanastot/nimet.RData"))
load(url("https://github.com/jtuimala/TextMining2/raw/master/sanastot/kunnat.RData"))
load(url("https://github.com/jtuimala/TextMining2/raw/master/sanastot/valtiot.RData"))
load(url("https://github.com/jtuimala/TextMining2/raw/master/sanastot/osoitteet.RData"))
 
# Kuvitteellinen esimerkki
tmp<-"Matti Meikäläisen henkilötunnus on 311299-9872. Matin Y-tunnus on 1234567-8 ja ALV-tunnus vastaavasti FI12345678. 
      Sähköpostiosoite on matti.meikalainen@hotmail.com. Pankkitili on FI4250001510000023 ja luottokortti on 4716767024524648. 
      Puhelinnumero on 040-1234567.  Matin osoite on Hevonperseensuo 19, 20100 Turku, Suomi. 
      Matilla on auto, jonka rekisterinumero on ABC-123. Ajoneuvo on ajokiellossa Tieliikennelain 6 § 1 mom. nojalla.
      Matin veli Ville asuu osoitteessa Rantatie 1. Villen sisko on Maria."
dat<-data.frame(id=1, text=tmp)
tmp2<-postag(dat$text)
tmp2$stemmed<-stemDocument(removePunctuation(as.character(tmp2$word)), language="finnish")
 
tmp2$YTunnus<-findYTunnus(tmp2$word, count=T)
tmp2$Hetu<-findHetu(tmp2$word, count=T)
tmp2$ALVTunnus<-findALVTunnus(tmp2$word, count=T)
tmp2$PuhNro<-findPhoneNumbers(tmp2$word, count=T)
tmp2$URL<-findURL(tmp2$word, count=T)
tmp2$email<-findEMail(tmp2$word, count=T)
tmp2$pannkitili<-findBankAccount(tmp2$word, count=T)
tmp2$luottokortti<-findCreditCard(tmp2$word, count=T)
tmp2$postinumero<-findZIP(tmp2$word, count=T)
tmp2$rekisterinumero<-findPlateNumber(tmp2$word, count=T)
tmp2$kunta<-findMunicipalities(tmp2$stemmed, kunnat, locate=T)
tmp2$valtio<-findCountries(tmp2$stemmed, valtiot, locate=T)
tmp2$katu_paikka <- findAddress(tmp2$word, osoitteet)
tmp2$miehet<-findNames(tmp2$word, etunimet_miehet)
tmp2$miehet2<-findNames(tmp2$stemmed, etunimet_miehet)
tmp2$naiset<-findNames(tmp2$word, etunimet_naiset)
tmp2$naiset2<-findNames(tmp2$stemmed, etunimet_naiset)
tmp2$sukunimi<-findNames(tmp2$word, sukunimet)
tmp2$sukunimi2<-findNames(tmp2$stemmed, sukunimet)
 
print(head(tmp2))
  sentence.id word.id          word word.type       stemmed YTunnus Hetu ALVTunnus PuhNro URL email pannkitili
1           1       1         Matti     PROPN           Mat       0    0         0      0   0     0          0
2           1       2   Meikäläisen       ADJ     Meikäläis       0    0         0      0   0     0          0
3           1       3 henkilötunnus      NOUN henkilötunnus       0    0         0      0   0     0          0
4           1       4            on      VERB            on       0    0         0      0   0     0          0
5           1       5  311299-9872.       NUM    3112999872       0    1         0      1   0     0          0
6           1       6         Matin      NOUN           Mat       0    0         0      0   0     0          0
  luottokortti postinumero rekisterinumero kunta valtio katu_paikka miehet miehet2 naiset naiset2 sukunimi sukunimi2
1            0           0               0     0      0           0      1       0      0       0        0         0
2            0           0               0     0      0           0      0       0      0       0        0         0
3            0           0               0     0      0           0      0       0      0       0        0         0
4            0           0               0     0      0           0      0       0      0       0        0         0
5            0           1               0     0      0           0      0       0      0       0        0         0
6            0           0               0     0      0           0      1       0      0       0        0         0

Funktioiden taustalla olevat tiedot on koottu useista lähteistä, jotka on lueteltu tarkemmin repositorystä löytyvässä README-tiedostossa. Kiitos viranomaisten julkaiseman runsaan avoimen datan, funktiot ovat edes tällä mallilla muutamien päivien kehitystyön jälkeen.

Tarkoituksena on kehittää toiminnallisuuksia vielä eteenpäin. Nyt esitellyt toiminnallisuudet ovat syntyneet suhteellisen nopeasti eivätkä ole mitenkään optimaalisia, kuten tuloksista käy hyvin ilmi. Esimerkiksi entiteettien tunnistaminen perustuu nyt suoraan termien vertailuun, mutta esimerkiksi nimiä on mahdollista tunnistaa myös vaikkapa Hidden Markov Model-mallilla tai sopivalla painoarvomatriisilla tai näiden yhdistelmällä.

Tags: ,

2 Responses to “Lisätoiminnallisuuksia tekstinlouhintaan: entiteettien tunnistaminen ja ontologioiden käyttö”

  • Mirjamaria sanoo:

    GitHub linkit eivtä tunnu toimivan. Ovatko koodit vielä jossain saatavilla?

    • Jarno sanoo:

      Yhden sanalistan lisenssi on muuttunut, joten Github on sen vuoksi päivityksen alla. Lisäsin kuitenkin nyt koodit takaisin julkiseen repositoryyn, koska päivitys ei koske niitä.


Category