R-ohjelmointi.org

Tilastotieteellistä ohjelmointia R-kielellä

Datan esikäsittelyvaiheet ja siihen tarkoitetut R-paketit

Datan muokkaus vie aikaa

Suuri osa data-analyysin vaatimasta ajasta kuluu tyypillisesti aineiston käsittelyyn analysoitavaan muotoon. Usein kuulee sanottavan, että aineiston muokkaaminen vie koko analyysiin tarvittavasti ajasta suurimman osan, keskimäärin jopa 80% ajasta. Käytännössä siis analyysin vaatimista vaiheista hitain on juuri aineiston käsittely. Tähän vaiheeseen voi mennä vieläkin pidemmän aikaa, jos samalla joutuu tutustumaan aineiston muodostaneisiin prosesseihin. Jollei aineisto ole varsin siistiä, on siis varsin epärealistista odottaa, että analyysin tekeminen olisi tuntien työ. Välillä yksinkertainenkin analyysi voi viedä päiviä, jos aineisto on hankalasti käsiteltävissä.

Oman kokemukseni mukaan aineiston käsittelyä opetetaan yllättävän vähän, vaikka siihen liittyviä komponentteja onkin esimerkiksi tilastotieteen koulutusohjelmissa useampienkin kurssien osana. Silti suuri osa käytännön työssä tarvittavista tekniikoista on opeteltava tai opeteltavissa vain käytännössä. Koska näiden tekniikoiden osaaminen liittyy likeisesti myös monissa analyytikon työtehtävissä menestymiseen, kokoan seuraavassa yhteenvedon data-analyysin vaiheista, ja keskityn erityisesti aineiston käsittelyyn liittyvien seikkojen käsittelyyn

Analyysin vaiheet

Data-analyysin tekemiseen on olemassa joitakin standardimenettelyitä, joista Cross-industry Standard Process for Data Analysis (CRISP-DM) lienee nykyisin eräs tunnetuimmista. CRISP-DM -prosessi koostuu seuraavista vaiheista:

1. Liiketoiminnan tarpeiden ymmärtäminen
2. Datan ymmärtäminen ja keruu
3. Datan esikäsittely
4. Analysointi ja mallinnus
5. Mallien ja tulosten arviointi
6. Tulosten käyttöönotto

Alla oleva Wikipedian kuva (Kenneth Jensen, lisenssi: CC BY-SA 3.0) havainnollistaa prosessin iteratiivista ja syklistä rakennetta. Analyysiprojekti kun harvoin on täysin suoraviivainen tai lineaarisesti kohti maalia etenevä projekti.

Koko malli perustuu ajatukselle, että dataa jalostetaan informaatioksi ja mahdollisesti edelleen tietämykseksi, jota voidaan sitten liiketoiminnassa soveltaa sopivalla tavalla. Tätä kutsutaan myös DIKW -pyramidiksi, joka on enemmän filosofinen rakennelma, kun taas CRISP-DM pyrkii kuvaamaan saman prosessin teknisemmin tai enemmän käytännön tasolla.

Haluan korostaa tässä erityisesti DIKW-pyramidin ylempien tasojen (tietämys ja viisaus) merkitystä, sillä kokemukseni mukaan ne ovat miltei elimellisesti mukana esimerkiksi yliopistojen perustutkimuksessa, koska yliopistojen yhdeksi tuotteeksi voisi ajatella tutkimuksessa syntyvän uuden tiedon ja ymmärryksen. Oman tutkimuksen nivominen yhteen muiden tutkijoiden tuotosten ja sen hetkisen tietämyksen kanssa on mukana joka ikisessä julkaistussa artikkelissa. Näin ei välttämättä tapahdu esimerkiksi yrityksen toiminnassa.

Jos data-analyyseillä hankittua tietoa liiketoiminnasta ei missään vaiheessa nivota yhteen yhteiseksi tietämykseksi, jäävät analyysit yllättävän helposti yksittäisiksi teknisiksi suorituksiksi. Vaikka tämän artikkelin ydin onkin aineiston muokkaamiseen liittyvissä seikoissa, kannatan vahvasti ajatusta siitä, että analyytikko mitä tahansa analyysiä tehdessään pitää mielessään edes jollakin tasolla tuon tietämyksen lisäämisen tavoitteen. Suuren organisaation tasolla sen hankkimiseen, jakamiseen ja ylläpitämiseen täytyy tietysti olla erillinen prosessi, joka vaatii tulosten reflektointia, niiden merkityksen pohtimista yhdessä ja tiedon jakamista yleiseen käyttöön.

Aineiston esikäsittely

