Sesjon 6: Beskrivende statistikk

R-workshop 30. og 31. august, OsloMet

Det første jeg gjør når jeg har et nytt datasett, er å utforske dataene med beskrivende statistikk. Da er hovedfokuset at R-kodingen skal gå fort og jeg skal få oversikt. Base-R har mange praktiske funksjoner for dette.

Når jeg skal presentere resultatene mine – også de beskrivende – bruker jeg mer tid og flere pakker; inkludert piper fra tidyverse.

Nå skal vi:

  • lage beskrivende statistikk: tall og figurer i base-R
  • ta vårt første dykk i dplyr (pakke i tidyverse)
  • lage fine tabeller

Pakker vi bruker:

  • dplyr (evt. tidyverse)
  • stargazer
  • kableExtra

Beskrivende statistikk

Vi begynner med å sjekke ut dataene.

View(df)
dim(df); names(df)

De første seks observasjonene.

head(df)

Univariate fordelinger

Funksjoner fra base-R er perfekte for kjapp utforskning av dataene, men ganske kjapt vil tidyverse gi stordriftsfordeler.

Kategoriske variabler

Frekvenstabell Absolutt fordeling

table(df$Parti)

Relativ fordeling

prop.table(table(df$Parti))

I prosent

prop.table(table(df$Parti)) * 100

Rund av til uten desimaler.

round(prop.table(table(df$Parti)) * 100)

Lagre resultatet

tabell1 <- prop.table(table(df$Parti)) * 100

Søylediagram

barplot(tabell1)

Din tur!

Bruk litt tid på å leke med denne.

  • legg en tittel og aksenavn på grafikken med: main=, xlab=, ylab=.
  • kan du sortere søylene fra lav til høy? Da sorterer du verdiene i tabellen med order + indeksering.
  • endre fargene på søylene med tilleggsargumentet col= Sjekk fargenavnene her: http://www.stat.columbia.edu/~tzheng/files/Rcolor.pdf
  • sjekk ut horiz = TRUE og las = 2. Hva kan du gjøre?

Kakediagram

pie(tabell1)

Kontinuerlige variabler

Numeriske beskrivelser

Når variablene er kontinuerlige, kan vi bruke kvartiler, gjennomsnitt…

Her ser jeg på respondentenes innvandrerskepsis.

summary(df$Skepsis)

stargazer gir deg et automatisk sammendrag av datasett med kontinuerlige variabler. Default utupt er i latex, så presiser at du vil ha “text”.

library(stargazer)
## 
## Please cite as:
##  Hlavac, Marek (2022). stargazer: Well-Formatted Regression and Summary Statistics Tables.
##  R package version 5.2.3. https://CRAN.R-project.org/package=stargazer
stargazer(df[,c("Skepsis", "KultSkepsis")],
          type = "text")

Grafisk utforskning

hist(df$Skepsis)

Bivariate sammenhenger

To kagetoriske variabler

table(df$Innvandrer, df$Prekaritet)

Lagre resultatet

krysstabell <- table(df[,c("Innvandrer", "Prekaritet")])

Legg til marginalfordelingen

addmargins(krysstabell)

Relativ fordeling Vil du ha andeler i stedet?

prop.table(krysstabell)

Regn ut fordelingen kolonnevis

prop.table(krysstabell, margin = 1)

Søylediagram Nå blir søylene lagt oppå hverandre.

barplot(krysstabell)

… ved siden av

barplot(krysstabell,
        beside = TRUE,
        names.arg = c("Prekaer", "Ikke-prekaer"))

Bytte sammenlikning? Da kan du transposere tabellen

krysstabell
t(krysstabell)
barplot(t(krysstabell),
        beside = TRUE)

### To kontinuerlige variabler

Numeriske beskrivelser

Pearsons R Bruk cor() for bivariate korrelasjoner. NA håndteres med å fortelle hvilke observasjoner vi ønsker å bruke.

cor(df$Skepsis,
    df$KultSkepsis,
    use = "pairwise.complete.obs")

Signifikansteste korrelasjonen

cor.test(df$Skepsis,
         df$KultSkepsis)

