5 Datan muokkaaminen
Aineisto ei tyypillisesti ole valmiiksi oikeassa muodossa. Voi olla että halutaan esimerkiksi käyttää vain jotain osajoukkoa aineistosta. Tällöin tarvitaan komentoja aineiston muokkaamiseksi.
Yleinen käytännön vinkki Aineiston muokkaaminen (data wrangling) on isojen tutkimusaineistojen kohdalla todella työlästä. Tällöin saatetaan joutua yhdistelemään aineistoja useista lähteistä, etsimään virheellisiä arvoja, muokkaamaan tekstimuotoisia (character) muuttujia eri muotoon ym. Mikäli halutaan muokata tekstimuotoisia vektoreita eri muotoon, niin ne kannattaa muuttaa faktoriksi vasta lopuksi, sillä muuttujan ei ole yleensä tarpeellista olla faktorimuodossa aineistoja muokatessa. Faktorit ovat tyypillisesti tarpeen vasta kun aineistoa aletaan todella analysoimaan.
5.1 Uuden muuttujan tai rivin luonti datakehikkoon
Uusi muuttuja voidaan luoda R:ssä joko perustuen aineiston muihin muuttujiin, tai muuttujan arvot voidaan syöttää vektorina aineistoon. Mikäli uusi muuttuja syötetään lukuina R-koodiin, tulee varmistua siitä, että havaintoja on sama määrä kuin aineistossa on rivejä. Muutoin aineisto tulee syötettyä virheellisesti ja tulokset eivät pidä paikkaansa.
Uuden sarakkeen luonti tapahtuu samalla tavalla kuin jo olemassa olevan sarakkeen muokkaaminen eli dollarisymbolilla, jossa dollarin jälkeen annetaan ensin uuden sarakkeen nimi ja tähän sijoitetaan halutut uuden muuttujan arvot.
# evaluate the number of rows and columns
dim(study_data)
## [1] 8 3
# there are 8 rows
# initiate a new variable called weight (imput data) with correct number of rows
$weight <- c(78.2, 65.8, 49.2, 71.2, 58.3, 54.1, 74.2, 62.8)
study_data
# calculate a new variable based on existing variables
$height_m <- study_data$height / 100 # height as metres
study_data$BMI <- study_data$weight / (study_data$height_m^2)
study_data study_data
## ID height gender weight height_m BMI
## 1 1 189.8 male 78.2 1.898 21.70773
## 2 2 184.0 female 65.8 1.840 19.43526
## 3 3 173.8 male 49.2 1.738 16.28792
## 4 4 175.9 male 71.2 1.759 23.01168
## 5 5 169.0 female 58.3 1.690 20.41245
## 6 6 183.7 male 54.1 1.837 16.03168
## 7 7 181.8 male 74.2 1.818 22.44999
## 8 8 16.9 female 62.8 0.169 2198.80256
5.2 Datakehikon käsittely
Datakehikosta voidaan poimia sarakkeita joko niiden nimien tai niitä vastaavien indeksien perusteella, kuten matriisin tapauksessa. Yksittäisiä sarakkeita voidaan poimia ja muokata myös dollarisymbolin $
kautta.
# Subscripting with variable names
c("height", "gender")] study_data[,
## height gender
## 1 189.8 male
## 2 184.0 female
## 3 173.8 male
## 4 175.9 male
## 5 169.0 female
## 6 183.7 male
## 7 181.8 male
## 8 16.9 female
# Subscripting with brackets - as matrix (but I do not recommend this style!)
1:2] study_data[,
## ID height
## 1 1 189.8
## 2 2 184.0
## 3 3 173.8
## 4 4 175.9
## 5 5 169.0
## 6 6 183.7
## 7 7 181.8
## 8 8 16.9
# Rownames and colnames
colnames(study_data)
## [1] "ID" "height" "gender" "weight" "height_m" "BMI"
names(study_data)
## [1] "ID" "height" "gender" "weight" "height_m" "BMI"
# Individual columns can be accessed and added with dollar sign
# Let's say that we find out that the ID number 8 was typed in incorrectly. We can fix the entire height variables as follows
$height <- c(189.8, 184.0, 173.8, 175.9, 169.0, 183.7, NA, 160.9)
study_data study_data
## ID height gender weight height_m BMI
## 1 1 189.8 male 78.2 1.898 21.70773
## 2 2 184.0 female 65.8 1.840 19.43526
## 3 3 173.8 male 49.2 1.738 16.28792
## 4 4 175.9 male 71.2 1.759 23.01168
## 5 5 169.0 female 58.3 1.690 20.41245
## 6 6 183.7 male 54.1 1.837 16.03168
## 7 7 NA male 74.2 1.818 22.44999
## 8 8 160.9 female 62.8 0.169 2198.80256
# It would have been possible to change value of only one cell e.g. like this
$height[8] <- 161.9
study_data study_data
## ID height gender weight height_m BMI
## 1 1 189.8 male 78.2 1.898 21.70773
## 2 2 184.0 female 65.8 1.840 19.43526
## 3 3 173.8 male 49.2 1.738 16.28792
## 4 4 175.9 male 71.2 1.759 23.01168
## 5 5 169.0 female 58.3 1.690 20.41245
## 6 6 183.7 male 54.1 1.837 16.03168
## 7 7 NA male 74.2 1.818 22.44999
## 8 8 161.9 female 62.8 0.169 2198.80256
Uuden rivin lisäys datakehikkoon on hieman monimutkaisempaa kuin uuden rivin lisääminen matriisiin, sillä ensin pitää tehdä uusi datakehikko, jolla on samat sarakkeet kuin alkuperäisellä (samassa järjestyksessä), ja vasta sitten liittää se komennolla rbind
. Käyttäjän tulee myös huolehtia siitä, että sarakkeet ovat samaa tyyppiä kuin alkuperäisessä datakehikossa.
<- data.frame(ID = 11, height = 182, gender = "male",
new_row weight = 81.2, height_m = 1.82, BMI = 81.2 / 1.82^2)
rbind(study_data, new_row)
## ID height gender weight height_m BMI
## 1 1 189.8 male 78.2 1.898 21.70773
## 2 2 184.0 female 65.8 1.840 19.43526
## 3 3 173.8 male 49.2 1.738 16.28792
## 4 4 175.9 male 71.2 1.759 23.01168
## 5 5 169.0 female 58.3 1.690 20.41245
## 6 6 183.7 male 54.1 1.837 16.03168
## 7 7 NA male 74.2 1.818 22.44999
## 8 8 161.9 female 62.8 0.169 2198.80256
## 9 11 182.0 male 81.2 1.820 24.51395
5.3 Osajoukkojen valinta
Aineistosta voi poimia osajoukon hakasulkujen avulla indeksoimalla. Osajoukon poimintaan tarvitaan usein vertailuoperattoreita, ja jos kriteerejä on useita, niin tarvitaan myös useita loogisia operaattoreita. Tarkemmin operaattoreita käsitellään luvussa Loogiset operaattorit. Voit käyttää kyseisen osion taulukkoa apuna jo tässä osiossa. Osajoukkoja voidaan poimia myös suoraan antamalla halutut indeksit esimerkiksi indeksivektorin avulla.
# Filter only females
$gender == "female", ] study_data[study_data
## ID height gender weight height_m BMI
## 2 2 184.0 female 65.8 1.840 19.43526
## 5 5 169.0 female 58.3 1.690 20.41245
## 8 8 161.9 female 62.8 0.169 2198.80256
# Filter individuals whose height is less than or equal to 175
$height <= 175, ] study_data[study_data
## ID height gender weight height_m BMI
## 3 3 173.8 male 49.2 1.738 16.28792
## 5 5 169.0 female 58.3 1.690 20.41245
## NA NA NA <NA> NA NA NA
## 8 8 161.9 female 62.8 0.169 2198.80256
# Filter individuals whose height is not missing and is less than or equal to 175
!is.na(study_data$height) & study_data$height <= 175, ] study_data[
## ID height gender weight height_m BMI
## 3 3 173.8 male 49.2 1.738 16.28792
## 5 5 169.0 female 58.3 1.690 20.41245
## 8 8 161.9 female 62.8 0.169 2198.80256
# Use multiple filter criteria
$height <= 175 & study_data$gender == "female", ] study_data[study_data
## ID height gender weight height_m BMI
## 5 5 169.0 female 58.3 1.690 20.41245
## 8 8 161.9 female 62.8 0.169 2198.80256
# Select individuals (rows) 1,3, and 7 directly with a vector of indices
<- c(1, 3, 7)
ind study_data[ind,]
## ID height gender weight height_m BMI
## 1 1 189.8 male 78.2 1.898 21.70773
## 3 3 173.8 male 49.2 1.738 16.28792
## 7 7 NA male 74.2 1.818 22.44999
5.4 Datakehikon ja vektorin järjestäminen
Yhden vektorin arvot voidaan asettaa nousevaan tai laskevaan järjestykseen funktiolla sort
. Funktiota voidaan soveltaa niin numeerisiin kuin merkkitietoa sisältäviin vektoreihinkin. Oletusarvoisesti järjestys on nouseva, eli numeeriset arvot järjestetään pienimmästä suurimpaan ja merkkitieto aakkosjärjestykseen. Järjestyksen voi kääntää laskevaksi argumentilla decreasing = TRUE
.
<- c(3, 1, 7, 8, 5, 4)
nums <- c("ab", "ca", "ac", "bb", "ba", "cb")
chars
# Ascending order
sort(nums)
## [1] 1 3 4 5 7 8
sort(chars)
## [1] "ab" "ac" "ba" "bb" "ca" "cb"
# Descending order
sort(nums, decreasing = TRUE)
## [1] 8 7 5 4 3 1
sort(chars, decreasing = TRUE)
## [1] "cb" "ca" "bb" "ba" "ac" "ab"
Jossain tilanteissa on haluttavaa järjestää datakehikon rivit jonkin muuttujan tai muuttujien suhteen. Tähän tarkoitukseen voi käyttää funktiota order
, joka palauttaa yhden tai useamman argumentin alkioiden järjestysluvut (rank). Seuraavassa esimerkissä aineiston rivit järjestetään koehenkilöiden pituuden suhteen nouseevaan suuruusjärjestykseen.
order(study_data$height),] study_data[
## ID height gender weight height_m BMI
## 8 8 161.9 female 62.8 0.169 2198.80256
## 5 5 169.0 female 58.3 1.690 20.41245
## 3 3 173.8 male 49.2 1.738 16.28792
## 4 4 175.9 male 71.2 1.759 23.01168
## 6 6 183.7 male 54.1 1.837 16.03168
## 2 2 184.0 female 65.8 1.840 19.43526
## 1 1 189.8 male 78.2 1.898 21.70773
## 7 7 NA male 74.2 1.818 22.44999
Järjestäminen voidaan tehdä usean muuttujan suhteen, esimerkiksi pituuden ja painon. Tämä tarkoittaa nousevassa järjestyksessä sitä, että jos kahdella koehenkilöllä on täsmälleen sama pituus, valitaan heidän keskinäinen järjestyksensä painon perusteella.
5.5 Faktorit
R:n numeeriset vektorit ovat lähtökohtaisesti jatkuva-asteikollisia. Olet ehkä ihmetellytkin, miten kategorinen muuttuja määritellään. Kategorista muuttujaa sanotaan R:ssä faktoriksi. Numeerisen tai tekstimuotoisen muuttujan tai vektorin voi muuttaa faktori-muotoiseksi muuttujaksi factor
-funktiolla.
# Let's change gender from character string to a factor and rename it as fgender
$fgender <- factor(study_data$gender)
study_data
# Let's now compare the printing of gender and fgender
$gender study_data
## [1] "male" "female" "male" "male" "female" "male" "male" "female"
$fgender study_data
## [1] male female male male female male male female
## Levels: female male
Huomataan, että faktori tulostaa faktorin tasot eli kaikkien mahdollisten luokkien nimet faktorin perässä: Levels: female male
.
Usein vastaan tulee myös tilanne, jossa faktorin eri tasoja vastaavat kokonaislukuarvot, kuten tässä esimerkissä luvut 1, 2 ja 3. Tällaisessa tilanteessa faktorin tasojen merkitys on usein annettu jossain dokumenttitiedostossa. Tällöin faktorin tasot ja niiden kuvaukset (labels) tulee määrittää käsin.
# Create a data for this example
<- data.frame(building_ID = c(1, 2, 3, 4, 5, 6), building_material = c(1, 1, 2, 2, 3, 3))
wall_dat
# Name is 'building_material' very long, I want to rename it
names(wall_dat) <- c("building_ID", "build_mat")
# We know from some kind of documentation that 1 stands for "wood", 2 is "steel" and 3 is "brick".
$fbuild_mat <- factor(wall_dat$build_mat,levels = c(1, 2, 3), labels = c("wood", "steel", "brick"))
wall_dat
str(wall_dat)
## 'data.frame': 6 obs. of 3 variables:
## $ building_ID: num 1 2 3 4 5 6
## $ build_mat : num 1 1 2 2 3 3
## $ fbuild_mat : Factor w/ 3 levels "wood","steel",..: 1 1 2 2 3 3
5.6 Extra: Lääketutkimusesimerkki
R:ssä on aiemmin nähtyjen numeric, character ja logical-vektorien lisäksi muitakin vektoriluokkia, tärkeimpänä näistä factor. Factor-vektoreihin tallennetaan kategorisia muuttujia, kuten tutkimuksessa määrättyjä ryhmiä, aikapisteitä tms. Luodaan esimerkiksi factor-vektori, jossa on kuvitteellisen lääketutkimuksen osallistujien ryhmätiedot:
<- as.factor(c("drug1", "drug2", "control", "drug1", "control",
groups "drug2", "drug2", "control", "control", "drug1"))
groups
## [1] drug1 drug2 control drug1 control drug2 drug2 control control
## [10] drug1
## Levels: control drug1 drug2
Factoreita voi luoda muista vektoreista funktioilla factor
tai as.factor
. as.factor
muuntaa vektorin automaattisesti ja nopeasti factoriksi, ja säilyttää myös jo valmiiksi factor-luokan vektorien tasojen järjestyksen (tästä lisää pian).
Kuten tulosteesta nähdään, factor-vektorin tulostus tulostaa factorin alkiot (HUOM: ei lainausmerkkejä) sekä factorin tasot. Factorit ovat pinnan alla kokonaisluku- eli integer-vektoreita, joissa on päällä “kerros”, joka määrittää factorin tasot. Edellä nähty vektori groups näyttää siis tältä:
Factorien tasoille annetaan siis lukuarvot ykkösestä eteenpäin. Oletuksena ensimmäinen taso eli taso 1 on aakkosissa ensimmäinen arvo, tai pienin lukuarvo jos factori tehdään numeerisista muuttujista. Lukuarvot saa näkyville muuntamalla factorin numeeriseksi vektoriksi:
as.numeric(groups)
## [1] 2 3 1 2 1 3 3 1 1 2
Tasojen järjestyksen voi myös päättää itse. Tämä on tärkeää, sillä kuten pian nähdään, factorin ensimmäinen taso on monissa tilastollisissa testeissä ns. referenssitaso, johon muita tasoja verrataan. Usein esiintyvä tapaus ovat tutkimukset, joissa on ryhmät nimeltä case ja control. Koska case on aakkosissa ennen controllia, R käyttää oletuksen case-ryhmää referenssitasona, ja testaa miten control-ryhmä poikkeaa tästä tasosta, vaikka haluaisimme päinvastaisen tuloksen. Tasot voi itse määrittää näin:
<- factor(c("case", "control", "control", "case", "case"),
study_groups levels = c("control", "case"))
study_groups
## [1] case control control case case
## Levels: control case
Nyt tasot ovat oikeassa järjestyksessä!
Kuten aiemmin mainittiin, factoreita voi tehdä myös numeerisista vektoreista. HUOM: muista, että as.numeric()
palauttaa factorin kokonaislukuarvot, ei alkuperäisiä lukuja. Alkuperäiset luvut saa käyttämällä ensin as.character
-funktiota, joka muuttaa factorin tasot merkkijonovektoriksi.
<- as.factor(c(0, 0, 1, 1, 5, 5, 1, 0, 5))
time_points time_points
## [1] 0 0 1 1 5 5 1 0 5
## Levels: 0 1 5
# Probably not what you expect
as.numeric(time_points)
## [1] 1 1 2 2 3 3 2 1 3
# First to character, then to numeric
as.numeric(as.character(time_points))
## [1] 0 0 1 1 5 5 1 0 5