Sesjon 2: Datatyper, objekter og funksjoner
R-workshop 30. og 31. august, OsloMet
Vi har tre hovedtyper av dataformater i R:
- vektorer
- datamatriser
- lister
Vektorer
Definer en vektor
Vi kan lage en vektor med kommandoen c()
(kortform for
“concatenate”).
c(1, 2, 3, 4)
## [1] 1 2 3 4
Hver observasjon separeres med komma. Vær nøye med å lukke parentesen. Det er slik R forstår at du er ferdig med å snakke, og at det er R sin tur til å svare. Om du markerer den ene delen av en parentes, vil RStudio vise deg hvor tvillingen befinner seg.
Engelske komma Desimalskilletegnet i R er punktum
.
.
c(1.2, 3.2, .0)
## [1] 1.2 3.2 0.0
Lagre vektoren vår i et objekt
<- c(3.75, 7.5, 7.25, 6, 2.25, 4, 1.5, 6.75)
hoyre hoyre
## [1] 3.75 7.50 7.25 6.00 2.25 4.00 1.50 6.75
Vektorer kan ha ulike målenivå: tall (“numeric”), bokstaver (“character”) og pre-definerte kategorier (“factor”).
Når vi lager en bokstavvektor, må vi “pakke inn” ordene i hermetegn
<-c("Ap", "FrP", "H", "KrF", "MDG", "Sp","SV", "V")
parti parti
## [1] "Ap" "FrP" "H" "KrF" "MDG" "Sp" "SV" "V"
Matematiske operasjoner
Vi kan gjøre matematiske operasjoner på vektorer også. Her øker jeg alle verdier med to.
hoyre
## [1] 3.75 7.50 7.25 6.00 2.25 4.00 1.50 6.75
+ 2 hoyre
## [1] 5.75 9.50 9.25 8.00 4.25 6.00 3.50 8.75
Skal du beholde hva du nettopp gjorde, må du ta vare på resultatet
<- hoyre + 2
hoyre_omk hoyre_omk
## [1] 5.75 9.50 9.25 8.00 4.25 6.00 3.50 8.75
R gir deg beskjed om målenivået er feil.
+ 2 parti
## Error in parti + 2 : non-numeric argument to binary operator
Indeksering
base-R
følger matematiske prinsipper. Dermed er
indekseringen symmetrisk med hva dere allerede kan. I
tidyverse
vil du bruke andre teknikker for å hente ut
observasjoner.
Tredje observasjon
parti
## [1] "Ap" "FrP" "H" "KrF" "MDG" "Sp" "SV" "V"
3] parti[
## [1] "H"
Jeg kan også be om å få se observasjonene 1 og 3. Da oppretter jeg i praksis en vektor med observasjonsnumrene inni hakeparentesen.
c(1,3)] parti[
## [1] "Ap" "H"
Andre og tredje
c(1,2)] parti[
## [1] "Ap" "FrP"
Andre til og med tredje
1:3] parti[
## [1] "Ap" "FrP" "H"
Funksjoner
Funksjoner er verbene i R-språket.
Hver funksjon har et navn og krever som et minimum at du oppgir hva du skal gjøre operasjonen på (objektet). Dette oppgir vi i parentes etter navnet (slik er syntaksen).
Generelt trenger du å oppgi:
- navnet på funksjonen
- et argument: obligatorisk informasjon i parantes; i det minste objektet og
- eventuelle tilleggsargumenter
Her summerer jeg på to forskjellige vis:
#på gamlemåten
2+2
## [1] 4
#med en funksjon på en vector
sum(c(2,2))
## [1] 4
Argument Hva er summen av alle tallene i vektoren min?
sum(x = hoyre)
## [1] 39
Implisitt argument Du kan av og til skippe navnet på argumentet
sum(hoyre)
## [1] 39
Tilleggsargument Eksempelvis, fjerne NA.
sum(hoyre, na.rm = TRUE)
## [1] 39
Funksjoner er grunnsteinen i R-språket sammen med objektene. De er i praksis pre-definerte operasjoner som du gjør på en viss type objekter; hvorav verb-analogien.
Hvor finner jeg funksjoner?
Du kan få enkle og generelle, eller spesifikke og/eller infløkte funksjoner.
base-R: har latterlig mange funksjoner. De kommer som legoklosser og er ofte enkle og generelle. Du kan alltid si hva du vil med base-R, men det kan kreve mange kodelinjer og tar av og til lang tid (særlig hvis du skriver løkker).
R-pakker distribusjon av funksjoner er kjerneoppgaven til “R-pakkene”. Dette er årsaken til at R er blitt et ledende programspråk. Kildekoden er åpen, slik at alle kan skrive funksjoner, “pakke dem inn” og dele dem. Når en ny metode blir introdusert til forskere/analytikere, vil mange benytte sjansen til å bygge sin forskningsmessige merkevare ved å skrive en egen R-pakke med de relevante funksjonene.
du selv Du kan fint skrive din R-funksjon og ta vare på den i et R-objekt. Jeg har flere slike. De befinner seg sammen med forskningsdataene mine i private R-pakker. Den jeg bruker mest, heter
silje
.
Repeter tall
rep(x = 1, times = 5)
## [1] 1 1 1 1 1
sekvens av tall
seq(from = 1, to = 5)
## [1] 1 2 3 4 5
Med tilleggsargument
seq(from = 1, to = 5, by = 0.5)
## [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
Utforsk med funksjoner
Lengde
length(hoyre)
## [1] 8
Målenivå
class(parti)
## [1] "character"
class(hoyre)
## [1] "numeric"
Din tur
Bruk indekseringen for å omkode variabelene.
- bruk
mean()
for å regne ut gjennomsnitlig høyreorientering for regjeringspartiene. - omkod Arbeiderpartiet til Kystpartiet.
- omkod MDG til 3.
- snu skalaretningen og regn ut ny gjennomsnitlig høyreorientering
Matriser
Vi kan ha alle slags objekter i R-området vårt, men datamatriser er fortsatt selve grunnsteinen i R. Siden datamatrisene også bare er et R-objekt, kan du ha mange datasett framme i arbeidsområdet samtidig.
Vi skal se på indeksering: * nyttig for omkoding + beskrivende statistikk * målenivå; også viktig når vi omkoder
Definer en matrise
Du vil oppleve at rutearkene dine kan klassifiseres på tre ulike vis:
- matrise (et ruteark med info; base R)
- datasett (dataframe; base R). R vet at kolonnene dine er variabler og lar deg gjøre analyser på den.
- datasett med penere printfunksjon (tibble; tidyverse).
Matriser er i praksis to eller flere vektorer som er limt sammen kolonnevis.
<- cbind(parti, hoyre) df
Hvordan ser objektet vårt ut?
df
## parti hoyre
## [1,] "Ap" "3.75"
## [2,] "FrP" "7.5"
## [3,] "H" "7.25"
## [4,] "KrF" "6"
## [5,] "MDG" "2.25"
## [6,] "Sp" "4"
## [7,] "SV" "1.5"
## [8,] "V" "6.75"
cbind()
(og tvillingen rbind()
) binder
vektorer sammen. Om vektorene ikke er like lange, vil R begynne å
“resirkulere”, men vil gi den en “advarsel”.
<- c(1,2,3)
annen cbind(df, annen)
## Warning in cbind(df, annen): number of rows of result is not a multiple of
## vector length (arg 2)
## parti hoyre annen
## [1,] "Ap" "3.75" "1"
## [2,] "FrP" "7.5" "2"
## [3,] "H" "7.25" "3"
## [4,] "KrF" "6" "1"
## [5,] "MDG" "2.25" "2"
## [6,] "Sp" "4" "3"
## [7,] "SV" "1.5" "1"
## [8,] "V" "6.75" "2"
Advarsler (“Warning”) er noe annet en “Error”. Begge kommer med rød skrift, men en feil betyr at operasjonen ikke ble gjennomført. En advarsel flagger mulige feil.
R skiller mellom matriser og datasett (data.frame). Dette er foreløpig en matrise.
class(df)
## [1] "matrix" "array"
Datasett Vi kan omdefinere matrisen til et datasett. Da får bl.a. hver variabel et definert målenivå, og indekseringen går enklere.
<- as.data.frame(df)
df class(df)
## [1] "data.frame"
df
Dimensjonen på datasettet
dim(df)
## [1] 8 2
Hvilke variabler har jeg?
names(df)
## [1] "parti" "hoyre"
Hva er første variabel?
names(df)[1]
## [1] "parti"
Se dataene Du kan åpne dataene i et eget vindu.
View(df)
Indeksere
Indeksering av data matriser følger vanlige matematisk notasjon:
matrise[rad,kolonne]
Jeg kan inspisere den første observasjonen i første kolonne.
1,1] df[
## [1] "Ap"
… første linje (observasjon)
1,] df[
Tre synonymer
…første kolonne (variabel)
1] df[,
… parti-variabelen med matriseindeksering (== første kolonne)
"parti"] df[,
## [1] "Ap" "FrP" "H" "KrF" "MDG" "Sp" "SV" "V"
… parti-variabelen med indeksering for datasett
$parti df
## [1] "Ap" "FrP" "H" "KrF" "MDG" "Sp" "SV" "V"
Vi må alltid oppgi navnet på datasettet (objektet) + dollartegn ($) + variabelnavn. Dette er prisen for å ha flere dataobjekter oppe samtidig.
Betinget omkoding
Det er også mulig å trekke fram én eller flere observasjoner basert på verdiene til en gitt variabelverdi.
Hvilke observasjoner skårer seks på høyreorientering?
$hoyre == 6 df
## [1] FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
Svaret er alltid like langt som dataene du putter inn.
Hvilket observasjonsnummer har de?
which(df$hoyre == 6)
## [1] 4
Hvilket parti skårer 6?
$hoyre==6, "parti"] df[df
## [1] "KrF"
#evt
which(df$hoyre == 6), "parti"] df[
## [1] "KrF"
Nå kan jeg se alle partier som skårer 6 eller høyere
$parti[df$hoyre >= 6] df
## [1] "FrP" "H" "KrF" "V"
… da er jeg ett skritt fra å omkode. Her lager jeg en binær variabel for høyreorientering.
$hoyre_bin = NA
df$hoyre_bin[df$hoyre >= 6] = 1
df$hoyre_bin[df$hoyre < 6] = 0 df
Hvor mange partier ble klassifisert som høyreorientert?
sum(df$hoyre_bin)
## [1] 4
Dette er mye skriving for å oppnå en omkoding. Det finnes andre måter å gjøre det på, men R er alltid basert på TRUE/FALSE gjetteleken.
Jeg kan også indeksere på bokstavverdier
$parti == "KrF", "hoyre"]
df[df$hoyre[df$parti == "KrF"] df
Ordne data Jeg kan ordne dataene fra lav til høy verdi
#Rangeringen til hvert parti
order(df$hoyre)
#Bruk denne i indekseringen
order(df$hoyre),] df[
Her sorterer jeg etter to variabler
order(df$parti, df$hoyre),] df[
Husk at denne sorteringen blir ikke lagret, med mindre vi oppretter et nytt dataobjekt.
<- df[order(df$parti, df$hoyre),]
nyedata nyedata
Målenivå
Målenivået til variabelen avgjør hvilke operasjoner du kan gjøre på den; som i det virkelige liv.
To regler:
- Sjekk alltid omkodingen før du overskriver den originale variabelen.
- Definer alltid en variabel som bokstaver før du omkoder dem til numre
Numeriske variabler (“Numeric”):
Når dataene ser ut som tall, vil R stort sett klassifisere dem som tall.
$hoyre df
## [1] "3.75" "7.5" "7.25" "6" "2.25" "4" "1.5" "6.75"
is.numeric(df$hoyre)
## [1] FALSE
as.numeric(df$hoyre)
## [1] 3.75 7.50 7.25 6.00 2.25 4.00 1.50 6.75
Om du forsøker å definere en bokstavvariabel til tall, vil hele vektoren forvandles til (“not available”).
Bokstavvariabler (“Character”):
Skrift kan defineres som skrift.
as.character(df$hoyre)
## [1] "3.75" "7.5" "7.25" "6" "2.25" "4" "1.5" "6.75"
Jeg har som absolutt regel at jeg alltid går via bokstavdefinisjonen når jeg skal omdefinere variabler fra ett målenivå til et annet. Årsaken henger sammen med R sin bruk av kategoriske variabler.
Kategoriske variabler - (“Factor”):
Faktorer/kategorier er en måte for R å spare plass på: Informasjon blir lagret som kategorier. Det betyr at teksten eller tallene som befant seg i ruta, vil bli lagret som en egen kategori, mens hver observasjon får et internt kategorinummer.
as.factor(df$parti)
## [1] Ap FrP H KrF MDG Sp SV V
## Levels: Ap FrP H KrF MDG Sp SV V
Vi kan omrokkere nivåene.
factor(df$parti,
levels=c("FrP", "H", "V", "KrF", "Sp", "Ap", "MDG", "SV"))
## [1] Ap FrP H KrF MDG Sp SV V
## Levels: FrP H V KrF Sp Ap MDG SV
Om vi vil opprette en ordinal variabel, må vi oppgi rekkefølgen fra lav til høy verdi.
ordered(df$parti,
levels=c("SV", "MDG", "Ap", "Sp", "KrF", "V", "H", "FrP"))
## [1] Ap FrP H KrF MDG Sp SV V
## Levels: SV < MDG < Ap < Sp < KrF < V < H < FrP
En felle
as.factor(df$hoyre)
## [1] 3.75 7.5 7.25 6 2.25 4 1.5 6.75
## Levels: 1.5 2.25 3.75 4 6 6.75 7.25 7.5
…er ikke det samme som…
as.numeric(as.factor(df$hoyre))
## [1] 3 8 7 5 2 4 1 6
Trikset er å gå via bokstavdefinisjonen
as.numeric(as.character(as.factor(df$hoyre)))
## [1] 3.75 7.50 7.25 6.00 2.25 4.00 1.50 6.75
Da blir tallverdiene i kategorinavnene lest, og ikke det interne registreringsnummeret.
Lister
Lister er objekter med ustrukturert format: I praksis objekter som er limt sammen.
- vi bruker dem ikke i stor grad
- R har mange av dem: f.eks modellobjektene våre.
De er svært nyttige når vi skal rapportere resultatene våre.
Opprette en liste
Vi kan starte med å opprette en liste.
<-list(hoyre=c("FrP", "H", "V"),
listesentrum=c("Sp", "KrF", "MDG"),
venstre=c("Ap", "SV"))
liste
## $hoyre
## [1] "FrP" "H" "V"
##
## $sentrum
## [1] "Sp" "KrF" "MDG"
##
## $venstre
## [1] "Ap" "SV"
Indekseringen er i prinsippet den samme som tidligere, men denne gangen kan flere objekttyper være limt sammen.
Indeksering
Hvert listeelement kan kalles opp ved navn ved hjelp av dollartegn eller med [[j]]. Internt i hvert element må vi bruke indekseringen som passer til elementets type.
Denne listen består av tre vektorer ved navn hoyre, sentrum og venstre.
1]] liste[[
## [1] "FrP" "H" "V"
$hoyre liste
## [1] "FrP" "H" "V"
Observasjonene er partier. Disse kan hentes fram ved hjelp av et annet sett med indekser.
1]][1] liste[[
## [1] "FrP"
$hoyre[1] liste
## [1] "FrP"
Det er til og med mulig å lime sammen en datamatrise med en vektor.
<-list(datamatrise = df,
nylisteorientering = c("hoyre", "sentrum", "venstre"))
nyliste
## $datamatrise
## parti hoyre hoyre_bin
## 1 Ap 3.75 0
## 2 FrP 7.5 1
## 3 H 7.25 1
## 4 KrF 6 1
## 5 MDG 2.25 0
## 6 Sp 4 0
## 7 SV 1.5 0
## 8 V 6.75 1
##
## $orientering
## [1] "hoyre" "sentrum" "venstre"
Lista mi har to objekter/forgreininger:
names(nyliste)
## [1] "datamatrise" "orientering"
Disse kan jeg gripe tak i på tre ulike vis
#take 1
$datamatrise nyliste
# take 2
1]] nyliste[[
# take 3
"datamatrise"]] nyliste[[
Jeg kan indeksere matrisen som henger på lista på vanlig vis.
$datamatrise[1,1] nyliste
## [1] "Ap"
$datamatrise[,1] nyliste
## [1] "Ap" "FrP" "H" "KrF" "MDG" "Sp" "SV" "V"