1 Kertausta

1.1 R:n perusteet

To understand computations in R, two slogans are helpful:

  • Everything that exists is an object.
  • Everything that happens is a function call.“
John Chambers
Creator of the S programming language, and core member of the R programming language project.

Eli R:n toiminnan ymmärtämisessä on tärkeää muistaa kaksi asiaa:

  1. Kaikki mitä on olemassa ovat objekteja
  2. Kaikki mikä tapahtuu, tapahtuu kutsumalla funktioita

1.1.1 Objektien luominen

Everything that exists is an object

objekti <- objektin_arvo
objekti = objektin_arvo

100 * (0.05 + 0.05)
# [1] 10
sqrt(10+6)
# [1] 4

# numeerinen vektori jonka pituus on 1 ja arvo 100
sata <- 100
sata
# [1] 100
is(sata)
# [1] "numeric" "vector"

# character vektori jonka pituus on 1 ja arvo "sata"
sata_tekstina <- "sata"
sata_tekstina
# [1] "sata"
is(sata_tekstina)
# [1] "character" "vector" "data.frameRowLabels" "SuperClassMethod"
# Luodaan kaksi 7 elementin pituista vektoria, joista toinen on numeerinen ja toinen character
nimi <- c("Juhani","Tuomas","Aapo","Simeoni","Timo","Lauri","Eero")
ika  <- c(25,23,23,22,20,20,17)
typeof(nimi)
# "character"
typeof(ika)
# "double"
length(ika)
# loogiset vektorit
looginen_vektori <- c(TRUE,FALSE,T,T,F,FALSE)

1.1.2 Funktioiden kutsuminen/käyttö

Everything that happens is a function call

vektori <- c(1,2,3,4,5,6,7,8)
ka <- mean(vektori)
ka
# [1] 4.5
is(mean)
# [1] "function" "OptionalFunction" "PossibleMethod"
sum(vektori)
# [1] 36

1.1.3 Koodin kirjoituskonventiot

Koodia kirjoitetaan ensisijaisesti tietokoneelle, mutta sen pitää olla ymmärrettävää myös ihmisille. R-ympäristössä on erilaisia tapoja kirjoittaa komentoja, ja tällä kurssilla pyrin käyttämään paljon ns. ketjutusta (piping ie. pipeline).

R:ään tämän ketjutuksen tarjoaa magrittr-paketti. Pipe-operator tai putkioperaattori %>% voidaan ajatella tarkoittavan then/sitten. Pikanäppäin on Ctrl + Shift + m.

Alla on erilaisia tapoja kirjoittaa/jäsentää koodia/analyysiprosessia. Esimerkissä käsitellään dplyr::starwars

library(dplyr)
d <- dplyr::starwars
 
# 1) Yksi operaatio per rivi
d_subset <- select(d, name, height, mass, hair_color, skin_color, eye_color, homeworld, species)
d_non_humans <- filter(d_subset, species != "Human")
d_non_humans_punajasinisilmat <- filter(d_subset, eye_color %in% c("red","blue"))
d_non_humans_punajasinisilmat_by_height <- arrange(d_non_humans_punajasinisilmat, desc(height))
tulos1 <- slice(d_non_humans_punajasinisilmat_by_height, 1:5)

# + analyysin välivaiheet on saatavilla
# - paljon nimeämistä, joka työlästä

# 2) operaatiot sisäkkäin yhdellä rivillä

tulos2 <- slice(arrange(filter(filter(select(d, name, height, mass, hair_color, skin_color, eye_color, homeworld, species),species != "Human"), eye_color %in% c("red","blue")), desc(height)), 1:5)
 
# - edellyttää lukemista oikealta vasemmalle
# + ei tarvitse nimetä

# 3) Operaatiot ketjutettuina
tulos3 <- d %>%  
  select(name, height, mass, hair_color, skin_color, eye_color, homeworld, species) %>% 
  filter(species != "Human") %>% 
  filter(eye_color %in% c("red","blue")) %>% 
  arrange(desc(height)) %>% 
  slice(1:5)

