Praktikum 7
Praktikumi kood: praktikum7_kood.r.
Andmetöötlus paketiga dplyr
Pakett dplyr mõeldud andmetabelite täienduste, tabelis olevate objektide või tunnuste alamhulkade valiku, grupeerimise ja sorteerimise teostamiseks. Samuti saab selle abil leida erinevaid andmeid agregeerivaid tabeleid, mis sobivad kirjeldava statistilise analüüsi läbiviimiseks. Paketi dplyr käskude juures võib välja tuua veel nende töö kiiruse suuremate andmestike korral. Põhjalik ülevaade selle paketi käskudest on paketi dokumentatsioonis1.
Paketiga kaasnevad põhifunktsioonid saab liigitada kolme kategooriasse:
- Read
filter()-- valib andmestikust vaatlused/read tõeväärtusvektori põhjal.slice()-- valib andmestikust read indeksi põhjal.arrange()-- andmestiku ridade sorteerimine.
- Veerud
select()-- valib andmestikust nime põhjal tunnused.rename()-- muudab andmestiku tunnuste nimesid.mutate()-- lisab andmestikku uusi tunnuseid, mis on leitud olemasolevate põhjal.
- Rühmitatud read
summarise()-- summaarsete näitajate leidmine.
Kõigi funktsioonide esimene argument on andmetabel, järgmised argumendid täpsustavad, mida andmestikuga teha tuues ära tunnuste nimed, mille kirjapanekuks siin käskudes jutumärke pole vaja kasutada. Kõik funktsioonid väljastavad tulemuseks omakorda andmetabeli. Käsk group_by() määrab toimingute tegemise gruppide kaupa, ehk rühmitab read.
Paketi dplyr käskude kasutamine
Loeme kõigepealt sisse näiteandmestiku: Massachusettsi valikuuring
mass <- read.table("https://courses.ms.ut.ee/LTMS.00.016/2026_fall/uploads/Main/mass.txt", sep = "\t", header = T)
Paketi installimine ja aktiveerimine:
#install.packages(dplyr) # vajadusel installeerida pakett library(dplyr)
Käsu mutate() abil saab andmestiku veergudega teisendusi teha, uusi tunnuseid tekitada või ka mingeid tunnuseid kustutada
# arvutame kaks uut tunnust, kustutame ühe vana
mass1 <- mutate(mass,
kuus = WAGP/12,
kuus_euro = kuus * 0.8,
MIG = NULL)
Käsk filter(.) aitab valida välja teatud kriteeriumitele vastavaid ridu. See on kiirem kui kantsulgude kasutamine, sest kantsulgusid kasutades vaadatakse üksikud elemendid ükshaaval üle, ent filter(.) käsu puhul kasutatakse nutikamaid algoritme (enamasti andmed sorditakse mingil moel enne kui hakatakse üldse filtris määratud kriteeriumeid kontrollima).
# rakendame filtrit (ekraanile paari esimese veeru väärtused neil vaatlustel) filter(mass, AGEP > 70, WAGP > 100000)[,1:3]
## id AGEP CIT ## 935 9452 84 U.S. citizen by naturalization ## 4900 49277 71 Born in the U.S. ## 6374 64546 77 Born in the U.S.
Käsu select(.) abil saab välja valida tingimustele vastavaid veerge andmestikust. Järgmises näites on rakendatud esmalt ridade filtreerimist, seejärel tehtud valik veergude hulgast: valitakse need veerud, mille nimes sisaldub täht "G", esimene veerg ja veerg nimega PINCP. Näeme, et select(.) käsus võib kombineerida veergude valikul tõeväärtusvektoreid, indekseid ja nimesid.
# rakendame filtrit ja selekteerime tunnuseid
select(filter(mass, AGEP > 70, WAGP > 100000), contains("G"), 1, PINCP)
## AGEP MIG WAGP id PINCP ## 935 84 No, different house in US or Puerto Rico 150000 9452 283000 ## 4900 71 Yes, same house (nonmovers) 110000 49277 259600 ## 6374 77 Yes, same house (nonmovers) 145000 64546 192900
Käsku slice(.) kasutades on võimalik eraldada alamandmestike kasutades reaindekseid. Käsuga kaasnevad ka abifunktsioonid levinud kasutusjuhtude jaoks:
slice_max(.)jaslice_min(.)-- eraldada vaatluseid mille puhul etteantud tunnuse väärtused on suurimad/vähimad.slice_sample(.)-- valida juhusliku arvu või osakaalu ridu.slice_head(.)jaslice_tail(.)-- valida andmestiku esimesed/viimased read.
Kõigile abifunktsioonidele on võimalik argumendiga n ette anda väljastavate ridade arv. Alternatiivselt on argumendiga prop võimalik määrata kui suur osakaal andmestikust valitakse. Käske slice_max(.) või slice_min(.) kasutades on võimalik, et väljastataske rohkem ridu kui argumendiga n on määratud, kui vastava tunnuse puhul on vaatluste astakud võrdsed.
select(slice(mass, c(1:10, 113:117)), 2:3)
## AGEP CIT ## 1 90 Born in the U.S. ## 2 49 Born in the U.S. ## 3 77 Born in the U.S. ## 4 33 Not a citizen of the U.S. ## 5 50 Born in the U.S. ## 6 8 Born in the U.S. ## 7 81 Born in the U.S. ## 8 31 Born in the U.S. ## 9 46 Born in the U.S. ## 10 45 Born in Puerto Rico, Guam, the U.S. Virgin Islands, ## 113 84 Born in the U.S. ## 114 11 Born in the U.S. ## 115 14 Born in the U.S. ## 116 4 Born in the U.S. ## 117 76 Born in the U.S.
select(slice_max(mass, PINCP, n = 3), PINCP, 2:3)
## PINCP AGEP CIT ## 2595 1078000 51 Born in the U.S. ## 77 854000 42 Born in the U.S. ## 5115 731000 49 Born in the U.S. ## 5654 731000 54 Born in the U.S.
#select(slice_max(mass, PINCP, n = 4), PINCP, 2:3) select(slice_sample(mass, prop = 0.0001))
Käsk group_by(.) aitab andmestiku tükkideks jagada, aga ei tee sellega midagi enamat. Kui tükkidel soovida midagi analüüsida, tuleb group_by(.) funktsiooni tulemus ette anda vastavaks analüüsiks kasutatavale funktsioonile. Siin kohal on hea kasutada funktsiooni summarise(.), mis esitab agregeeritud tulemused:
summarise(group_by(mass, CIT),
keskpalk = mean(WAGP, na.rm = T),
n = n(),
notNA = sum(!is.na(WAGP)))
## # A tibble: 5 × 4 ## CIT keskpalk n notNA ## <chr> <dbl> <int> <int> ## 1 Born abroad of American parent(s) 28589. 62 51 ## 2 Born in Puerto Rico, Guam, the U.S. Virgin Islands, 12516. 79 74 ## 3 Born in the U.S. 33829. 5422 4361 ## 4 Not a citizen of the U.S. 32797. 448 423 ## 5 U.S. citizen by naturalization 30703. 413 404
Käsu arrange(.) abil saab andmestikke sorteerida
osa <- filter(select(mass, id, SEX, AGEP, WKHP, WAGP), WAGP > 300000, AGEP < 55) arrange(osa, SEX, desc(AGEP), WKHP)
## id SEX AGEP WKHP WAGP ## 393 4026 Female 53 50 502000 ## 4716 47523 Female 44 45 502000 ## 5427 54710 Female 38 30 502000 ## 5654 56856 Male 54 65 502000 ## 4468 45001 Male 52 60 502000 ## 2595 26473 Male 51 60 502000 ## 2666 27055 Male 50 60 502000 ## 5115 51654 Male 49 60 502000 ## 6327 63966 Male 48 48 502000 ## 4195 42026 Male 45 40 502000 ## 4860 48820 Male 45 40 502000 ## 1254 12981 Male 45 55 502000 ## 4697 47379 Male 45 60 502000 ## 4809 48414 Male 45 70 502000 ## 77 821 Male 42 50 502000 ## 1182 12187 Male 40 50 502000 ## 2689 27263 Male 40 60 502000 ## 3782 38114 Male 39 50 502000 ## 6178 62255 Male 37 60 502000 ## 4191 41999 Male 34 60 502000 ## 5989 60364 Male 32 55 502000 ## 5950 59973 Male 29 85 502000
Kuigi tänapäeval on toru ehk aheldamisoperaator (kujul |>) defineeritud ka R-i baasversioonis, võite siiski kohata ka paketis dplyr defineeritud toru (kujul %>%). Toru operaatoriga on võimalik ühe funktsiooni tulemused edasi anda järgmisele funktsioonile, ilma, et vahetulemust ekraanile prinditaks või uuele muutujale omistataks. Ehk koodi, kus on vaja rakenda kahte funktsiooni fun1 ja fun2 järgmiselt fun2(fun1(x), y) võib kirja panna kujul fun1(x) |> fun2(y). Esimese funktsiooni tulemus antakse siin teisele funktsioonile ette esimeseks argumendiks. Rstudio-s on toru operaatori klahvikombinatsiooniks Windowsi süsteemidel Ctrl+Shift+M, MacOS süsteemidel Command+Shift+M.
Toru kasutamine aitab mõnikord muuda koodi loetavamaks. Näiteks, kui on vaja leida andmestikust mass soo ja perekonnaseisu gruppides keskmist palka ning grupi mahtu ja saadud tulemustabelist näha esimesi ridu, siis aheldamisoperaatori abil saaks selle kirja panna järgmiselt:
mass |> group_by(SEX, MAR) |> summarise(keskpalk = mean(WAGP, na.rm = T), n = n()) |> head()
## `summarise()` has grouped output by 'SEX'. You can override using the `.groups` argument.
## # A tibble: 6 x 4 ## # Groups: SEX [2] ## SEX MAR keskpalk n ## <chr> <chr> <dbl> <int> ## 1 Female Divorced 33860 281 ## 2 Female Married 28164. 1356 ## 3 Female Never married or under 15 years old 21621. 1336 ## 4 Female Separated 19476. 54 ## 5 Female Widowed 4233. 272 ## 6 Male Divorced 39444. 187
Kui paneksime sama asja kirja "tavaliselt", siis peaksime koodirida alustama nö tagantpoolt ettepoole ehk alustama viimasest operatsioonist, mida andmetele rakendada (head)
head(summarise(group_by(mass, SEX, MAR), keskpalk = mean(WAGP, na.rm = T), n = n()))
Kuigi vaikimisi kasutatakse toru operaatorile eelnevat esimese argumendina, on võimalik seda suvalise argumendina kasutada. Näiteks lm() käsu puhul pole andmestik data esimene argument, nagu see on mitmete tidyverse paketide puhul, vaid hoopis teine. Siiski on meil võimalik saadud andmestiku toru operaatoriga lm() käsule ette anda kui kasutame alakriipsu soovitud argumendi väärtustamiseks (siin näites data=_).
?lm() mtcars |> lm(mpg~hp) #veateade mtcars |> lm(mpg~hp, data = _)
Ülesanded
- Leia inimeste vanuses 16 aastat kuni 85 (kaasaarvatud) aastat, keskmine ja maksimaalne nädala töötundide arv (WKHP), soo ja vanusgruppide (5-aastased vanusgrupid) kaupa. Esita tabelis ka gruppide mahud ja vaatluste arv, mida on keskväärtuse/maksimumi leidmisel kasutatud. Leia küsitud tabel kahte moodi, nii "toru" kasutades kui ilma.
- Tee eelmise ülesande andmete põhjal joondiagramm.
- Aheldamisoperaatorit kasutades ühenda eelmised kaks ülesannet.
- Tekita tabel, kus oleks soo ja perekonnaseisu gruppides leitud keskmine vanus, vanuse standardhälve ja levinum haridustase.
- Täienda eelmist tabelit gruppide osakaaludega ja järjesta osakaalude järgi kasvavalt.
Pakett data.table
Suurte andmete filtreerimiseks, teisendamiseks, agregeerimiseks ja grupeerimiseks sobib ka pakett data.table2.
Paketi andmetabel ehk data.table on tavalise andmetabeli data.frame-i edasiarendus. Nagu tavalise andmetabeli korral on data.table tabelist võimalik objekte ja veerge valida kantsulgudes indekseid määrates. Lisavõimalus on see, et data.table tabelis saab sel moel uusi tunnuseid arvutada, tunnuseid jooksvalt uuendada ning andmeid grupitunnuse põhjal agregeerida.
Kui DT on data.table tüüpi andmetabel, siis põhisüntaksi kuju saab kirja panna järgnevalt
DT[i, j, by]
kus
imäärab read/objektid, mida edasi kasutadajmäärab veerud, mis valitakse, uuendatakse või tekitataksebymäärab vajadusel grupitunnusejtehtavateks arvutustesse.
Näited data.table süntaksi kasutamisest
Siinkohal mõned näiteid andmestikust objektide või veergude valimisest ja arvutuste kirjapanekust. Proovi need läbi ja uuri tulemust. Erinevalt tavalisest andmestikust ei ole data.table tabelites reanimesid, on ainult reanumbrid, seega rida nime järgi valida saa. Teiseks võib välja tuua, et tekstitunnused on neis tabelites vaikimisi character tüüpi, mitte factor tüüpi.
#install.packages("data.table") # vajadusel installeerida
library(data.table)
# data.table tüüpi objekti moodustamine
DT <- data.table(a = 1:10,
b = rep(1:3, c(3, 3, 4)),
c = rep(LETTERS[5:7], c(4, 3, 3)))
DT
## a b c ## 1: 1 1 E ## 2: 2 1 E ## 3: 3 1 E ## 4: 4 2 E ## 5: 5 2 F ## 6: 6 2 F ## 7: 7 3 F ## 8: 8 3 G ## 9: 9 3 G ## 10: 10 3 G
str(DT)
## Classes 'data.table' and 'data.frame': 10 obs. of 3 variables: ## $ a: int 1 2 3 4 5 6 7 8 9 10 ## $ b: int 1 1 1 2 2 2 3 3 3 3 ## $ c: chr "E" "E" "E" "E" ... ## - attr(*, ".internal.selfref")=<externalptr>
Ridade ja veergude valik (alamosa andmetabelist)
DT[1:2, ] DT[b > 1.5, ] DT[, 3] DT[, a] DT[,"a"] DT[b > 1.5, 3] DT[c(1, 3:4), .(a, b)] DT[.N,]
Uue tabeli moodustamine, arvkarakteristikud, loendamine, uued tunnused:
DT[, .(kv = mean(a), s = sd(a), mitu = .N), by = c] DT[a > 3, .N] DT[, .N, by = c] DT[, .(d = a + 50)]
Olemasoleva tabeli sees muudatuste tegemine. Lisatud tühjad kantsulud [] rea lõpus prindivad muudetud tabeli DT ekraaanile. Üldjuhul neid lisama ei pea.
# ühe uue tunnuse lisamine
DT[, d := a + 5][]
# mitme uue tunnuse lisamine
DT[, c("uus1", "uus2") := .(a + 5, b - 2) ][]
# mitme uue tunnuse lisamine, variant 2
DT[, [ `:=` ] (uus3 = a + 50,
uus4 = b - 2,
b = -b)][]
# väärtuste muudatus valitud ridades
DT[c(2, 4), a := a*10L][]
# uus tunnus, aga mitte igas reas
DT[c(2, 4), uus5 := a*10L][]
# tunnuste kustutamine
DT[, uus5 := NULL][]
DT[, c("uus1", "uus2") := NULL][]
Ülesanded
- Teisenda andmestik
masspaketi data.table andmetüübiks käsugaas.data.table(.). - Kasutades
DT[i, j, by]konstruktsiooni leia mitu meessoost üle 60 aastast on uuritavate hulgas. - Kasutades
DT[i, j, by]konstruktsiooni leia perekonnaseisu sagedustabel. - Järjesta eelmine tabel sageduste järgi kasvavalt.
- *Soovi korral proovi ka dplyr-i osale järgnenud ülesandeid data.table-ga lahendada.