── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.2 ✔ readr 2.1.4
✔ forcats 1.0.0 ✔ stringr 1.5.0
✔ ggplot2 3.4.2 ✔ tibble 3.2.1
✔ lubridate 1.9.2 ✔ tidyr 1.3.0
✔ purrr 1.0.1
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Når vi tar inn et datasett i SPSS er det vanligvis fordi vi vil transformere det på et vis. Vi gjør også en god del transformasjoner i Excel. Så klart skal vi også transformere verdier i R også. Nå vil vi merke fordelen ved at R er designa for å operere på vektorer. Når du gjør en transformasjon på en kolonne i et datasett (som du kanskje husker kan anses som en vektor i en liste), vil R utføre transformasjonen på hele lista. Hva betyr det? Vi lager en enkel kolonne i et datasett. Kolonnas verdi avhenger av en annen kolonne i datasettet.
# A tibble: 87 × 4
name hair_color eye_color blond_blue_eyed
<chr> <chr> <chr> <lgl>
1 Luke Skywalker blond blue TRUE
2 C-3PO <NA> yellow FALSE
3 R2-D2 <NA> red FALSE
4 Darth Vader none yellow FALSE
5 Leia Organa brown brown FALSE
6 Owen Lars brown, grey blue FALSE
7 Beru Whitesun lars brown blue FALSE
8 R5-D4 <NA> red FALSE
9 Biggs Darklighter black brown FALSE
10 Obi-Wan Kenobi auburn, white blue-gray FALSE
# ℹ 77 more rows
Det vakre her er at vi slipper å iterere over alle radene i hver kolonne og sammenlikne dem med hverandre via f.eks. en loop. R gjør dette av seg sjøl.
Når vi transformerer tar vi en verdi i et datasett og endrer på den. Dette har vi allerede gjort mange ganger allerede iløpet av denne pamfletten, men la oss nå formelt introdusere arbeidshesten vår: mutate().
9.1 Mutate
mutate() kommer fra etc. etc. You know the drill. Den en enkel å bruke. Hvis vi vil lage en ny kolonne bare gir vi den et navn og definerer hvordan den skal se ut. Vi tar inn prognoseeksemplet vårt:
Her er noen nyttige funksjoner som jeg ofte bruker sammen med mutate().
Varianter av if else: ifelse(), if_else og case_when.
# Vi lager et datasett med noen personer som vi veit kjønn og alder til.set.seed(123)folk <-tibble(kjonn =rep(c("M", "K"), 25),alder =round(runif(50, 10, 80)))folk
# A tibble: 50 × 2
kjonn alder
<chr> <dbl>
1 M 30
2 K 65
3 M 39
4 K 72
5 M 76
6 K 13
7 M 47
8 K 72
9 M 49
10 K 42
# ℹ 40 more rows
# Vi kan lage en ny variabel som forteller oss hvem som er myndig (fylt 18):# Til dette bruker vi `if_else()`. folk %>%mutate(myndig =if_else(alder >17, TRUE, FALSE))
# A tibble: 50 × 3
kjonn alder myndig
<chr> <dbl> <lgl>
1 M 30 TRUE
2 K 65 TRUE
3 M 39 TRUE
4 K 72 TRUE
5 M 76 TRUE
6 K 13 FALSE
7 M 47 TRUE
8 K 72 TRUE
9 M 49 TRUE
10 K 42 TRUE
# ℹ 40 more rows
# Verdiene til `if_else()` kan være noe annet også:folk %>%mutate(myndig =if_else(alder >17, "myndig", "barn"))
# A tibble: 50 × 3
kjonn alder myndig
<chr> <dbl> <chr>
1 M 30 myndig
2 K 65 myndig
3 M 39 myndig
4 K 72 myndig
5 M 76 myndig
6 K 13 barn
7 M 47 myndig
8 K 72 myndig
9 M 49 myndig
10 K 42 myndig
# ℹ 40 more rows
Hva er forskjellen på ifelse() og if_else()? Sistnevnte kommer fra dplyr og er en kjappere og strengere versjon av ifelse(). Alle argumenta må være av samme type, så du henter du får feilmelding når du bruker denne.
case_when() er en nyttig utvidelse av if else-tankegangen når vi har mer enn to muligheter. For eksempel hvis vi skal lage en kjapp alderskategorisering. case_when() følger en struktur hvor du definerer betingelsen på venstre side av ~ og resultatet på høyre side. Bruken av tilde (~) indikerer at dette et et formel-objekt. Vi har ikke snakka noe særlig om formel-objekter hittil, og jeg tenker at vi ikke trenger å gå inn på det her heller. Men hvis du noen gang skal gjøre noe fancy med case_when() kan det være greit å vite at den bruker formler i koden sin.
# A tibble: 50 × 3
kjonn alder alders_gruppe
<chr> <dbl> <dbl>
1 M 30 3
2 K 65 5
3 M 39 3
4 K 72 5
5 M 76 5
6 K 13 1
7 M 47 4
8 K 72 5
9 M 49 4
10 K 42 4
# ℹ 40 more rows
Noen ting å merke seg med case_when():
Logikken arbeider seg nedover og for hver rad velger den ut den første betingelsen som stemmer.
Det er smart å ha en catch-all på slutten av case_when(). Du ser det i eksemplet mitt over, i form av det siste argumentet som er TRUE ~ NA_real_. Dersom ingen av betingelsene over stemmer, vil raden få verdien NA. Hvorfor skriver jeg NA_real_? case_when(), lik if_else() er streng med å holde seg til samme type verdier. Derfor lar den meg ikke uten videre bruke NA uten å definere om dette er en numerisk NA eller en streng-NA. Hadde jeg brukt strenger som gruppenavn istedenfor tall ville jeg i siste linje oppgitt NA_character_ istedenfor.
Dersom du arbeider på en case_when() som begynner å bli lang og komplisert er det ofte bedre å heller gjøre det om til en funksjon.
9.2 Transmute
Tvillingen til mutate() heter transmute(). De opererer likt, bortsett fra at transmute() kun beholder de variabelene som blir laga. Noen ganger er dette nyttig. Merk at det gjør disse to kodebrokkene lik
Også nært beslekta er summarise(). Vi har prata om summarise() tidligere (sec-oppsummering), og du vil lett se at disse likner på hverandre. summarise() bruker vi når vi vil lage en oversikt over enkelte deler av, eller hele, datasettet. Til forskjell fra mutate() summerer den opp alle radene på hver kolonne, eventuelt gruppert etter grupper om man kombinerer den med group_by().