R – Tidy Data

R Ei kommentteja

Tidy Data (suom. siisti, puhdas) on aineiston muoto, jonka tilastotieteilijä Hadley Wickham on tehnyt tunnetuksi. Tidy -muotoa kannattaa useimmiten pitää ensimmäisenä tavoitteena aineiston puhdistuksessa. Kun aineisto on siistissä muodossa, on sitä helpompi lukea, muokata sekä analysoida. Tidy Data pohjautuu kolmeen periaatteeseen:

  1. Jokainen muuttuja on omassa sarakkeessaan
  2. Jokainen havainto on omalla rivillään
  3. Jokainen arvo on omassa solussaan.

Kun näistä periaatteista noudattaa vähintään kahta, niin kolmannen tulisi toteutua itsestään. Näiden perusperiaatteiden lisäksi jokainen yksittäinen aineisto tulisi olla omassa taulukossaan.

Vaikka periaatteet kuulostavat itsestäänselvyyksiltä, niin reaalimaailman aineistot voivat useammallakin tavalla rikkoa näitä periaatteita. Yleisimmät virheet ovat:

  1. Sarakkeen nimet ovat havaintoja, eivätkä muuttujia
  2. Useampi muuttuja on samassa sarakkeessa
  3. Muuttujia on sekä riveillä että sarakkeissa
  4. Useampi eri aineisto on samassa taulukossa
  5. Yksi aineisto on useammassa eri taulukossa

Seuraavaksi käymme esimerkkejä sotkuisista aineistoista (untidy data) ja käymme läpi ratkaisuesimerkkejä tapauskohtaisesti.

Otetaan esimerkkiaineisto tilastokeskuksen vapaasti saatavilla olevista tilastoista. Aineistoksi valitaan keskiväkiluku, KOKO MAA, vuodet 2010-2019, miehet ja naiset, sekä ikäryhmät yhteensä. Tilastokeskuksen palvelusta saa kyllä muokattua aineiston puhtaaseen muotoon, mutta harjoitusteknisesti katsomme kuinka sama asia onnistuu R:llä.

Tallennetaan aineisto ja ladataan se R-ympäristöön tarkastelua varten. Huom, ensimmäinen rivi kannattaa jättää pois (skip=1) jotta miehet ja naiset saadaan sarakkeiden nimiksi:

Nyt aineisto on sopivan sotkuinen harjoittelua varten. Ensinnäkin aineistossa on paljon tyhjiä soluja (NA), sekä sarakkeiden nimet ovat muuttujia, eivätkä niiden nimiä (Miehet ja Naiset). Ensin aineisto pitää putsata niin, että tyhjät solut ja ylimääräiset tekstit poistetaan. Ensimmäinen sarake ei sisällä olennaista informaatiota, joten se voidaan poistaa edellisen artikkelin oppien mukaisesti funktiolla select(). Funktioon kirjoitetaan ensin miinus (-), koska valittu sarake tulee poistaa, ja koska kyseinen sarake on järjestykseltään ensimmänen, tulee select() funktioon ainoaksi argumentiksi -1 (poistetaan ensimmäinen sarake).

library(readxl)
library(tidyverse)

df <- read_excel("026_11s1_2019.xlsx", skip=1)

df %>% 
  select(-1)

# A tibble: 54 x 3
   ...2  Miehet        Naiset       
   <chr> <chr>         <chr>        
 1 NA    Yhteensä      Yhteensä     
 2 NA    Keskiväkiluku Keskiväkiluku
 3 2010  2631741.5     2731610      
 4 2011  2645475       2742796.5    
 5 2012  2659578       2754392.5    
 6 2013  2673493       2765479      
 7 2014  2686113.5     2775398      
 8 2015  2696676.5     2782854      
 9 2016  2706908.5     2788394      
10 2017  2715729       2792484.5    
# … with 44 more rows

Seuraavaksi riveiltä pitää suodattaa ne havainnot pois, joissa ei ole meille tarpeellista informaatiota. Kaksi ensimmäistä riviä, sekä viimeiset 42 riviä aineistossa on tyhjiä soluja (NA). NA-arvojen poistamiseen ja korvaamiseen on olemassa useita vaihtoehtoja esim. paketissa tidyr. Lunttilappu (Cheat sheet) paketin funktioihin, sekä muuta hyödyllistä tietoa paketista löytyy Tidyversen sivulta: https://tidyr.tidyverse.org.

Voimme suodattaa muuttujan …2 sisältämät NA-arvot funktiolla drop_na(), joka poistaa kaikki havainnot (rivit), jotka sisältävät NA-arvoja:

