Rakendustarkvara:
R
4. praktikum1
4. praktikum1
1 Toimingud andmestikuga – jätk
1.1 Andmestike täiendamine ja ühendamine
Oleme tutvunud, kuidas andmestikust saab eraldada alamhulki (nt ridu
või veerge, mis vastavad teatud kriteeriumitele). Ühekaupa saab uusi
veerge data.frame-tüüpi objektile lisada nii dollarimärgi
kui kantsulgude abil, kui anname ette uue veeru nime.
Vaatame siin näiteandmestikuna andmestikku mk
(maakonnad.txt), mis sisaldab infot USA 5 osariigi mõnede
maakondade kohta (425 maakonda). Loeme andmed sisse
mk <- read.table("https://github.com/Rkursus/2022/raw/master/data/maakonnad.txt", sep = " ", header = TRUE)
Mitut uut veergu või rida saab andmestikule lisada
cbind(.) ja rbind(.) käskudega. Neid kasutades
tuleb aga olla ettevaatlik: lisatavas reas peab olema sama palju
elemente kui on andmestikus veerge ja lisatavas veerus peab olema sama
palju elemente, kui on andmestikus ridu. Tunnuste nimed lisatavates
ridades peavad vastama andmestiku omale, samuti peab lisatavates
veergudes objektide järjestus olema sama kui esialgses andmestikus.
# teeme kaks uut tunnust
suurus <- cut(mk$pop_estimate, c(0, 1000, 10000, 1000000, Inf),
labels = c("mikro", "väike", "keskmine", "suur"), include.lowest = T)
sooylekaal <- ifelse(mk$fem > 50, "F", "M")
# lisame need vektorid andmestiku lõppu veergudeks:
mk <- cbind(mk, suurus, sooylekaal)
# või
lisatabel<- data.frame(suurus, sooylekaal)
mk <- cbind(mk, lisatabel)
# ridade lisamine, praegu tekitame sellega dubleeritud vaatlusi!
lisa <- rep(seq(1, nrow(mk), by = 60),c(1:3, 1:3, 1, 1))
mktopelt <- rbind(mk, mk[lisa, ]) # seda andmestikku kasutame järgnevalt ühes ülesandes
Sageli on analüüsiks vajaminevad andmed mitmes erinevas andmetabelis,
mis võivad olla objektide arvu poolest ka erinevad. Näiteks
jooksuvõistluste andmete puhul võivad ühes tabelis olla kirjas
isikuandmed (nimi, sugu, vanus), teises tabelis aga võistlustulemuste
andmed. Kui sooviks analüüsida tulemuste jaotust sugude vahel või
sõltuvalt vanusest, oleks mugav need tabelid mestida käsuga
merge(.). Andmete ühendamiseks peaks mõlemas tabelis olema
nn võtmetunnus, mille abil read vastavusse pannakse.
isikud <- data.frame(nimi = c("Peeter", "Mari", "Tiina", "Laine"),
sugu = c("M", "N", "N", "N"), vanus = c(30, 22, 25, 20))
tulemused <- data.frame(nimi = c("Mari", "Peeter", "Tiina", "Peeter", "Toomas"),
tulemus = c(30.1, 22.5, 18.4, 25.3, 20.4),
voistlus = c("jooks1", "jooks1", "jooks2", "jooks2", "jooks2"))
isikud
## nimi sugu vanus
## 1 Peeter M 30
## 2 Mari N 22
## 3 Tiina N 25
## 4 Laine N 20
tulemused
## nimi tulemus voistlus
## 1 Mari 30.1 jooks1
## 2 Peeter 22.5 jooks1
## 3 Tiina 18.4 jooks2
## 4 Peeter 25.3 jooks2
## 5 Toomas 20.4 jooks2
(kokku <- merge(isikud, tulemused, by = "nimi", all = TRUE))
## nimi sugu vanus tulemus voistlus
## 1 Laine N 20 NA <NA>
## 2 Mari N 22 30.1 jooks1
## 3 Peeter M 30 22.5 jooks1
## 4 Peeter M 30 25.3 jooks2
## 5 Tiina N 25 18.4 jooks2
## 6 Toomas <NA> NA 20.4 jooks2
1.1.1 Ülesanded
- Kuidas peaks
mergekäsu kirja panema, kuiisikudjatulemusedandmestikes on võtmetunnusel erinev nimi? - Proovi, mis muutub
mergekäsu tulemuses, kui kasutadaall = TRUEargumendi asemelall.x = TRUEvõiall.y = TRUE.
1.2 Sorteerimine
Väga sageli soovime, et andmestiku read oleks mingi tunnuse (nt inimese vanuse) alusel sorteeritud. Sorteeri-miseks on R-is kaks olulist käsku:
order(.)tagastab etteantud vektori elementide järjekorranumbrid sellises järjekorras, et saaksime järjestatud vektori, mh argumendigadecreasingsaab määrata, kas see on kahanev või kasvav;sort(.)tagastab etteantud vektori elemendid kasvavas (või kahanevas) järjekorras.
x <- c(8, 1, NA, 7, 7)
order(x)
## [1] 2 4 5 1 3
sort(x, na.last = TRUE)
## [1] 1 7 7 8 NA
x[order(x)]
## [1] 1 7 7 8 NA
#andmestiku ridade sorteerimine kahe vektori järgi:
kokku[order(kokku$vanus, kokku$tulemus, decreasing = TRUE), ]
## nimi sugu vanus tulemus voistlus
## 4 Peeter M 30 25.3 jooks2
## 3 Peeter M 30 22.5 jooks1
## 5 Tiina N 25 18.4 jooks2
## 2 Mari N 22 30.1 jooks1
## 1 Laine N 20 NA <NA>
## 6 Toomas <NA> NA 20.4 jooks2
1.2.1 Ülesanded
- Loe sisse kaks andmestikku ja tutvu nendega (dimensioon,
tunnused):
link <- "https://github.com/Rkursus/2022/raw/master/data/"
visiidid <- read.table(paste0(link, "visiidid.txt"), sep = "\t", header = TRUE)
inimesed <- read.table(paste0(link, "isikud.txt"), sep = "\t", header = TRUE)
- Andmestikus
visiididon neli veergu:ik– isikukood,visiidi_kp– arsti külastamise kuupäev,vererohk– süstoolne vererõhk antud arstivisiidil (mmHg),crv- C-reaktiivse valgu kontsentratsioon (nn näpuveri) (mg/L). Visiitide andmestik kirjeldab 10 aasta jooksul arsti külastamisel tehtud vererõhu ja CRV mõõtmisi. - Andmestikus
inimesedon isikukoodid ja isikukoodist tuletatud info(sugu, sünnikuupäev, vanus).
Järjesta visiitide andmestik kasvavalt isikukoodi ja arstivisiidi kuupäeva järgi.
Ühenda isikukoodide ning visiitide andmestik, ühendatud andmestik peab sisaldama kõik inimesed mõlemast andmestikust. Mitu vaatlust on ühendatud andmestikus? Mis tunnuste osas esineb puuduvaid väärtusi.
1.3 Unikaalsed ja mitmekordsed elemendid. Hulgatehted.
Mõnikord on üks objekt andmestikus mitu korda, ent me soovime seda
ainult ühel korral analüüsi kaasata. Etteantud vektorist saab unikaalsed
elemendid kätte käsuga unique(.). Käsuga
duplicated(.) saab teada, kas ette antud
vektoris/andmetabelis on element esimest või juba mitmendat korda
(tulemuseks on tõeväärtusvektor, kus TRUE tähendab seda, et
antud väärtus on juba mitmendat korda).
# vaatame andmestikku 'kokku', andmestike ühendamise alapunktist
kokku$nimi
## [1] "Laine" "Mari" "Peeter" "Peeter" "Tiina" "Toomas"
unique(kokku$nimi) # unikaalsed nimed
## [1] "Laine" "Mari" "Peeter" "Tiina" "Toomas"
duplicated(kokku$nimi) # mitmes element nimede vektoris on dubleeriv
## [1] FALSE FALSE FALSE TRUE FALSE FALSE
duplicated(kokku) # mitmes rida andmestikus on dubleeriv (sellist pole!)
## [1] FALSE FALSE FALSE FALSE FALSE FALSE
R-is on realiseeritud ka elementaarsed hulgaoperaatorid: ühisosa,
ühend ja vahe. Käsk union(x, y) tagastab ette antud kahe
vektori x ja y elementidest koostatud uue
vektori, sealjuures mõlema vektori kõik elemendid on esindatud. Käsk
intersect(x, y) tagastab vektori elementidest, sealjuures
on esindatud ainult need elemendid mis on nii vektoris x
kui ka y. Käsk setdiff(x, y) tagastab vektori,
kus on ainult need x elemendid, mida vektoris
y ei ole. Kõik hulgatehete käsud tagastavad sellised
vektorid, kus igat elementi on ainult üks kord
x <- c(1:5, 1:5)
y <- 3:7
union(x, y)
intersect(x, y)
setdiff(x, y)
1.3.1 Ülesanded
Kontrolli kas alapunktis 1.1 tekitatud andmestikus
mktopelton dubleeritud andmeid. Mitu objekti on korduvad? Kas mõni maakond on rohkem kui 2 korda korratud? Kui jah, siis millised?Vaata visiitide ja isikukoodide ühendatud andmestikku. Kas arsti mitte külastanud isikute osakaal (protsentuaalselt) on suurem meeste või naiste hulgas?
2 Andmestiku teisendused
2.1 Pikk ja lai andmetabel. Pakett reshape2
Teise praktikumi materjali alguses näiteks toodud traditsioonilist andmetabeli kuju ehk \(objekt \times\ tunnus\)-maatriksit nimetatakse vahel ka nn laias formaadis andmestikuks, tabeli iga rida vastab ühele objektile, infoliiasus on viidud miinimumini. Näide laias formaadis andmestikust:
## nimi kaal pikkus sugu pulss0m pulss10m pulss30m
## 1 Mari 68 170 2 70 130 150
## 2 Jaan 65 180 1 80 120 120
## 3 Jüri 100 190 1 80 190 NA
Pikas formaadis andmestiku puhul proovitakse hoida
kõiki sama omadust kirjeldavaid andmeid ühes veerus; üks objekt võib
kajastuda mitmel real. Sellisel kujul andmestikku on mõnikord mugav
arvuti abil analüüsida (nt segamudelite hindamine, joonised
ggplot2 paketiga):
## nimi kaal pikkus sugu variable value
## 1 Mari 68 170 2 pulss0m 70
## 2 Jaan 65 180 1 pulss0m 80
## 3 Jüri 100 190 1 pulss0m 80
## 4 Mari 68 170 2 pulss10m 130
## 5 Jaan 65 180 1 pulss10m 120
## 6 Jüri 100 190 1 pulss10m 190
## 7 Mari 68 170 2 pulss30m 150
## 8 Jaan 65 180 1 pulss30m 120
## 9 Jüri 100 190 1 pulss30m NA
Eriti äärmuslik on pika formaadi puhul hoida kõiki arvulisi tunnuseid ühes veerus:
## nimi variable value
## 1 Mari kaal 68
## 2 Jaan kaal 65
## 3 Jüri kaal 100
## 4 Mari pikkus 170
## 5 Jaan pikkus 180
## 6 Jüri pikkus 190
## 7 Mari sugu 2
## 8 Jaan sugu 1
## 9 Jüri sugu 1
## 10 Mari pulss0m 70
## 11 Jaan pulss0m 80
## 12 Jüri pulss0m 80
## 13 Mari pulss10m 130
## 14 Jaan pulss10m 120
## 15 Jüri pulss10m 190
## 16 Mari pulss30m 150
## 17 Jaan pulss30m 120
## 18 Jüri pulss30m NA
Andmestiku ühest formaadist teise viimiseks tutvume paketiga
reshape2, milles olulisimad käsud melt(.)
ja dcast(.) aitavad vastavalt teisendada andmestikku laiast
formaadist pikka ja vastupidi, ning teha veel täiendavaid
toiminguid/arvutusi.
Funktsioon melt(.) teisendab andmed laiast formaadist
pikka. Argumendiga measure.vars saab sellele ette anda
veerunimede või -indeksite vektori, milles olevad tunnused pannakse kõik
ühte veergu. Vaikimisi pannakse kõik arvulised väärtused ühte veergu
nimega value ning teises veerus nimega
variable on kirjas, mida antud väärtus tähendab (millises
veerus see väärtus esialgses andmestikus oli).
#install.packages("reshape2") # kui arvutis pole paketti reshape2, siis esmalt installida
library(reshape2)
vr <- data.frame(nimi = c("Mari", "Jaan", "Jyri"),
kaal = c(68, 65, 100),
pikkus = c(170, 180, 190),
sugu = c(2, 1, 1),
pulss0m = c(70, 80, 80),
pulss10m = c(130, 120, 190), pulss30m = c(150, 120, NA))
(m <- melt(vr, measure.vars = 5:7)) # välimised sulud tingivad ekraanile trükkimise
## nimi kaal pikkus sugu variable value
## 1 Mari 68 170 2 pulss0m 70
## 2 Jaan 65 180 1 pulss0m 80
## 3 Jyri 100 190 1 pulss0m 80
## 4 Mari 68 170 2 pulss10m 130
## 5 Jaan 65 180 1 pulss10m 120
## 6 Jyri 100 190 1 pulss10m 190
## 7 Mari 68 170 2 pulss30m 150
## 8 Jaan 65 180 1 pulss30m 120
## 9 Jyri 100 190 1 pulss30m NA
Funktsioon dcast(.) aitab andmeid pikast formaadist laia
teisendada, sealjuures tuleb argumendiga formula kindlasti
ette öelda, millised tunnused määravad ära tulemusandmestiku read ning
millised määravad ära veerud:
formula = reatunnus1 + reatunnus2 ~ veerutunnus1 + veerutunnus2.
Väga kasulik on argument fun.aggregate, mille abil saab
määrata, kas ja millist funktsiooni peaks kasutama veerutunnustega antud
väärtuste agregeerimiseks. Funktsiooniga recast(.) saab
korraga ära teha töö, mille teeks ära järjestikku rakendatud
melt(.) ja dcast(.) käsud.
dcast(m, formula = nimi ~ variable)
## nimi pulss0m pulss10m pulss30m
## 1 Jaan 80 120 120
## 2 Jyri 80 190 NA
## 3 Mari 70 130 150
dcast(m, nimi + kaal ~ variable + sugu)
## nimi kaal pulss0m_1 pulss0m_2 pulss10m_1 pulss10m_2 pulss30m_1 pulss30m_2
## 1 Jaan 65 80 NA 120 NA 120 NA
## 2 Jyri 100 80 NA 190 NA NA NA
## 3 Mari 68 NA 70 NA 130 NA 150
dcast(m, nimi ~ . , fun.aggregate = mean, na.rm = TRUE, value.var = "value")
## nimi .
## 1 Jaan 106.6667
## 2 Jyri 135.0000
## 3 Mari 116.6667
2.1.1 Ülesanded
- Kasuta arstivisiitide ja isikute andmestiku ühte alamosa:
link <- "https://github.com/Rkursus/2022/raw/master/data/"
valik <- read.table(paste0(link, "valik.txt"), sep = "\t", header = TRUE). Vaata andmestik ülehead(valik). Tegu on valikuga isikutest, tunnuste osas on lisatud visiidi järjekorranumber.- Vii andmed laiale kujule, kus iga isiku jaoks oleks andmestikus üks rida, kus on kirjas isikukood, sugu, sünnikuupäev, vanus ning vererõhu väärtus esimesel ja teisel visiidil.
- Vii andmed laiale kujule, kus iga isiku jaoks oleks andmestikus üks rida, kus on kirjas isikukood, sugu, sünnikuupäev, vanus, crv väärtus esimesel ja teisel visiidil ning vererõhu väärtus esimesel ja teisel visiidil.
- Kasuta arstivisiitide andmestikku.
visiidid <- read.table(paste0(link, "visiidid.txt"), sep = "\t", header = TRUE)
Leia iga isiku keskmine vererõhk ja CRV.
3 Veel andmestruktuure
Oleme varem tutvunud sellega, mis tüüpi võivad olla üksikud
andmeelemendid (int, char, Factor
jm). Üksikuid elemente saab kokku panna üheks vektoriks näiteks käsuga
c(.), millega oleme samuti tuttavad. Samuti oleme tuttavad
data.frame-tüüpi objektiga – see on R-is andmetabeli tüüp.
Andmeid on aga võimalik R-is hoida ka teistsugustes struktuurides kui
vektor või data.frame.
Maatriks on sisuliselt vektor, mille elemendid on
paigutatud ridadesse ja veergudesse. Kuna tegemist on vektoriga, siis
peavad kõik elemendid olema sama tüüpi. Maatriksit saab luua mitmel
moel. Käsule matrix(.) tuleks ette anda vastav vektor ning
see, mitmesse ritta ja veergu selle vektori elemendid paigutatakse.
Olemasolevaid reavektoreid saab omavahel ühendada käsuga
rbind(.), veeruvektoreid käsuga cbind(.).
(m <- matrix(1:12, nrow = 3, byrow = F))
## [,1] [,2] [,3] [,4]
## [1,] 1 4 7 10
## [2,] 2 5 8 11
## [3,] 3 6 9 12
cbind(1:3, 5:7, 11:13)
## [,1] [,2] [,3]
## [1,] 1 5 11
## [2,] 2 6 12
## [3,] 3 7 13
Maatriksi elemente saab eraldada kantsulgudega:
m[1:2, 2:3]
## [,1] [,2]
## [1,] 4 7
## [2,] 5 8
List on universaalne andmestruktuur. Sisuliselt on
tegemist erinevatest elementidest koosneva loendiga, sealjuures need
elemendid võivad olla täiesti erinevat tüüpi objektid (isegi
funktsioonid). Kui listi elementidel on nimi, saab sobiliku elemendi
kätte dollarimärgi ja nime abil, üldisemalt saab elementide eraldamiseks
kasutada kahekordseid kantsulgusid. Listi saab tekitada käsuga
list(.). Uusi elemente saab lisada kantsulgudes indeksi
abil või dollarimärgi abil.
(minulist <- list(esimene = "üksainus sõne", matrix(1:12, 3), funktsioon = min))
## $esimene
## [1] "üksainus sõne"
##
## [[2]]
## [,1] [,2] [,3] [,4]
## [1,] 1 4 7 10
## [2,] 2 5 8 11
## [3,] 3 6 9 12
##
## $funktsioon
## function (..., na.rm = FALSE) .Primitive("min")
# elementide valik listist
minulist$esimene
## [1] "üksainus sõne"
minulist[[2]]
## [,1] [,2] [,3] [,4]
## [1,] 1 4 7 10
## [2,] 2 5 8 11
## [3,] 3 6 9 12
# elementide lisamine listi
minulist$neljas <- c(5, 7) # lisame uue elemendi
minulist[[5]] <- letters[1:10] # lisame veel ühe uue elemendi
# muudetud listi struktuuri vaatamine
str(minulist)
## List of 5
## $ esimene : chr "üksainus sõne"
## $ : int [1:3, 1:4] 1 2 3 4 5 6 7 8 9 10 ...
## $ funktsioon:function (..., na.rm = FALSE)
## $ neljas : num [1:2] 5 7
## $ : chr [1:10] "a" "b" "c" "d" ...
Andmetabel (data.frame) on tegelikult
teatud piirangutega list: kõik elemendid peavad olema sama pikad
vektorid (võivad olla erinevat tüüpi). Andmetabelit saab “käsitsi”
tekitada käsuga data.frame(.):
df <- data.frame(esimene = 1:5,
"2. veerg" = 11:15,
nimed = c("Peeter", "Mari", "Kaur", NA, "Tiiu"))
Kontrollimaks, kas tegemist on maatriksi, listi või andmetabeliga,
saab kasutada käske is.matrix(.), is.list(.),
is.data.frame(.). Veelgi kasulikum on käsk
class(.), millega saab objekti tüübi nime teada.
class(df)
## [1] "data.frame"
is.list(df)
## [1] TRUE
3.0.1 Ülesanded
Tekita list:
sõnad <- list(
a = c("aabits", "aade", "aadel", "aader", "aadlik"),
b = c("baar", "baas", "baat"),
c = c("c-vitamiin", "ca", "circa", "cafe"))
Eralda listist teine element, kasutades elemendi nime.
Eralda listist teine element, kasutades elemendi indeksit.
Eralda listist esimese elemendi kolmas element.
Praktikumijuhendid põhinevad aine MTMS.01.092 Rakendustarkvara: R (2 EAP) materjalidel, mille autorid on Mait Raag ning Raivo Kolde↩︎