rxlsxr-rio

How to import one excel file with several sheets into R with import_list


I use the rio-Package to import one excel-file into my tidyverse. I only need the first two columns: The zip-code (plz) and the inhabitants (einwohner).

library(tidyverse)
library(rio)

url <- "https://dam-api.bfs.admin.ch/hub/api/dam/assets/32229177/master"

bev22 <- import(url, setclass="tibble", skip=3, sheet="2022") %>%
select(plz=1, einwohner=2)

bev20 <- import(url, setclass="tibble", skip=3, sheet="2020") %>%
select(plz=1, einwohner=2)

And so on...works well, but gets tedious very quickly.

So I tried:

bev <- import_list(url, setclass="tibble", skip=3, rbind=T) %>%
select(plz=1, einwohner=2, sheet="_file")

That works, it seems like all the sheets are imported (although without the name of the year), but everything except the first sheet is full of NAs:

bev %>%
drop_na() %>%
count(sheet)

As far as I can tell, all the sheets have the same structure. What am I doing wrong?


Solution

  • The issue is that you skip the first three rows. As a result the values in the row for Switzerland become the column names, i.e. the first column is named Schweiz for all sheets but the second and and all other columns are named according to the values for Switzerland, i.e. the column names differ and hence the values are put in different columns when binding by row. As a result, after binding by rows the second column contains only the values for the first sheet.

    Here is an illustration of the issue where I only selected the first two columns and rows per sheet:

    library(tidyverse)
    library(rio)
    
    url <- "https://dam-api.bfs.admin.ch/hub/api/dam/assets/32229177/master"
    
    file <- tempfile(fileext = ".xlsx")
    
    download.file(url, destfile = file)
    
    import_list(file, skip = 3) |>
      lapply(\(x) select(x, 1:2) |> head(2)) |> 
      bind_rows()
    
    #>    Schweiz 8962258 8815385 8738791 8670300 8606033 8544527 8484130 8419550
    #> 1     1000    4332      NA      NA      NA      NA      NA      NA      NA
    #> 2     1003    6762      NA      NA      NA      NA      NA      NA      NA
    #> 3     1000      NA    4072      NA      NA      NA      NA      NA      NA
    #> 4     1003      NA    6707      NA      NA      NA      NA      NA      NA
    #> 5     1000      NA      NA    4101      NA      NA      NA      NA      NA
    #> 6     1003      NA      NA    6679      NA      NA      NA      NA      NA
    #> 7     1000      NA      NA      NA    3991      NA      NA      NA      NA
    #> 8     1003      NA      NA      NA    6528      NA      NA      NA      NA
    #> 9     1000      NA      NA      NA      NA    3579      NA      NA      NA
    #> 10    1003      NA      NA      NA      NA    6539      NA      NA      NA
    #> 11    1000      NA      NA      NA      NA      NA    3434      NA      NA
    #> 12    1003      NA      NA      NA      NA      NA    7515      NA      NA
    #> 13    1000      NA      NA      NA      NA      NA      NA    3448      NA
    #> 14    1003      NA      NA      NA      NA      NA      NA    7826      NA
    #> 15    1000      NA      NA      NA      NA      NA      NA      NA    3329
    #> 16    1003      NA      NA      NA      NA      NA      NA      NA   10479
    #> 17    1000      NA      NA      NA      NA      NA      NA      NA      NA
    #> 18    1003      NA      NA      NA      NA      NA      NA      NA      NA
    #> 19    1000      NA      NA      NA      NA      NA      NA      NA      NA
    #> 20    1003      NA      NA      NA      NA      NA      NA      NA      NA
    #> 21    1000      NA      NA      NA      NA      NA      NA      NA      NA
    #> 22    1003      NA      NA      NA      NA      NA      NA      NA      NA
    #> 23    1000      NA      NA      NA      NA      NA      NA      NA      NA
    #> 24    1003      NA      NA      NA      NA      NA      NA      NA      NA
    #> 25    1000      NA      NA      NA      NA      NA      NA      NA      NA
    #> 26    1003      NA      NA      NA      NA      NA      NA      NA      NA
    #> 27    1000      NA      NA      NA      NA      NA      NA      NA      NA
    #> 28    1003      NA      NA      NA      NA      NA      NA      NA      NA
    #>    8327126 8237666 8139631 8039060 7954662 7870134
    #> 1       NA      NA      NA      NA      NA      NA
    #> 2       NA      NA      NA      NA      NA      NA
    #> 3       NA      NA      NA      NA      NA      NA
    #> 4       NA      NA      NA      NA      NA      NA
    #> 5       NA      NA      NA      NA      NA      NA
    #> 6       NA      NA      NA      NA      NA      NA
    #> 7       NA      NA      NA      NA      NA      NA
    #> 8       NA      NA      NA      NA      NA      NA
    #> 9       NA      NA      NA      NA      NA      NA
    #> 10      NA      NA      NA      NA      NA      NA
    #> 11      NA      NA      NA      NA      NA      NA
    #> 12      NA      NA      NA      NA      NA      NA
    #> 13      NA      NA      NA      NA      NA      NA
    #> 14      NA      NA      NA      NA      NA      NA
    #> 15      NA      NA      NA      NA      NA      NA
    #> 16      NA      NA      NA      NA      NA      NA
    #> 17    3072      NA      NA      NA      NA      NA
    #> 18    9326      NA      NA      NA      NA      NA
    #> 19      NA    2964      NA      NA      NA      NA
    #> 20      NA    8269      NA      NA      NA      NA
    #> 21      NA      NA    3041      NA      NA      NA
    #> 22      NA      NA    8615      NA      NA      NA
    #> 23      NA      NA      NA    2886      NA      NA
    #> 24      NA      NA      NA    6974      NA      NA
    #> 25      NA      NA      NA      NA    2832      NA
    #> 26      NA      NA      NA      NA    6256      NA
    #> 27      NA      NA      NA      NA      NA    2995
    #> 28      NA      NA      NA      NA      NA    5685
    

    Instead I would suggest to skip only the first two rows and get rid of the entry for Switzerland after binding by row. Additionally you can make your life a bit easier using dplyr::bind_rows which allows to add a year column automatically.

    bev <- import_list(file, skip = 2) |>
      dplyr::bind_rows(.id = "year") |>
      select(year, plz = 2, einwohner = 3) |>
      filter(!is.na(einwohner), plz != "Schweiz")
    
    count(bev, year, !is.na(einwohner))
    #>    year !is.na(einwohner)    n
    #> 1  2010              TRUE 3186
    #> 2  2011              TRUE 3190
    #> 3  2012              TRUE 3190
    #> 4  2013              TRUE 3189
    #> 5  2014              TRUE 3189
    #> 6  2015              TRUE 3185
    #> 7  2016              TRUE 3183
    #> 8  2017              TRUE 3184
    #> 9  2018              TRUE 3182
    #> 10 2019              TRUE 3182
    #> 11 2020              TRUE 3182
    #> 12 2021              TRUE 3183
    #> 13 2022              TRUE 3180
    #> 14 2023              TRUE 3180