Korrelasjonsmatrise

cor(df[,c("Skepsis", "KultSkepsis", "Inntekt", "Utdanning")],
    use = "pairwise.complete.obs")

Grafisk framstilling

plot(df$Skepsis,
     df$KultSkepsis)

plot(df[,c("Skepsis", "KultSkepsis", "Inntekt", "Utdanning")])

Hva er tidyverse/dplyr?

Til nå har vi jobbet i base-R. Det er den eldste og mest stabile dialekten i R. Det er fullt mulig å gjøre de fleste operasjoner i base-R, men de siste årene har en ny dialekt oppstått basert på tidyverse. Tidy-universet består av et sett med R-pakker som alle følger omtrent samme språklige prinsipper. Denne dialekten har flere fordeler:

  • datarydding: Som navnet indikerer, er pakken spesielt godt egnet for å rydde i data. dplyr er en pakke som bygger på tidyverse. Den har gjort mye av datatilretteleggingen svært rask. R har tradisjonelt vært lite tilpasset til store datasett, hvor alle funksjoner som krever å gå gjennom lange variabler har vært svært trege. I tillegg gjør pakken det mulig å kommunisere med databaser (SQL).

  • intuitiv: I tillegg til et eget vokabular (et sett med funksjoner), bygger pakken også på en annen type syntaks. Mange opplever at denne syntaksen ligger nærmere slik vi tenker og bygger opp en argumentasjon. Dermed kan kodene virke mer intuitive.

Det er en fordel å ha grunnleggende kunnskaper i begge dialekter. Dermed kan du jobbe deg rundt ethvert problem.

Før du bruker funksjoner fra tidyverse, må du hente pakken (eller en av pakkene som baserer seg på denne) ut av biblioteket og inn i arbeidsminnet ditt. Funksjonene og syntaksen befinner seg i pakken.

Vi skal basere oss på dplyr-pakken som er en del av tidy-universet. Vi begynner med å hente opp pakken fra biblioteket. Om du ikke har installert den allerede, må du gjøre det først.

# install.packages("dplyr")
library(dplyr)

R følger opp med å informere oss om hvilke pakker som maskeres fra arbeidsområdet vårt. For eksempel inneholder dplyr funksjonen intersect() som har en navnebror i base-R. Om vi bruker funksjonsnavnet, er det dplyr sin funksjon vi nå vil få servert.

Eksempeldataene Her skal vi bruke en versjon av norske ESS (2014). Vi begynner med å laste in dataene og gi dem et navn vi liker.

library(laerdegR)
data(kap5)
df <- kap5

Syntaks: Piper eller parenteser?

I base-R: parentes

I base-R kommuniserer du ved først å oppgi funksjonen du ønsker å bruke, så objektnavnet i parentes, samt argumenter/tilleggsargument separert med komma.

Her regner jeg gjennomsnittet til variabelen om innvandrerskepsis blant ESS respondentene. Tilleggsargumentet na.rm = TRUE adresserer problemet med at noen respondenter ikke har svart.

mean(df$Skepsis, na.rm = T)

For å gjøre koden mer lesbar, vil vi ofte skifte linje etter hvert komma.

mean(df$Skepsis, 
     na.rm = T)

I tidyverse: piper

I tidyverse bruker vi “piper” for å binde ulike argumenter sammen. Det gjør vi med “%>%” (prosent, større-enn, prosent). Vi kan bruke funksjoner fra base-R eller fra tidyverse sammen med pipene.

Vi oppgir objektet først, så funksjonen. Alle argumenter som ikke oppgir objektet, må oppist på “gammelt vis”. Vi indikerer hvor objektet skulle ha vært med “.”.

df$Skepsis %>% mean(., na.rm = T)

Med piper, er det ekstra ryddig å skifte linje for lesbarhet.

df$Skepsis %>% 
  mean(., na.rm = T)

Flere operasjoner på samme objekt

Vi kan alltid bygge opp en sekvens koder. Dette skal foregå kronologist (første operasjon først). Vi kan gjøre det på tre måter:

  • én operasjon av gangen. Vi kan gjøre hver operasjon for seg og lagre dem i egne objekter.