df %>% 
  select(-1) %>% 
  drop_na(...2)

# A tibble: 10 x 3
   ...2  Miehet    Naiset   
   <chr> <chr>     <chr>    
 1 2010  2631741.5 2731610  
 2 2011  2645475   2742796.5
 3 2012  2659578   2754392.5
 4 2013  2673493   2765479  
 5 2014  2686113.5 2775398  
 6 2015  2696676.5 2782854  
 7 2016  2706908.5 2788394  
 8 2017  2715729   2792484.5
 9 2018  2721210.5 2794314  
10 2019  2725776   2795829.5

Puuttuvat arvot voisi myös jossain tilanteessa korvata viereisten solujen arvoilla (fill()) tai itse valitsemilla arvoilla (replace_na()).

df %>% 
  select(-1) %>% 
  mutate(...2 = replace_na(...2, 99))

# A tibble: 54 x 3
   ...2  Miehet        Naiset       
   <chr> <chr>         <chr>        
 1 99    Yhteensä      Yhteensä     
 2 99    Keskiväkiluku Keskiväkiluku
 3 2010  2631741.5     2731610      
 4 2011  2645475       2742796.5    
 5 2012  2659578       2754392.5    
 6 2013  2673493       2765479      
 7 2014  2686113.5     2775398      
 8 2015  2696676.5     2782854      
 9 2016  2706908.5     2788394      
10 2017  2715729       2792484.5    
# … with 44 more rows

Tässä tilanteessa tavoitteena on NA-arvojen pois jättäminen, joten jatketaan aineistolla, josta ...2 sarakkeessa olleet NA-arvoja sisältävät rivit on poistettu. Nyt enää muuttujan ...2 nimi tulee muuttaa vastaamaan sarakkeen sisältöä (Vuosi). Lisäksi aineisto tallennetaan tässä vaiheessa nimellä df1 :

df1 <- df %>% 
  select(-1) %>% 
  drop_na(...2) %>% 
  rename(Vuosi=...2)

# A tibble: 10 x 3
   Vuosi Miehet    Naiset   
   <chr> <chr>     <chr>    
 1 2010  2631741.5 2731610  
 2 2011  2645475   2742796.5
 3 2012  2659578   2754392.5
 4 2013  2673493   2765479  
 5 2014  2686113.5 2775398  
 6 2015  2696676.5 2782854  
 7 2016  2706908.5 2788394  
 8 2017  2715729   2792484.5
 9 2018  2721210.5 2794314  
10 2019  2725776   2795829.5

Nyt aineisto ei enää sisällä tyhjiä soluja, mutta se on edelleen rakenteeltaan oppikirjaesimerkki virheistä 1 ja 3, sillä arvot Miehet ja Naiset ovat havaintoja (sukupuoli), joten ne tulisi olla omilla riveillään. Lisäksi jokainen muuttuja pitäisi olla omassa sarakkeessa (periaate 1), mutta keskiväkiluku on nyt jaettu kahteen sarakkeeseen (Miehet ja Naiset).

Aineiston kääntäminen (Pivoting)

Tämän vuoksi tutustumme yhteen tärkeimmistä tekniikoista aineiston rakenteen muuttamiseksi, eli sen kääntämiseen (pivoting).

Long vs Wide

Tätä varten on hyvä käsittää kaksi eri aineiston muotoa, joissa aineisto voi esiintyä: wide (leveä) ja long (pitkä). Wide tarkoittaa aineiston muotoa, jossa havaintoarvoja on esitetty sarakkeissa, jolloin sarakkeita on tarpeellista enemmän ja aineisto levenee. Esimerkkinä alla olevassa kuvassa vasemmalla Miehet ja Naiset ovat oikeasti havaintoarvoja, mutta ne ovat taulukossa sarakkeiden niminä). Long puolestaan tarkoittaa muotoa, jossa kaikki havaintoarvot on esitetty riveillä, jolloin rivejä on enemmän ja aineisto pitenee. Esimerkiksi alla olevassa kuvassa oikealla Miehet ja Naiset ovat omalla paikallaan muiden havaintoarvojen kanssa riveillä. Nyt aineistoon on nimetty (vihreällä) sarakkeet Sukupuoli ja Keskiväkiluku sarakkessa olevien havaintoarvojen mukaan.

Long ja wide aineistomuodoista on saatavilla kattavasti lisätietoa mm. open access kirjassa R for Data Science. Tällä hetkellä esimerkkiaineisto on leveässä muodossa, koska väestön keskiluku on nyt levitetty kahteen eri sarakkeeseen yhden sijasta. Seuraavissa esimerkeissä käytettävät funktiot ovat paketista tidyr.

Long-wide rakenteen ymmärtäminen auttaa koodin kirjoittamista, sillä R:ssä olevat funktiot ongelman korjaamiseksi on nimetty datalle tehtävän toimenpiteen mukaan: pivot_longer() ja pivot_wider(). Tässä tilanteessa meidän pitää tehdä kääntö: wide -> long, joten käytämme pivot_longer() funktiota.

Pivot_longer() kääntää cols (columns) kohtaan määritellyt sarakkeet pitkään muotoon, eli siirtää miehet ja naiset erikseen omale rivilleen joka vuoden kohdalle. Lisäksi funktioon tulee määritellä uusien sarakkeiden nimet, names_to kohtaan käännettävät sarakkeet ja uuden, syntyvän sarakkeesen nimi kohtaan values_to.

df1 %>% 
  pivot_longer(cols=Miehet:Naiset,
               names_to="Sukupuoli",
               values_to="Keskiväkiluku")

# A tibble: 20 x 3
   Vuosi Sukupuoli Keskiväkiluku
   <chr> <chr>     <chr>        
 1 2010  Miehet    2631741.5    
 2 2010  Naiset    2731610      
 3 2011  Miehet    2645475      
 4 2011  Naiset    2742796.5    
 5 2012  Miehet    2659578      
 6 2012  Naiset    2754392.5    
 7 2013  Miehet    2673493      
 8 2013  Naiset    2765479      
 9 2014  Miehet    2686113.5    
10 2014  Naiset    2775398      
11 2015  Miehet    2696676.5    
12 2015  Naiset    2782854      
13 2016  Miehet    2706908.5    
14 2016  Naiset    2788394      
15 2017  Miehet    2715729      
16 2017  Naiset    2792484.5    
17 2018  Miehet    2721210.5    
18 2018  Naiset    2794314      
19 2019  Miehet    2725776      
20 2019  Naiset    2795829.5  

Nyt kun tarkastamme Tidy Datan perusperiaatteet, voimme todeta, että jokainen muuttuja on omassa sarakkeessaan, jokainen havainto omalla rivillään ja jokainen on solu on yksi arvo. Nyt kun aineisto on puhdistetussa muodossa, joka on tallennettu objektiksi df2, pystymme laskemaan kätevästi naisten ja miesten yhteenlasketun keskiväkiluku funktioilla group_by() ja summarise().

df2 %>% 
  group_by(Vuosi) %>% 
  summarise(Keskiväkiluku=sum(as.numeric(Keskiväkiluku)))

# A tibble: 10 x 2
   Vuosi Keskiväkiluku
   <chr>         <dbl>
 1 2010       5363352.
 2 2011       5388272.
 3 2012       5413970.
 4 2013       5438972 
 5 2014       5461512.
 6 2015       5479530.
 7 2016       5495302.
 8 2017       5508214.
 9 2018       5515524.
10 2019       5521606.

Lisäharjoituksena voimme seuraavaksi kokeilla palauttaa nyt tidyyn muotoon saatu aineisto wide-muotoon käyttämällä funktiota pivot_wider().

Pivot_wider() toimii täysin vastaavasti pivot_longer():n kanssa, mutta tekee käännön vastakkaiseen suuntaan. Nimetään pivot_wider():n names_from käskyyn muuttuja Sukupuoli, josta saamme nimet uusille sarakkeille, ja kohtaan values_from muuttuja Keskiväkiluku, joka nimensä mukaan valitsee uusiin sarakkeisiin arvot Keskiväkiluku-sarakkeesta:

df2 %>% 
  pivot_wider(names_from=Sukupuoli,
              values_from=Keskiväkiluku)

# A tibble: 10 x 3
   Vuosi Miehet    Naiset   
   <chr> <chr>     <chr>    
 1 2010  2631741.5 2731610  
 2 2011  2645475   2742796.5
 3 2012  2659578   2754392.5
 4 2013  2673493   2765479  
 5 2014  2686113.5 2775398  
 6 2015  2696676.5 2782854  
 7 2016  2706908.5 2788394  
 8 2017  2715729   2792484.5
 9 2018  2721210.5 2794314  
10 2019  2725776   2795829.5

Näin saamme aineiston takaisin alkuperäiseen, leveään muotoon.