Aineiston esikäsittelyn (CRISP-DM:n vaihe 3) tarkoituksena on saada aineisto luettua analyysiohjelmistoon, muokattua se sisällöllisesti johdonmukaiseen muotoon ja lisäksi saada aineisto saatettua teknisesti analysoitavissa olevaan muotoon. Kunkin vaiheen alla on erilaisia alivaiheita, jotka on tarpeen huomioida sen mukaan, millaista aineisto on. On huomattava, että esikäsittelyn varassa lepäävät kaikki sitä seuraavat prosessin vaiheet, joten esikäsittely kannattaa yleensä tehdä mahdollisimman huolellisesti.

Seuraavassa oletetaan, että aineiston on taulukkomuodossa eli muuttujat ovat sarakkeilla ja erilliset havainnot riveillä. Esikäsittelyn päävaiheet muutamin usein hankaluuksia aiheuttavin esimerkinomaisin alakohdin höystettynä ovat siis seuraavat:

1. Aineiston lukeminen
1.1. Tiedoston tyypin huomioiminen (teksti: CSV / TSV, Excel, XML, HTML, SPSS, SAS, jne.)
1.2. Tiedoston sarake-erottiminen huomioiminen (tekstitiedostot; esim. sarkain, välilyönti, pystypalkki, jne.)
1.3. Lukujen desimaalierottimen huomioiminen (,/.)
1.4. Lukujen tuhaterottimen huomioiminen (,)
1.5. Tiedoston sarakeotsikoiden huomioiminen (on/ei)
1.6. Tiedoston merkistökoodauksen huomioiminen (esim. latin1, UTF-8, UTF-16LE, ISO-8859-1)
1.8. Erikoistilanteet, kuten ”solujen” sisäisten rivinvaihtojen huomioiminen TSV (tab-separated file) -tiedostossa

2. Aineiston teknisen johdonmukaisuuden varmistaminen
2.1. Aineiston sisältämien muuttujien pilkkominen sarakkeiksi menee oikein
2.1.1. Kullakin rivillä on yhtä monta havaintoa
2.1.2. Rivien havainnot sijoittuvat oikeisiin muuttujiin
2.2. Sarakkeiden sisältämien muuttujien tyypit ovat johdonmukaisia
2.2.1. Muuttujat ovat oletettu tyyppiä, esimerkiksi R:ssä luvut ovat numeroita, teksti faktoreita tai merkkijonoja ja päivämäärät päivämääriä

3. Aineiston sisällöllisen johdonmukaisuuden varmistaminen
3.1. Puuttuvien arvojen (NULL / NA) käsittely
3.1.1. Puuttuvia arvoja sisältävien havaintojen poistaminen
3.1.2. Puuttuvien arvojen korvaaminen (imputointi)
3.2. Loogisten muuttujien (TRUE / FALSE), äärettömien arvojen (-Inf / Inf) ja ei-lukujen (NaN) huomioiminen käsittelyssä
3.3. Poikkeavien havaintojen käsittely (oikeita havaintoja / virheitä?)
3.4. Varmasti väärien havaintojen käsittely (esim. negatiivinen ikä, synnytystapahtuma miehellä, jne.)
3.5. Tyypillisimpien numeeristen muuttujien virheiden korjaaminen (esim. pyöristysvirheet, lukujen vaihtuminen, jne.)
3.6. Havaintojen mahdollisten kopioiden poistaminen
3.7. Muuttujien muunnokset
3.7.1. Kaikki muuttujan mittaustulokset ovat samalla skaalalla (esim. ei sekaisin senttejä ja tuumia)
3.7.2. Muut halutut / tarvittavat muunnokset (esim. muuttujien normalisointi, logaritmointi, ym.)
3.7.3. Uusien muuttujien muodostaminen (esim. muunnos luokitteluasteikolle, summamuuttujien laskeminen, ym.)
3.7.4. Tekstin pilkkominen useiksi muuttujiksi (esim. henkilötunnuksen jakaminen)

4. Aineiston esitysmuodon tekninen muuntaminen analyysiin soveltuvaksi
4.1. Aineiston suodattaminen (filtteröinti)
4.2. Aineiston aggregointi (ryhmätason tulosten laskeminen)
4.3. Aineiston muuntaminen pitkän (long) ja leveän (wide) muodon välillä (melt / cast / reshape)
4.4. Ajallisen ja/tai paikkaan sidottujen analyysien erityisvaatimukset (esim. paneelidata, kasvukäyrät, ym.)
4.5. Sekamallien ja verkostomallien erityisvaatimukset
4.6. Aineiston kuvantamisen ja visualisoinnin asettamat erityisvaatimukset (voivat erota analyysin vaatimuksista)