# + ei tarvitse nimetä
# + vasemmalta oikealle
# - ei pääsyä välivaiheisiin

1.2 Funktiot tiedostojärjestelmän käyttöön

Tiedostojärjestelmätoiminnot [fs](http://fs.r-lib.org/)-paketilla

library(magrittr)
# luo kansio "aineisto" nykyiseen työhakenmistoon
dir.create(path = "./aineisto")
fs::dir_create(path = "./aineisto")
# luo uusi tekstitiedosto "teksti.txt" nykyiseen työhakemistoon ja avaa se muokattavaksi
file.create("./teksti.txt")
file.edit("./teksti.txt")
fs::file_create("./teksti.txt") %>% file.edit()
# listaa työhakemistossa ja sen alahakemistoissa olevat tiedostot, joilla pääte ".R"
list.files(path = "./", all.files = TRUE, full.names = TRUE, recursive = TRUE, pattern = ".R$")
fs::dir_ls(path = "./",  all = TRUE, type = "file",  recursive = TRUE, glob = "*.R")
# listaa kaikki työhakemiston alahakemistot ja niiden alahakemistot
list.dirs(path = "./", recursive = TRUE, full.names = TRUE)
fs::dir_ls(path = "./",  all = TRUE, type = "directory",  recursive = TRUE)
# kopioi tiedosto teksti.txt kansioon aineisto
file.copy(from = "./session1_perusteet.R", to = "./aineisto")
fs::file_copy(path = "./session1_perusteet.R", new_path = "./aineisto/session1_perusteet.R")
# poista kaikki tiedostot kansiosta aineisto, joilla pääte ".R"
file.remove(list.files(path = "./aineisto", pattern = ".R$"))
fs::file_delete(path = fs::dir_ls(path = "./",  all = TRUE, type = "file",  recursive = TRUE, glob = "*.R"))
# fs-paketin näppärät lisämuuttujat
fs::dir_info(path = "./", all = TRUE, recursive = TRUE, type = "file") %>% 
  arrange(desc(size))
# tiedostojen lataaminen verkosta levylle
download.file(url = "http://siteresources.worldbank.org/INTRES/Resources/469232-1107449512766/allginis_2013.xls", 
              # windowsissa muista
              mode = "wb",
              destfile = "./aineisto/allginis_2013.xls")
# pakattujen zip-tiedostojen lataaminen ja purkaminen
download.file(url = "http://fenixservices.fao.org/faostat/static/bulkdownloads/Food_Security_Data_E_All_Data_(Normalized).zip",
              destfile = "./Food_Security_Data_E_All_Data_(Normalized).zip")
unzip("./Food_Security_Data_E_All_Data_(Normalized).zip", exdir = "./aineisto")
file.remove("./Food_Security_Data_E_All_Data_(Normalized).zip")
d <- read.csv("./aineisto/Food_Security_Data_E_All_Data_(Normalized).csv", stringsAsFactors = FALSE)

1.3 Datojen lukeminen ja kirjoittaminen

fs::dir_create("./aineisto_tmp/")
download.file("http://www.qogdata.pol.gu.se/data/qog_oecd_cs_jan18.csv", "./aineisto_tmp/qog_oecd_cs_jan18.csv", mode = "wb")
download.file("http://www.lisdatacenter.org/wp-content/uploads/it04ip.sav", "./aineisto_tmp/it04ip.sav", mode = "wb")
download.file("http://www.lisdatacenter.org/wp-content/uploads/it04ip.sas7bdat", "./aineisto_tmp/it04ip.sas7bdat", mode = "wb")
download.file("http://www.lisdatacenter.org/wp-content/uploads/it04ip.dta", "./aineisto_tmp/it04ip.dta", mode = "wb")

csv   <- readr::read_csv("./aineisto_tmp/qog_oecd_cs_jan18.csv")
spss  <- haven::read_sav("./aineisto_tmp/it04ip.sav")
sas   <- haven::read_sas("./aineisto_tmp/it04ip.sas7bdat")
stata <- haven::read_dta("./aineisto_tmp/it04ip.dta")

haven::write_dta(data = stata, path = "./aineisto_tmp/stata.dta")
haven::write_sas(data = stata, path = "./aineisto_tmp/stata.sas7bdat")
haven::write_sav(data = stata, path = "./aineisto_tmp/stata.sav")

fs::dir_delete(path = "./aineisto_tmp") 

1.4 Pakettien asentaminen ja lataaminen

Asentamalla uusia paketteja saat R:ään käyttöön uusia funktioita. Monissa paketeissa mukana tulee myös pieniä datoja funktioiden käytön harjoitteluun. Useimmat paketeista mahdollistavat jonkun laskennallisen operaation tekemisen, yhä useammat tarjoavat toiminnallisuuksia R:stä esim. tietokantojen (eurostat) tai verkkoteknologioiden (leaflet) rajapintoihin.

# Asenna keskitetystä pakettihallinnasta CRAN
install.packages("eurostat")
# Ota paketti käyttöön
library(eurostat)
# Asenna kehitysversiot github:sta devtools-paketin avulla
devtools::install_github("ropengov/eurostat")

Ladattujen pakettien uusia funktioita voi käyttää joko A) lataamalla paketin ja kutsumalla funktiota tai B) kutsumalla pakettia ja funktiota yhtä aikaa. Tämän kurssin materiaaleissa pyrin käyttämään aina vaihtoehtoa B, jotta opiskelijoille olisi selkeämpää milloin käytössä oleva funktio on ns. “ulkoisesta” paketista ja milloin taas ns. base-R:stä