er.na <- is.na(df$Skepsis)
ant.na <- sum(er.na)
ant.na

Vi har ant.na hull i variabelen.

  • to operasjoner av gangen
    • base-R: Vi kan legge parenteser i pareneteser. Den siste kommer først. Aller sist kommer objektet.
sum(is.na(df$Skepsis))
  • tidyverse: Vi kan lage en pipe: Objektet først, så første operasjon, så operasjonen vi vil gjøre på resultatet av denne operasjonen.
df$Skepsis %>%
  is.na(.) %>% 
  sum()

Det finnes ingen regler for hva som er best. Du bestemmer!

Frekvenstabell

Kontinuerlig variabel

Funksjonen summarize lar deg samle ulik statistikk for en eller flere variabler i datasettet. Du begynner med å presisere datasettet, så pipe, så summarize-funksjonen. Den vil da forstå at variablene/objektene du refererer til finnes i datasettet df.

df %>%
  summarize(gjennomsnitt = mean(Skepsis, na.rm = TRUE),
            median = median(Skepsis, na.rm = TRUE))

Du kan også lage kvantiler:

df %>% 
  summarize("skepsis" = quantile(Skepsis, na.rm = TRUE),
            "kulturell skepsis" = quantile(KultSkepsis, na.rm = TRUE)) %>% 
  t()

Her flipper jeg også tabellen (transposerer) med t().

Kategorisk variabel

Vi kan telle gruppemedlemmer med tidyverse. Da grupperer vi dataene etter en kategori med group_by(), så ber vi om et sammendrag summarize() og presiserer at vi ønsker antallet i hver gruppe n().

df %>%
  group_by(Parti) %>%
  summarize(n())

Vi kan bygge opp tabellen med flere sammendragstyper og runde av til to desimaler.

df %>%
  summarize(antall = table(Parti),
            andel = prop.table(antall),
            prosent = prop.table(antall)*100) %>%
  round(.,2) 

Lagre tabellen

frekvenstabell <- df %>%
  summarize(antall = table(Parti),
            andel = prop.table(antall),
            prosent = prop.table(antall)*100) %>%
  round(.,2) %>%
  #Skal du ha partinavnene, må du jobbe litt...
  cbind(parti = unique(df$Parti[!is.na(df$Parti)]),
        .)

Trivariat frekvenstabell

Bivariat tabell

df %>%
  group_by(Prekaritet) %>%
  summarize(skepsis = mean(Skepsis, na.rm = T),
            kulturell_skepsis = mean(KultSkepsis, na.rm = T))

Trivariat tabell

df %>%
  group_by(Innvandrer, Prekaritet) %>%
  summarize(skepsis = mean(Skepsis, na.rm = T),
            kulturell_skepsis = mean(KultSkepsis, na.rm = T))
## `summarise()` has grouped output by 'Innvandrer'. You can override using the
## `.groups` argument.
trivariat <- df %>%
  group_by(Innvandrer, Prekaritet) %>%
  summarize("Innvandrerskepsis" = mean(Skepsis, na.rm = T),
            "Kulturell innvandrerskepsis" = mean(KultSkepsis, na.rm = T))
## `summarise()` has grouped output by 'Innvandrer'. You can override using the
## `.groups` argument.

Eksporter tabellen din

Du kan eksportere tabellen på flere måter:

  • Excel: Dette er et datasett, så du kan eksportere med write.table() og importere i Excel, for eksempel.

  • LaTeX: Skriv tabellen ut med latex-kode ved hjelp av de samme tabellfunksjonene. Her er ofte stargazer-pakken fin (mer om det senere).

  • HTML/Word: Du kan bruke tabellfunksjoner i R for å printe tabellen som html. Da kan du “copy-paste” til Word. Her er knitr og kableExtra gode pakker (mer om disse senere også).

**Eksporter tabellen med html* Vi kan eksportere tabellen som html og importere den inn i word. I prosessen kan vi legge til ny informasjon.