Analyysin tarvitsema aineisto voi koostua useista erillisistä tiedostoista, joille kaikille pitää tehdä edellä mainittuja esikäsittelyjä, ja lisäksi tiedostot pitää sopivalla tavalla yhdistää toisiinsa. Aina eri tiedostojen yhdistelykään ei ole helppoa, sillä tiedostojen välillä ei välttämättä ole mitään tunnistetta, jolla kukin havainto linkittyy yksiselitteisesti.

R:n tarjoamat mahdollisuudet

Seuraavassa on lueteltu paketteja ja funktioita, joilla yllä mainittuja esikäsittelyvaiheita voidaan R:ssä suorittaa.

1. Aineiston lukeminen

– tekstitiedostot: read.table() {utils}, fread() {data.table}, readLines() {base}, readChar() {base}
– Excel: XLConnect, xlsx, gdata, openxlsx, readxl
– HTML/XML: XML
– SPSS: foreign, haven
– SAS: foreign, Hmisc, sas7bdat, haven
– Stata: foreign, haven, readstata13
– JSON: rjson, jsonlite
– Edellisten tiedostomuotojen lukeminen samalla paketilla: rio
– merkistökoodaus: iconv() {base}, iconvlist() {base}, Sys.getlocale() {base}, Sys.setlocale {base}, Encoding() {base}

2. Aineiston teknisen johdonmukaisuuden varmistaminen

– merkkijonojen manipulointi: stringr, stringi
– päivämäärien kanssa työskentely: lubridate

3. Aineiston sisällöllisen johdonmukaisuuden varmistaminen

– puuttuvien arvojen tutkiminen: VIM, vtreat
– tyypillisten virheiden poistaminen: editrules, deducorrect, SeleMix, vtreat
– imputointi: mice, Amelia, mi, impute, imputation
– havaintojen kopioiden käsittely: RecordLinkage
– merkkijonojen manipulointi: stringr, stringdist, stringi
– äärevien arvojen käsittely: outliers, extremevalues, HighDimOut, mvoutlier

4. Aineiston esitysmuodon tekninen muuntaminen analyysiin soveltuvaksi

– aineiston esitystavan muuntaminen: reshape, reshape2, data.table, sqldf
– split-apply-combine (mm. muuttujien muunnokset, aggregointi): plyr, dplyr, psych, data.table, sqldf
– aineiston siivoaminen: tidyr
– suodatus: subset() {base}, sqldf, data.table, dplyr

Muut potentiaalisesti hyödylliset paketit, mm.:

– eri aineistojen yhdistäminen ilman yksiselitteistä tunnistetta: RecordLinkage
– aineiston anonymisointi: sdcMicro, sdcTable
– ruudun kaavinta: XML, RCurl, rvest
– tekstidatan käsittely: tm, qdap

Esimerkki hankalasta aineistosta

Toisinaan helppokin homma osoittautuu vaikeaksi. Kaisen Fung kertoo kahdessa blogi-artikkelissaan (1, 2), kuinka yrityksen asiakasrekisterin luominen Facebook-ryhmään kuuluvien ja uutiskirjeen tilaajien tietojen pohjalta osoittautui oletettua haastavammaksi.

Fungin alkuperäisenä ajatuksena oli yhdistää uutiskirjeen tilaajien tiedot ja Facebook-ryhmään kuuluvien tiedot heidän sähköpostiosoitteidensa perusteella. Tavoitteena kun oli laskea vain yhteen kertaan henkilöt, jotka olivat molemmilla listoilla. Facebook-ryhmän tiedoissa vain ei ollut sähköpostiosoitetta! Niinpä listat piti yhdistää käyttäjätunnusten (ja siis periaatteessa nimien) perusteella. Jokainen käyttäjätunnusten ja nimien perusteella yhdistelyä tehnyt tietää, ettei se ole helppoa. Nimissä on esimerkiksi usein kirjoitusvirheitä (esim. Jarno, Jarbo, Jano, JArno, JArmo). Toisilla on kaksiosainen sukunimi: Ville von Virtanen. Joissakin kulttuureissa on tavanomaista kirjoittaa aina sukunimi ennen etunimeä. Lisäksi Facebookin käyttäjätunnus on aina yksiselitteinen, mutta nimi ilman sähköpostiosoitteen domeenia ei ole.