# tapa A
library(eurostat)
d <- get_eurostat(id = "tgs00026")
# tapa B
d <- eurostat::get_eurostat(id = "tgs00026")

Paketit tulee asentaa uudelleen aina uuden R-version myötä (x.y version kohdalla, ei x.y.z kohdalla)

1.5 Datojen käsittelyn perusteet

Kurssin esimerkeissä tästä eteenpäin näytetään aina kaksi erilaista tapaa toteuttaa sama operaatio, 1) ns. base-R ratkaisu (ilman lisäpaketteja) ja 2) dplyr ratkaisu. Ratkaisut ovat aina peräkkäin ja dplyr-toteutus on aina merkitty eksplisiittisesti dplyr::funktio_x().

Kurssillä pyrimme käyttämään ainoastaan ns. data.frame luokkaan kuuluvia objekteja. Teknisesti ajateltuna R:ssä data.frame on vektoreista koostuva lista. Vektorit voivat olla numeerisia, tekstiä tai faktoreita, mutta niiden tulee olla saman pituisia (ks. 7-veljestä demo).

Käytetään dataa starwars paketista dplyr.

sw <- as.data.frame(dplyr::starwars) # tehdään aluksi normaaliksi data.frameksi
nrow(sw) # rivien määrä
ncol(sw) # sarakkeiden/muuttujien määrä
dim(sw)  # molemmat
# Kuusi ensimmäistä riviä
head(sw) # tai
sw[1:6,] # tai
# dplyr-tapa
dplyr::slice(sw, 1:6)

1.5.1 Vektoreiden ja datojen rakenteet ja niihin viittaaminen

# vektorin indeksit
v1 <- 10:20
v1[1:4]

# data.frame
sw[[1,2]]

1.5.2 data.frame vs. tibble

R:llä on jo ikää ja tavanomaisen data.frame:n oheen on kehitetty vastaavia hieman modernimpia luokkia, kuten data.table ja tibble. data.table on saman nimisen paketin luokka vastaavalle rakenteelle, jolle tehdyt metodit ovat nopeita. Luokka eroaa data.frame luokasta sen verran, että perusmetodit eivät aina toimi. Mm. siitä syystä tällä kurssilla käytämme rinnakkain datoja luokissa tibble ja data.frame.

  • stringsAsFactors = FALSE oletuksena
  • printtaa nätisti
  • list-columns eli listasarakkeet
