Denne posten beskriver hvordan man kan hente ut informasjonen fra
en nestet liste i R der data er plassert på ulike nivåer. Først
beskrives det hvordan vi får en oversikt over innholdet i lista med
str(). Deretter brukes funksjonen hoist()
for å få ut
dataene i en data.frame
eller en tibble
. Dette
er ofte nyttig når vi har data fra et API eller en nettjeneste.
Data kommer ikke alltid i enkle tabeller. Ofte vil vi jobbe med data
fra nettet som ikke er tabeller, men heller nestede trær med
informasjon. Dette er for eksempel tilfellet om vi henter json-data fra
et web-API. Heldigvis finnes det nyttige funskjoner for å hente ut
informasjonen fra slike lister og gjøre dem om til mer nyttige tabeller
slik som en tibble
, data.frame
eller
data.table
. Andre ganger får vi flere tabeller i en liste,
for eksempel hvis vi har kjørt en loop som genererer mange tabeller.
Denne posten omhandler ikke slike situasjoner. Da vil vi ofte kunne
bruke for eksempel rbindlist()
fra
data.table
.
Denne posten ble egentlig inspirert av data fra json
,
men jeg lager en kunstig tabell her til dette eksemplet. Json kan fint
leses inn med pakka rjson
.
#Starter med pakker:
library("tidyverse")
library("knitr")
# kunstig liste med mange nivåer
partiliste <-
list(
list(
parti="SV",
partileder=list(etternavn="Lysbakken",
fornavn="Audun"),
valgresultat= list(
stortingsvalg=list(
valg_21=list(
prosent=7.6,
mandater=13),
valg_17=list(
prosent=6,
mandater=11)
)
)
),
list(
parti="Frp",
partileder=list(fornavn="Sylvi",
etternavn="Listhaug"),
valgresultat= list(
stortingsvalg=list(
valg_21=list(prosent=11.6,
mandater=21),
valg_17=list(prosent=15.2,
mandater=27)
)
)
)
)
Over har jeg laget en liste med mange nivåer.1 Som regel har vi ikke helt oversikten over hva som ligger i en liste. Hvis vi printer den i sin helhet får vi ofte en litt vanskelig tolkbar oversikt:
print(partiliste)
1]]
[[1]]$parti
[[1] "SV"
[
1]]$partileder
[[1]]$partileder$etternavn
[[1] "Lysbakken"
[
1]]$partileder$fornavn
[[1] "Audun"
[
1]]$valgresultat
[[1]]$valgresultat$stortingsvalg
[[1]]$valgresultat$stortingsvalg$valg_21
[[1]]$valgresultat$stortingsvalg$valg_21$prosent
[[1] 7.6
[
1]]$valgresultat$stortingsvalg$valg_21$mandater
[[1] 13
[
1]]$valgresultat$stortingsvalg$valg_17
[[1]]$valgresultat$stortingsvalg$valg_17$prosent
[[1] 6
[
1]]$valgresultat$stortingsvalg$valg_17$mandater
[[1] 11
[
2]]
[[2]]$parti
[[1] "Frp"
[
2]]$partileder
[[2]]$partileder$fornavn
[[1] "Sylvi"
[
2]]$partileder$etternavn
[[1] "Listhaug"
[
2]]$valgresultat
[[2]]$valgresultat$stortingsvalg
[[2]]$valgresultat$stortingsvalg$valg_21
[[2]]$valgresultat$stortingsvalg$valg_21$prosent
[[1] 11.6
[
2]]$valgresultat$stortingsvalg$valg_21$mandater
[[1] 21
[
2]]$valgresultat$stortingsvalg$valg_17
[[2]]$valgresultat$stortingsvalg$valg_17$prosent
[[1] 15.2
[
2]]$valgresultat$stortingsvalg$valg_17$mandater
[[1] 27 [
For å få en brukbar oversikt over innholdet i lista kan vi heller
bruke str()
. str()
gir oss en kompakt oversikt
over strukturen i et R-objekt.2 Vi kan spesifisere hvor
mange nivåer vi ønsker å printe med max.level
, men siden vi
er interessert i å se hele lista lar vi str()
printe alt,
noe som også er standard.
str(partiliste)
List of 2
$ :List of 3
..$ parti : chr "SV"
..$ partileder :List of 2
.. ..$ etternavn: chr "Lysbakken"
.. ..$ fornavn : chr "Audun"
..$ valgresultat:List of 1
.. ..$ stortingsvalg:List of 2
.. .. ..$ valg_21:List of 2
.. .. .. ..$ prosent : num 7.6
.. .. .. ..$ mandater: num 13
.. .. ..$ valg_17:List of 2
.. .. .. ..$ prosent : num 6
.. .. .. ..$ mandater: num 11
$ :List of 3
..$ parti : chr "Frp"
..$ partileder :List of 2
.. ..$ fornavn : chr "Sylvi"
.. ..$ etternavn: chr "Listhaug"
..$ valgresultat:List of 1
.. ..$ stortingsvalg:List of 2
.. .. ..$ valg_21:List of 2
.. .. .. ..$ prosent : num 11.6
.. .. .. ..$ mandater: num 21
.. .. ..$ valg_17:List of 2
.. .. .. ..$ prosent : num 15.2
.. .. .. ..$ mandater: num 27
Vi ser at informasjonen vi er interessert i er lagret på ulike steder
i lista. Liste består av to underlister, en for hvert parti. For hver av
disse listene finnes det en variabel for hvilket parti (kalt
parti
..), men også informasjon om partiledere3
fornavn og etternavn under partileder
og så
fornavn
eller etternavn
og det er en liste med
valgresultatet i to valg under valgresultat
,
stortingsvalg
, valg_21
eller
valg_17
og så til slutt prosent
eller
mandater
. Vi kunne selvfølgelig henta ut denne
informasjonen med ulike subsettinger. I vårt eksempel kunne både
subsetting med tall og med tekst vært mulig fordi vi har så liten liste.
Men listene vil ofte være mye lenger og større. Da vil en slik
framgangsmåte være lite hensiktsmessig.
partiliste[[1]]$valgresultat$stortingsvalg$valg_21$prosent
[1] 7.6
Tall-subsetting er også ganske kronglete og vanskelig å lese her:
partiliste[[2]][[3]][[1]][[1]][[1]]
[1] 11.6
hoist()
Som vanlig har noen andre hatt dette problemet før og funnet en god
måte å løse det på. Ikke overraskende er en av løsningene tilgjengelig i
tidyverse
og i pakka tidyr
. Funksjonen hoist()
lar oss hente enkeltelementer i lista og lage en tibble
med
informasjonen.
hoist()
fungerer bare med tibble som input. Vi lagrer lista i en
tibble
og sier at den skal hete datasett.
Når vi nå har en tibble kan vi bruke hoist()
til å hente ut data. Hadde vi bare vært interessert i data fra det
øverste nivået kan vi bare spesifisere hva dataene heter. Her finnes for
eksempel partinavnet på det øverste nivået.
parti_tibble %>%
# Vi har en tibble hoist() kan jobbe med:
hoist(
#Vi kalte tibblen datasett:
datasett,
#her følger alle enkeltelementene du ville ha:
#Når de er på det øverste nivået kan du bare skrive dem:
"parti") %>%
kable()
parti | datasett |
---|---|
SV | Lysbakken, Audun , 7.6 , 13 , 6 , 11 |
Frp | Sylvi , Listhaug, 11.6 , 21 , 15.2 , 27 |
For å få informasjon fra lavere nivåer må vi spesifisere hele grenen
Dette kan bli litt kronglete, men koden er i hvert fall veldig grei å
skrive. Vi bruker c()
til å spesifisere alle nivåene innover
til informasjonen vi er interessert i. Her er for eksempel partiledernes
navn lagt under partileder og så fornavn eller etternavn. Vi skriver
dermed at variabelen partileder_fornavn
skal være
c("partileder", "fornavn")
. Tilsvarende lager vi en lengre
remse for å hente ut valgresultatene.
parti_tabell<- parti_tibble %>%
# Vi har en tibble hoist() kan jobbe med:
hoist(
#Vi kalte tibblen datasett:
datasett,
#her følger alle enkeltelementene du ville ha:
#Når de er på det øverste nivået kan du bare skrive dem:
"parti",
# Når de er lenger ned kan du skrive de overordnede nivåene inne i en c() og så det du vil ha:
partileder_fornavn = c("partileder", "fornavn"),
partileder_etternavn = c("partileder", "etternavn"),
valgresultat_21 = c("valgresultat", "stortingsvalg",
"valg_21", "prosent"),
mandater_21 = c("valgresultat", "stortingsvalg",
"valg_21", "mandater"),
valgresultat_17 = c("valgresultat", "stortingsvalg",
"valg_17", "prosent"),
mandater_17 = c("valgresultat", "stortingsvalg",
"valg_17", "mandater")
)
Vi så i det første eksempelet over at hoist()
automatisk legger all den andre informasjonen i lista/tibblen til slutt
i tabellen. Dette er vi ikke interessert i. Dermed fjerner vi variabelen
datasett
(navnet vi spesifiserte da vi lagde den første
tibblen) fra tabellen. Vi bruker grep()
til å finne ut
hvilken kolonne som heter “datasett”.
Når vi har funnet hvilket nummer denne kolonnen er, kan vi subsette
part_tabell
slik at denne kolonna blir fjerna. Det gjør vi
ved å bruke minustegnet før tallet (her
-rest_kolonnenummer
). Da fjerner vi kolonne nummer 8 i
dette tilfelle. Dette skal spesifiseres etter kommaet siden det er en
kolonne og ikke en rad.
parti_tabell <- parti_tabell[,-rest_kolonnenummer]
kable(parti_tabell)
parti | partileder_fornavn | partileder_etternavn | valgresultat_21 | mandater_21 | valgresultat_17 | mandater_17 |
---|---|---|---|---|---|---|
SV | Audun | Lysbakken | 7.6 | 13 | 6.0 | 11 |
Frp | Sylvi | Listhaug | 11.6 | 21 | 15.2 | 27 |
Vi ser at dette er en tabell det går an å jobbe med.
Dataene er hentet fra valgresultat.no↩︎
Jeg blei lei av å lage liste ganske raskt, men her burde selvfølgelig også vært spesifisert at Siv Jensen var partileder i 2017-valget.↩︎
For attribution, please cite this work as
Solheim (2022, June 13). Solheim: Hvordan gjøre en liste til en tabell (data.frame) i R?. Retrieved from https://www.oyvindsolheim.com/code/Hente data fra lister/
BibTeX citation
@misc{solheim2022hvordan, author = {Solheim, Øyvind Bugge}, title = {Solheim: Hvordan gjøre en liste til en tabell (data.frame) i R?}, url = {https://www.oyvindsolheim.com/code/Hente data fra lister/}, year = {2022} }