Vastaavankaltaisia ongelmia riitti ratkottavaksi paljon muitakin. Niinpä Fungin alkuperäinen projektille antama aika-arvio, joka oli kaksi tuntia, ylittyi rutkasti, ja homma oli valmis vasta n. 12 tunnin työn jälkeen. Sekin kuulostaa minusta erinomaiselta suoritukselta! Tarinan opetus lienee, että vaikka olisi kuinka kokenut analyytikko, on ainakin toisinaan mahdotonta antaa tarkkaa arviota edes aineiston esikäsittelyn vaatimasta ajasta.

Yhteenveto

Aineiston esikäsittely on vain yksi koko data-analyysin vaatimista työvaiheista. Koska myöhemmät työvaiheet riippuvat hyvin tehdystä esikäsittelystä, siihen käytetty aika on usein hyvin perusteltavissa. Esikäsittelyyn tarkoitettuja R-paketteja on olemassa jo varsin laaja valikoima. Esikäsittelyn voi joiltakin osin hoitaa ilman pakettejakin, ja etenkin suurten aineiston kanssa se saattaakin olla laskennallisesti tehokkain keino. Pienempien aineistojen ollessa kyseessä pakettien käytön hallitseminen voi olla paikallaan, ja saattaa nopeuttaa esikäsittelyvaiheita. Esikäsittelyyn kuluu tyypillisesti suurin osa analyysin vaatimasta ajasta. Aina esikäsittelyn vaatiman ajan arviointi ei onnistu kovin tarkasti edes hyvin kokeneelta analyytikolta, ja sen kanssa on opittava elämään.

EDIT 2016-01-03: Lisätty linkki Wikipedian CRISP-DM -prosessia havainnollistavaan kuvaan.
EDIT 2016-07-19: Lisätty maininta paketeista rio ja vtreat

2 Responses to “Datan esikäsittelyvaiheet ja siihen tarkoitetut R-paketit”

  • Lauri Nikkinen kirjoitti:

    Itse olen siirtynyt käyttämään datan pyörittelyssä dplyr-pakettia lähes kokonaan. Se on tuonut lisää suorituskykyä ja parantanut koodin luettavuutta.

  • HK kirjoitti:

    Hyvä ruohonjuuritason yhteenveto analyysiprosessista ja aineiston
    esikäsittelyyn sisältyvistä vaiheista. Oman haasteensa analyysin vaatiman
    työ- ja aikamäärän arvioimiseen tuo myös se seikka, ettei varsinainen
    analysointiprosessi monestikaan taivu CRISP-DM:n mukaisiin selkeisiin
    työvaiheisiin, vaan eri vaiheiden välillä voi joutua risteilemään edes
    takaisin (kuten linkatun Wikipedia-artikkelin kuvasta eksplisiittisesti
    käykin ilmi). Tällaisten iteraatioiden määrää ei useinkaan pysty näkemään
    ennalta.

    Itse olen huomannut, että analyysiprosessin ajatteleminen turhan tiukasti
    CRISP-DM:n mukaisissa erillisissä vaiheissa saattaa jopa johtaa harhaan.
    Ongelma korostuu etenkin liiketoimintaympäristössä, jossa joutuu usein
    käsittelemään ihan muuhun tarkoitukseen kuin varsinaiseen
    analyysitarpeeseen kerättyä dataa ja muodostamaan samalla ymmärrystä datan
    sisällöstä ja riippuvuussuhteista analyysin jatkovaiheita varten. Tällöin
    on helppo jumittua suhteettoman pitkäksi aikaa esikäsittelyvaiheeseen, kun
    haluaa viimeisen päälle varmistua siitä, että kaikki aineistossa
    piileskelevät tekniset ja sisällölliset sudenkuopat on huomioitu ja
    asianmukaisesti täytetty.

    Monesti voisi kuitenkin olla hyödyllisempää siirtyä jo melko varhaisessa
    vaiheessa testailemaan datan analysointi- ja mallinnusvaihetta hieman
    kevyemmin esikäsitellyllä (mutta toki teknisesti soveltuvaan muotoon
    muokatulla) aineistolla. Tällöin aineistosta saattaa myös paljastua
    sellaisia ongelmakohtia, jotka jäisivät muutoin esikäsittelyvaiheessa
    huomaamatta ja aiheuttaisivat paljon harmaita hiuksia myöhemmin, kun datan
    pitäisi olla jo teknisesti reilassa. Ongelman paljastuessa voidaan palata
    takaisin esikäsittelyvaiheeseen, ja kun se on korjattu, voidaan siirtyä
    taas testailemaan seuraavaa vaihetta.

    Summa summarum: CRISP-DM on hyvä yleistason malli ja lähtökohta
    analysointiprosessille, mutta etenkin käytännön työssä on syytä pitää
    mielessä, että malli on (melkein) aina kaunisteltu kuva todellisuudesta.


Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *