To understand computations in R, two slogans are helpful:
John Chambers Creator of the S programming language, and core member of the R programming language project.
- Everything that exists is an object.
- Everything that happens is a function call.“
Eli R:n toiminnan ymmärtämisessä on tärkeää muistaa kaksi asiaa:
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)
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
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
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)
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")
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)
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)
# vektorin indeksit
v1 <- 10:20
v1[1:4]
# data.frame
sw[[1,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
oletuksenalibrary(tidyverse)
# tulostetaan data sellaisenaan
sw
# tehdään datasta tibble ja tulostetaan
sw_tb <- tibble::as_tibble(sw)
sw_tb
# 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))
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.
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ä.
Garret Grolemundin Data wrangling with R and RStudio on hyvä johdanto datan käsittelyn perusteisiin sekä tidy-datan konseptiin.
Katso oheinen lyhyt video ggplot2:m perusteista. Jos tykkäät opetella asioita videoilta, katso joku perusteellisempi johdanto ggplot2
-pakettiin samaan syssyyn.
2017-2018 Markus Kainu.
Tämä teos on lisensoitu Creative Commons Nimeä 4.0 Kansainvälinen -lisenssillä.