Tässä käytetyt funktiot toimivat vastaavissa aineiston kääntämisissä, mutta niiden intuitiivinen käyttö vaatii harjoittelua. Varsinkin alussa näitä funktioita käyttäessä kannattaa pitää help-tiedosto auki (esim. ?pivot_wider()). On myös hyvä ymmärtää, että tietyissä tilanteessa kannattaa tidyssa muodossa oleva aineisto muuttaa long tai wide muotoon analysoinnin ja visualisoinnin helpottamiseksi ja mahdollistamiseksi.

Muuttujien yhdistäminen ja erottaminen (separate ja unite)

Seuraavaksi käsittelemme yhtä yleisimmistä virheistä: Useampi muuttuja on samassa sarakkeessa (virhe 2). Tämä virhe on onneksi useimmiten yksinkertaista korjata. Tyypillinen esimerkki usean arvon sisältävästä muuttujasta on päivämäärät. Vaikka tidyverse sisältää erittäin käytännöllisen paketin päivämäärien muokkaukseen (lubridate), harjoittelemme muuttujien yhdistämistä ja erottamista päivämäärien avulla.

Esimerkkiaineisto luodaan funktioilla tibble() ja sample(), joka luo satunnaisen aineiston (tibble:n) haluamillamme kriteereillä (10 satunnaista päivää 1.1.2019 ja 1.1.2020 väliltä:

df_pvm <- tibble(pvm=sample(seq(as.Date('2019/01/01'), 
                       as.Date('2020/01/01'), 
                       by="day"), 10))

df_pvm

# A tibble: 10 x 1
   pvm       
   <date>    
 1 2019-05-30
 2 2019-12-16
 3 2019-11-05
 4 2019-10-02
 5 2019-11-13
 6 2019-09-26
 7 2019-08-22
 8 2019-08-12
 9 2019-02-09
10 2019-09-13

Nyt meillä on tallennettu aineisto objektiksi df_date, joka sisältää yhden sarakkeen nimeltä pvm, jossa on kymmenen päivämäärää. Haluaisimme kuitenkin erottaa tästä muuttujasta omiin sarakkeisiinsa päivän, kuukauden, sekä vuoden.

Tätä varten käytämme funktiota separate(), joka nimensä mukaisesti erottelee halutun muuttujan useammaksi muuttujaksi. Ensimmäiseksi määritellään sarake col, joka halutaan erotella. Lisäksi määritellään uudet sarakkeet joihin eroteltu muuttuja jaetaan argumentilla into. Koska muuttujasta tulee useampi uusi muuttuja, tulee ne määritellä vektoriksi (c()). Lopuksi määritellään, että minkä välimerkin perusteella jako (sep) tehdään (-).

df_pvm %>% 
  separate(col=pvm, into = c("vuosi", "kuukausi", "päivä"), sep="-")

# A tibble: 10 x 3
   vuosi kuukausi päivä
   <chr> <chr>    <chr>
 1 2019  05       30   
 2 2019  12       16   
 3 2019  11       05   
 4 2019  10       02   
 5 2019  11       13   
 6 2019  09       26   
 7 2019  08       22   
 8 2019  08       12   
 9 2019  02       09   
10 2019  09       13 

Näin saamme aineiston muuttujan erotettua kolmeen uuteen muuttujaan. Mikäli alkuperäisen muuttujan haluaa säästää, kannattaa se aluksi monistaa (pvm-> pvm1) ja erotella monistettu muuttuja:

df_pvm %>% 
  mutate(pvm1=pvm) %>% 
  separate(col=pvm1, into = c("vuosi", "kuukausi", "päivä"), sep="-")

# A tibble: 10 x 4
   pvm        vuosi kuukausi päivä
   <date>     <chr> <chr>    <chr>
 1 2019-05-30 2019  05       30   
 2 2019-12-16 2019  12       16   
 3 2019-11-05 2019  11       05   
 4 2019-10-02 2019  10       02   
 5 2019-11-13 2019  11       13   
 6 2019-09-26 2019  09       26   
 7 2019-08-22 2019  08       22   
 8 2019-08-12 2019  08       12   
 9 2019-02-09 2019  02       09   
10 2019-09-13 2019  09       13   

Mikäli aineistossa on taas päinvastainen tilanne, eli yksi muuttuja on useammassa sarakkeessa, voidaan se yhdistää yhdeksi muuttujaksi funktiolla unite(). Tätä havainnollistamaan voimme hyödyntää edellisessä esimerkissä luotua eroteltua pvm aineistoa, joka tallennetaan uudeksi objeksiksi df_separated.

df_separated <- df_pvm %>% 
  separate(col=pvm, into = c("vuosi", "kuukausi", "päivä"), sep="-")

Funktioon unite() määritellään ensin uuden muuttujan nimi (col), seuraavaksi sarakkeet jotka halutaan yhdistää (vuosi:päivä), sekä välimerkki joka lisätään yhdistettyjen sarakkeiden väliin (-).

df_separated %>% 
  unite(col=pvm, vuosi:päivä, sep="-")

# A tibble: 10 x 1
   pvm       
   <chr>     
 1 2019-05-30
 2 2019-12-16
 3 2019-11-05
 4 2019-10-02
 5 2019-11-13
 6 2019-09-26
 7 2019-08-22
 8 2019-08-12
 9 2019-02-09
10 2019-09-13

Näin saamme kolmen eroitellun sarakkeen tiedot takaisin yhteen sarakkeeseen.

Mikäli muuttujasta halutaan poimia vain tietty osa, voidaan se ensin muuttaa tekstiksi (string) ja valita tarvittava osa funktiolla substring(). Tämä tehdään käyttäen mutate():a, jonka avulla luomme uuden muuttujan nimelta vuosi. Funktioon substring() määritellään ensin muuttuja, josta poiminta tehdään, ja sen jälkeen eroitellaan pilkuin, monennesta merkistä poiminta alkaa ja monenteen se loppuu. Eli tässä tilanteessa pvm muuttujassa ensimmäiset 4 (1-4) merkkiä ovat vuosi, joten funktioon määritellään poiminnaksi 1,4.

df_pvm %>% 
  mutate(vuosi=substr(pvm,1,4))

# A tibble: 10 x 2
   pvm        vuosi
   <date>     <chr>
 1 2019-05-30 2019 
 2 2019-12-16 2019 
 3 2019-11-05 2019 
 4 2019-10-02 2019 
 5 2019-11-13 2019 
 6 2019-09-26 2019 
 7 2019-08-22 2019 
 8 2019-08-12 2019 
 9 2019-02-09 2019 
10 2019-09-13 2019 

Näin saamme poimittua uuteen muuttujaan ainoastaan vuosiluvun. Samalla tavalla voimme poimia myös kuukauden sekä päivän:

df_pvm %>% 
  mutate(vuosi=substr(pvm,1,4),
         kuukausi=substr(pvm,6,7),
         päivä=substr(pvm,9,10))

# A tibble: 10 x 4
   pvm        vuosi kuukausi päivä
   <date>     <chr> <chr>    <chr>
 1 2019-05-30 2019  05       30   
 2 2019-12-16 2019  12       16   
 3 2019-11-05 2019  11       05   
 4 2019-10-02 2019  10       02   
 5 2019-11-13 2019  11       13   
 6 2019-09-26 2019  09       26   
 7 2019-08-22 2019  08       22   
 8 2019-08-12 2019  08       12   
 9 2019-02-09 2019  02       09   
10 2019-09-13 2019  09       13  

Aineistojen yhdistäminen (Joining)

Yleisimmistä virheistä on enää käsittelemättä 4. (Useampi eri aineisto on samassa taulukossa) ja 5. (Yksi aineisto on useammassa eri taulukossa). Tämän vuoksi seuraavaksi käsitellään funktioryhmää join, joka myös kuuluu tidyversen dplyr– pakettiin. Kyseisten funktioiden avulla voimme yhdistää useamman aineiston samaan taulukkoon.

Join -funktioita on useampia, ja oikean funktion valinta riippuu halutusta lopputuloksesta. Funktioon määritellään aina yksi tai useampi sarake, jonka perusteella yhdistäminen tehdään, käyttäen argumenttia by.

Left_join(x,y, by=z) sisällyttää aineiston x (koodissa vasemmanpuoleinen) kokonaisuudessaan ja yhdistää y-aineistosta havainnot, joille löytyy vastaava arvo aineiston x sarakkeesta z.

Right_join(x,y, by=z) sisällyttää aineiston y (koodissa oikeanpuoleinen) kokonaisuudessaan, ja yhdistää aineistosta x havainnot, joille löytyy vastaava arvo aineiston y sarakkeesta z.

Inner_join(x,y, by=z) sisällyttää molemmista aineistosta kaikki havainnot, joille löytyy vastaava arvo molempien aineistojen sarakkeesta z.

Full_join(x,y, by=z) sisällyttää molemmista aineistosta kaikki havainnot, ja yhdistää ne, joille löytyy vastaava arvo molempien aineistojen sarakkeesta z.

Semi_join(x,y, by=z) sisällyttää aineistosta x kaikki havainnot, joille löytyy vastaava arvo aineiston y sarakkeesta z, mutta ei liitä aineiston y arvoja mukaan aineistoon x.

Anti_join(x,y, by=z) sisällyttää molemmista aineistoista kaikki havainnot, joille ei löydy vastaavaa arvoa molempien aineistojen sarakkeesta z.

Näin ollen, vaihtoehtoja aineistojen yhdistämiseen löytyy useita ja varsinkin alussa tulee olla tarkkana, että käyttää oikeaa vaihtoehtoa. Join-funktioiden ymmärtämistä varten kannattaa tutustua mm. Data Transformation Cheatsheetiin.

Tutustutaan seuraavaksi join-funktioihin esimerkkien kautta.

Luodaan kuvitteellinen aineisto, joka kuvaa jonkin taudin tapausmääriä n Suomessa molemmilla sukupuolilla vuosien

df_join <- tibble(Vuosi=as.character(seq(2010, 2019, 1)),
                  Miehet=sample(1000:2000, 10),
                  Naiset=sample(1000:2000, 10)) %>% 
  pivot_longer(cols=Miehet:Naiset,
               names_to="Sukupuoli",
               values_to="N")
  
df_join

# A tibble: 20 x 3
   Vuosi Sukupuoli     N
   <chr> <chr>     <int>
 1 2010  Miehet     1579
 2 2010  Naiset     1121
 3 2011  Miehet     1240
 4 2011  Naiset     1997
 5 2012  Miehet     1903
 6 2012  Naiset     1386
 7 2013  Miehet     1527
 8 2013  Naiset     1745
 9 2014  Miehet     1815
10 2014  Naiset     1739
11 2015  Miehet     1647
12 2015  Naiset     1424
13 2016  Miehet     1489
14 2016  Naiset     1035
15 2017  Miehet     1811
16 2017  Naiset     1231
17 2018  Miehet     1227
18 2018  Naiset     1575
19 2019  Miehet     1117
20 2019  Naiset     1205

Nyt aineisto on samassa muodossa kuin ensimmäisen esimerkin Tidy-muotoon muutettu aineisto df2. Aineistoja tarkastellessa huomaamme, että molemmista aineistoista löytyy muuttujat Vuosi ja Sukupuoli, mutta aineistossa df_join on muuttuja N, joka kuvaa tautitapausten määrää ja aineistossa df2 on Kokonaisväkiluku. Koska haluaisimme laskea näistä ilmaantuvuuden molemmille sukupuolille, täytyisi aineistot yhdistää ensin.

Nyt yhdistämisen suhteen on ideaalinen tilanne, koska samat muuttujat löytyvät molemmista aineistoista, ja ne ovat vieläpä saman nimiset. Lisäksi havaintoja on yhtä paljon. Näin ollen, yhdistämisen voisi tehdä useammalla eri funktiolla, mutta käytämme tässä left_join:ia, jota kannattaa käyttää tilanteessa, jossa alkuperäinen aineisto halutaan pitää koskemattomana ja ainoastaan lisätä siihen muuttujia toisesta aineistosta.

Esimerkissä otetaan aineisto df2, johon liitetään aineisto df_join.

df2 %>% 
  left_join(df_join)

# A tibble: 20 x 4
   Vuosi Sukupuoli Keskiväkiluku     N
   <chr> <chr>     <chr>         <int>
 1 2010  Miehet    2631741.5      1579
 2 2010  Naiset    2731610        1121
 3 2011  Miehet    2645475        1240
 4 2011  Naiset    2742796.5      1997
 5 2012  Miehet    2659578        1903
 6 2012  Naiset    2754392.5      1386
 7 2013  Miehet    2673493        1527
 8 2013  Naiset    2765479        1745
 9 2014  Miehet    2686113.5      1815
10 2014  Naiset    2775398        1739
11 2015  Miehet    2696676.5      1647
12 2015  Naiset    2782854        1424
13 2016  Miehet    2706908.5      1489
14 2016  Naiset    2788394        1035
15 2017  Miehet    2715729        1811
16 2017  Naiset    2792484.5      1231
17 2018  Miehet    2721210.5      1227
18 2018  Naiset    2794314        1575
19 2019  Miehet    2725776        1117
20 2019  Naiset    2795829.5      1205

Koska muuttujat Vuosi ja Sukupuoli ovat identtiset molemmissa aineistossa, funktio left_join() tunnistaa ne automaattisesti ja tekee yhdistämisen ilman että yhdistävää muuttujaa tarvitsee määritellä. Nyt saamme laskettua ilmaantuvuuden yksinkertaisesti mutate():lla. Ensin korjataan muuttujat Keskiväkiluku ja N numeerisiksi funktiolla as.numeric(), ja sitten lasketaan ilmaantuvuus jakamalla tautitapaukset (N) Keskiväkiluvulla ja kertomalla suhde 100 000:lla, jotta saamme vuosittaisen ilmaantuvuuden 100 000 henkilöä kohden:

df2 %>% 
  left_join(df_join) %>% 
  mutate(N = as.numeric(N),
         Keskiväkiluku=as.numeric(Keskiväkiluku),
         ilmaantuvuus=N/Keskiväkiluku*100000)

# A tibble: 20 x 5
   Vuosi Sukupuoli Keskiväkiluku     N ilmaantuvuus
   <chr> <chr>             <dbl> <dbl>        <dbl>
 1 2010  Miehet         2631742.  1579         60.0
 2 2010  Naiset         2731610   1121         41.0
 3 2011  Miehet         2645475   1240         46.9
 4 2011  Naiset         2742796.  1997         72.8
 5 2012  Miehet         2659578   1903         71.6
 6 2012  Naiset         2754392.  1386         50.3
 7 2013  Miehet         2673493   1527         57.1
 8 2013  Naiset         2765479   1745         63.1
 9 2014  Miehet         2686114.  1815         67.6
10 2014  Naiset         2775398   1739         62.7
11 2015  Miehet         2696676.  1647         61.1
12 2015  Naiset         2782854   1424         51.2
13 2016  Miehet         2706908.  1489         55.0
14 2016  Naiset         2788394   1035         37.1
15 2017  Miehet         2715729   1811         66.7
16 2017  Naiset         2792484.  1231         44.1
17 2018  Miehet         2721210.  1227         45.1
18 2018  Naiset         2794314   1575         56.4
19 2019  Miehet         2725776   1117         41.0
20 2019  Naiset         2795830.  1205         43.1

Useimmiten tilanne ei kuitenkaan ole näin yksinkertainen, vaan yhdistettävät sarakkeet ovat eri nimisiä ja havaintoja on myös muilta vuosilta kuin halutuilta. Tämän vuoksi luomme uuden kuvitteellisen aineiston, jossa on tiedot vain vuosilta 2000-2015, ja muuttujien nimet on englanniksi.

df_join2 <- tibble(Year=as.character(seq(2005, 2014, 1)),
                  Miehet=sample(1000:2000, 10),
                  Naiset=sample(1000:2000, 10)) %>% 
  pivot_longer(cols=Miehet:Naiset,
               names_to="Gender",
               values_to="N")

df_join2

# A tibble: 20 x 3
   Year  Gender     N
   <chr> <chr>  <int>
 1 2005  Miehet  1113
 2 2005  Naiset  1879
 3 2006  Miehet  1521
 4 2006  Naiset  1472
 5 2007  Miehet  1557
 6 2007  Naiset  1975
 7 2008  Miehet  1483
 8 2008  Naiset  1624
 9 2009  Miehet  1512
10 2009  Naiset  1721
11 2010  Miehet  1680
12 2010  Naiset  1686
13 2011  Miehet  1749
14 2011  Naiset  1398
15 2012  Miehet  1011
16 2012  Naiset  1417
17 2013  Miehet  1813
18 2013  Naiset  1486
19 2014  Miehet  1787
20 2014  Naiset  1534

Nyt kun käytämme funktiota left_join() saamme N ja Keskiväkiluvut niille vuosille jotka ovat ensimmäisessä aineistossa, sekä aineistoon jäävät mukaan vuodet jotka ovat vain ensimmäisessä aineistossa. Nyt täytyy kutenkin määritellä muuttujat, minkä perusteella yhdistäminen tehdään. Koska muuttujien nimet ovat erilaiset, tulee vastaavat muuttujat määritellä vektoriksi.

df2 %>% 
  left_join(df_join2, by = c("Vuosi" = "Year", 
                             "Sukupuoli" = "Gender"))

# A tibble: 20 x 4
   Vuosi Sukupuoli Keskiväkiluku     N
   <chr> <chr>     <chr>         <int>
 1 2010  Miehet    2631741.5      1680
 2 2010  Naiset    2731610        1686
 3 2011  Miehet    2645475        1749
 4 2011  Naiset    2742796.5      1398
 5 2012  Miehet    2659578        1011
 6 2012  Naiset    2754392.5      1417
 7 2013  Miehet    2673493        1813
 8 2013  Naiset    2765479        1486
 9 2014  Miehet    2686113.5      1787
10 2014  Naiset    2775398        1534
11 2015  Miehet    2696676.5        NA
12 2015  Naiset    2782854          NA
13 2016  Miehet    2706908.5        NA
14 2016  Naiset    2788394          NA
15 2017  Miehet    2715729          NA
16 2017  Naiset    2792484.5        NA
17 2018  Miehet    2721210.5        NA
18 2018  Naiset    2794314          NA
19 2019  Miehet    2725776          NA
20 2019  Naiset    2795829.5        NA

Nyt aineistossa df2 on mukana kaikki sen alun perin sisältämä tieto, mutta siihen on yhdistetty aineisto df_join2 mukaan niiltä vuosilta, joille molemmista aineistoista löytyi vastaavuus.

Mikäli haluaisimme sisällyttää kaikki df_join2 aineiston tiedot, ja yhdistää aineistosta df2 vain ne vuodet, jotka löytyvät molemmista aineistoista, voimme käyttää funktiota right_join().

df2 %>% 
  right_join(df_join2, by = c("Vuosi" = "Year", 
                             "Sukupuoli" = "Gender"))

# A tibble: 20 x 4
   Vuosi Sukupuoli Keskiväkiluku     N
   <chr> <chr>     <chr>         <int>
 1 2010  Miehet    2631741.5      1680
 2 2010  Naiset    2731610        1686
 3 2011  Miehet    2645475        1749
 4 2011  Naiset    2742796.5      1398
 5 2012  Miehet    2659578        1011
 6 2012  Naiset    2754392.5      1417
 7 2013  Miehet    2673493        1813
 8 2013  Naiset    2765479        1486
 9 2014  Miehet    2686113.5      1787
10 2014  Naiset    2775398        1534
11 2005  Miehet    NA             1113
12 2005  Naiset    NA             1879
13 2006  Miehet    NA             1521
14 2006  Naiset    NA             1472
15 2007  Miehet    NA             1557
16 2007  Naiset    NA             1975
17 2008  Miehet    NA             1483
18 2008  Naiset    NA             1624
19 2009  Miehet    NA             1512
20 2009  Naiset    NA             1721

Tässä tilanteessa olisikin ideaalisinta käyttää funktiota inner_join() joka sisällyyttää vain havainnot, joille löytyy molemmista aineistoista vastaavat arvot sarakkeista Vuosi/Year ja Sukupuoli/Gender:

df2 %>% 
  inner_join(df_join2, by = c("Vuosi" = "Year", 
                             "Sukupuoli" = "Gender"))
# A tibble: 10 x 4
   Vuosi Sukupuoli Keskiväkiluku     N
   <chr> <chr>     <chr>         <int>
 1 2010  Miehet    2631741.5      1680
 2 2010  Naiset    2731610        1686
 3 2011  Miehet    2645475        1749
 4 2011  Naiset    2742796.5      1398
 5 2012  Miehet    2659578        1011
 6 2012  Naiset    2754392.5      1417
 7 2013  Miehet    2673493        1813
 8 2013  Naiset    2765479        1486
 9 2014  Miehet    2686113.5      1787
10 2014  Naiset    2775398        1534

Yhteenvetona

Tässä artikkelissa käsittelimme yleisimpiä tilanteita sotkuisesta aineistosta. Useimmiten sotkuinen aineisto on lukuisilla eri tavoilla sotkuinen, jolloin putsaaminen vaatii useita eri menetelmiä. On tärkeää pitää mielessä Tidy Datan perusperiaatteet, ja aina ennen analysoinnin aloittamista käydä läpi mielessä seuraavat kysymykset:

  • Onko aineisto tidy?
  • Jos ei, niin mikä siitä tekee untidyn?
  • Mitä pitäisi tehdä että aineisto olisi tidy?
  • Millä funktioilla muutokset pystyisi tekemään?

Vaikka tässä artikkelissa pyrittiin käymään läpi yleisimmät sotkuisen aineiston virheet, on olemassa lukematon määrä tapoja, joilla aineisto voi olla sotkuinen, joten jokaisen aineiston puhdistaminen on aina erilaista. Tästä johtuen Tidy Dataan ja sen korjaamiseen kannattaa paneutua lisää englanninkielisten artikkeleiden kautta:

Kirjoittanut Ville Ponkilainen, vertaisarvioinut Aleksi Reito ja Mikko Uimonen.

Mitä mieltä olit artikkelin sisällöstä?

Klikkaa tähteä arvostellaksi artikkelin!

Keskiarvo 0 / 5. Arvostelujen lukumäärä: 0

Kukaan ei ole vielä äänestänyt, ole ensimmäinen

Vastaa

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