library(tidyverse)
# tulostetaan data sellaisenaan
sw
# tehdään datasta tibble ja tulostetaan
sw_tb <- tibble::as_tibble(sw)
sw_tb

1.5.3 Datan suodattaminen: Rivien/tapausten valitseminen (filtering)

# tehdään ensin sw-dastasta tibble
sw <- dplyr::starwars
# valitaan kaikki ruskeatukkaiset hahmot
sw[sw$hair_color == "brown",]
dplyr::filter(sw, hair_color == "brown") # dplyr
# valitaan kaikki alle kaksimetriset, joilla siniset silmät
sw[sw$height < 200 & sw$eye_color == "blue",]
dplyr::filter(sw, height < 200, eye_color == "blue") # dplyr
# valitaan kaikki M:llä alkavat hahmot
sw[grepl("^M", sw$name),]
dplyr::filter(sw, grepl("^M", name)) # dplyr
# valitaan rivit väliltä 10-15
sw[10:15,]
dplyr::slice(sw, 10:15)

Datan suodattaminen: Sarakkeiden/muuttujien valitseminen

# valitaan muuttujat "name", "height" ja "mass"
sw[,c("name", "height","mass")]
dplyr::select(sw, name, height, mass) # dplyr
# valitaan kolme ensimmäistä muuttujaa
sw[,1:3]
dplyr::select(sw, 1:3) # dplyr
# valitaan ensimmäinen, neljäs ja kuudes muuttuja
sw[,c(1,4,6)]
dplyr::select(sw, c(1,4,6)) # dplyr

Datan suodattaminen: Sekä muuttujien että sarakkeiden valitseminen

# valitaan kaikki alle kaksimetriset hahmot, joilla siniset silmä JA sarakkeet name, eye_color ja mass
sw[sw$height < 200 & sw$eye_color == "blue",c("name", "eye_color","mass")]

library(dplyr)
sw %>%
  dplyr::filter(height < 200, eye_color == "blue") %>%
  dplyr::select(name, eye_color, mass)

Uusien muuttujien tekeminen laskemalla vanhoista

# lasketaan uusi muuttuja painoindeksi kullekin hahmolle
sw$bmi <- sw$mass / (sw$height/100)^2
# ja listataan vaan lievästi tai enemmän ylipainoiset
sw[sw$bmi >= 25,(c("name","bmi"))]

library(dplyr)
sw %>%
  dplyr::mutate(bmi = mass / (height/100)^2) %>%
  dplyr::filter(bmi >= 25) %>% 
  select(name,bmi) %>% 
  arrange(desc(bmi))

2 Luento 2 - Datan käsittelyn ja visualisoinnin perusteet

Tällä luennolla jatkamme datan datan käsittelyä ja aloitamme grafiikkaharjoitukset ´ggplot2`-paketilla. Starwars-datan ohella otamme käyttöön sivuston data-osiossa kuvatut aineistot.

2.1 Datan lukeminen/tuominen R:ään

Datan lukeminen levyltä on melko yksinkertaista, mutta katso oheisen webinaarin alku (0.00 - 14.00): Hadley Wickham - Getting your data into R. Lataa slaidit täältä.

2.2 Datan käsittely dplyr & tidyr -paketeilla

Garret Grolemundin Data wrangling with R and RStudio on hyvä johdanto datan käsittelyn perusteisiin sekä tidy-datan konseptiin.

2.3 Visualisoinnin perusteet ggplot2-paketilla

Katso oheinen lyhyt video ggplot2:m perusteista. Jos tykkäät opetella asioita videoilta, katso joku perusteellisempi johdanto ggplot2-pakettiin samaan syssyyn.

2.4 Tee ja palauta harjoitustehtävä!


2017-2018 Markus Kainu.

Creative Commons -lisenssi
Tämä teos on lisensoitu Creative Commons Nimeä 4.0 Kansainvälinen -lisenssillä.