kableExtra-pakkken (sammen med knitr) har fine funksjoner for dette. kbl() er kjernefunksjonen. Den krever en tabellel.

Jeg henter pakken inn fra biblioteket.

library(kableExtra)
?kbl

Her lager jeg en enkel tabell. Utputtet befinner seg i “Viwer” nederst til høyre.

kbl(x = trivariat)

Hvilke tilleggsargumenter finnes?

?kbl

Legg til tittel, for eksempel.

kbl(x = trivariat,
    caption = "Sammenhengen mellom økonomisk usikkerhet og innvandringsskepsis.")

Nå kan jeg eksportere tabellen. Det gjør jeg med en ny funksjon: save_kable(). Da må jeg presisere filnavnet.

kbl(x = trivariat,
    caption = "Sammenhengen mellom økonomisk usikkerhet og innvandringsskepsis.") %>%
  save_kable("tabell.html")

Utskriften befinner seg i mappen hvor arbeidsretningen din er satt. Husker du ikke hvor? La oss sjekke?

getwd() #Min arbeidsretning ("get working directory")

Jeg kan til og med spørre R om hvilke filer som befinner seg der.

list.files()

Er filen min i listen?

any(list.files() == "tabell.html")

Åpne fila i nettlesern din og kopier/lim den inn i Word. Voilá!

Din tur

  • Fortsett med tabellen hvor du kontrollerer for Innvandrer og Prekaritet, men hvor du også presiserer hvor mange observasjoner du har i hver kategori. Dette gjør du i summarize, med funksjonen n() (uten noen andre argumenter).

  • Lag en trivariat tabell hvor du kontrollerer for Inntekt istedet for innvandring.

    • blir den lang? Du kan bruke print(n = 20) i enden av kabelen din for å printe 20 observasjoner (osv.).
    • filtrer ut “NA” i prekaritet. Da bruker du filter(!is.na(Prekaritet)) i kabelen før du grupperer.
  • lag en html-tabell av resultatet med kbl() fra kableExtra.

  • pimp tabellen med info fra hjelpesidene:

    • digits =
    • align =

Mitt forsøk på trivariat tabell

Fungerer ikke funksjonen din som den skal?

Når du henter ut en pakke fra biblioteket, vil du av og til få beskjed om at enkelte funksjoner overskygger (eller er “maskert”) funksjoner som allerede befant seg i arbeidsområdet ditt. Årsaken er at du av og til vil oppleve konflikter mellom ulike pakker. Derfor er det lurt å være bevisst på hvilke pakker du bruker til enhver tid og hvor funksjonene dinne hører hjemme. Ikke last inn et drøss med pakker uten å vite hvilke funksjoner du skal bruke.

Eksempelvis, har enkelte pakker definert ulike funksjoner med likt navn. Ett eksempel er select() som både befinner seg i MASS-pakken og i dplyr-pakken. Om du ikke fikk med deg denne beskjeden da du hentet ut den nye pakken, og kodene dine ikke oppfører seg som de skal, bør du undersøke om dette er problemet. En måte å gjøre dette på er å bruke hjelpesidene. Finner du at den samme funksjonen befinner seg i to åpne pakker? Da har du to valg:

  • spesifiser hvor funksjonen din kommer fra. Du kan alltid fortelle R at du ønsker å bruke en spesifikk funksjon fra en spesifikk pakke. Da trenger du faktisk ikke å laste inn hele biblioteket. Dette gjør du med to kolon.

Her forteller jeg R at jeg ønsker å bruke select()-funksjonen fra dplyr.

dplyr:: select()
  • du kan fjerne den ene pakken. Dette kan du gjøre ved å klikke deg fram i RStudio eller med syntaks. Du kan enten klikke på fanen “Packages” i vinduet nederst til høyre. Her finner du en liste over alle pakkene i biblioteket ditt, med pakkene som er lastet inn i R huket av. Huk vekk pakken du ikke ønsker. Eventuelt kan du bruke detach( ).

Her laster jeg først inn dplyr, så fjerner jeg den igjen.

library(dplyr)
detach("package:dplyr", unload = TRUE)