Har vi haft underdödlighet under juli 2020?

2020-08-28

I en artikel i SvD för några veckor påståds det att vi efter Corona-pandemins värsta dagar nu har en underdödlighet i Sverige. Det här kan enligt artikelförfattaren ses som en effekt av att många personer i riskgrupper gått bort under våren.

Jag fick en fråga av min kompis Benjamin som undrade om det här stämmer, givet data från SCB, och om det finns ett sätt för oss att slå fast huruvida vi haft en underdödlighet eller om det egentligen sett likadant ut.

Det här liknar i mångt och mycket ett klassiskt hypotestest, där vi har en nollhypotes \(H0\) att ingenting har hänt och \(H1\) att nollhypotesen förkastas, d.v.s. vi har haft en under eller överdödlighet.

För att besvara den här frågan har vi en Excel-fil med antal rapporterade dödsfall som SCB fått in under ett antal år. Vi börjar med att läsa in den.

library(tidyverse)
library(readxl)

data <- read_excel("scb-doda.xlsx", sheet = "Tabell 1", range = "A7:G373")

data
## # A tibble: 366 x 7
##    DagMånad   `2015` `2016` `2017` `2018` `2019` `2020`
##    <chr>       <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
##  1 1 januari     295    245    339    275    300    254
##  2 2 januari     272    272    317    312    276    300
##  3 3 januari     281    293    310    295    271    256
##  4 4 januari     256    260    305    285    282    272
##  5 5 januari     268    260    304    291    275    265
##  6 6 januari     256    246    304    268    281    285
##  7 7 januari     309    270    313    272    280    246
##  8 8 januari     294    292    296    260    274    292
##  9 9 januari     272    276    288    274    239    277
## 10 10 januari    285    256    304    287    254    253
## # … with 356 more rows

För att kunna arbeta med den här datan behöver vi samla alla observationer i en kolumn och skapa en datumkolumn.

library(lubridate)
library(tsibble)
tidy_data <- data %>% 
  pivot_longer(cols = `2015`:`2020`, names_to = "år", values_to = "antal_döda") %>% 
  mutate(datum = paste0(år,
                         str_extract(DagMånad, "[:alpha:]+"),
                         str_extract(DagMånad, "[:digit:]+")) %>% 
           as.Date(format = "%Y%B%d")) %>% 
  mutate(dag = day(datum), månad = month(datum)) %>% 
  select(datum, antal_döda) %>% 
  filter(datum < "2020-08-18") %>% 
  na.omit() %>% 
  as_tsibble(index = datum)

tidy_data
## # A tsibble: 2,056 x 2 [1D]
##    datum      antal_döda
##    <date>          <dbl>
##  1 2015-01-01        295
##  2 2015-01-02        272
##  3 2015-01-03        281
##  4 2015-01-04        256
##  5 2015-01-05        268
##  6 2015-01-06        256
##  7 2015-01-07        309
##  8 2015-01-08        294
##  9 2015-01-09        272
## 10 2015-01-10        285
## # … with 2,046 more rows

Vi kan nu visualisera det här över tid:

p <- tidy_data %>% 
  ggplot(aes(x = datum, y = antal_döda)) +
  geom_line() +
  theme_minimal() +
  labs(title = "Antal rapporterade dödsfall över tid",
       caption = "Källa: SCB")

plotly::ggplotly(p)

För jämförelsens skull kan vi visualisera varje år som en separat linje.

library(feasts)
library(gghighlight)

tidy_data %>% 
  filter(datum < "2020-08-17") %>% 
  as_tsibble() %>% 
  gg_season() +
  theme_minimal() +
  labs(title = "Antal rapporterade dödsfall över tid",
       caption = "Källa: SCB") +
  gghighlight(max(antal_döda) > 350, label_key = år)

Vi kan undersöka distributionen under dessa perioder.

tidy_data %>% 
  filter(month(datum) %in% c(07)) %>% 
  mutater = as.factor(year(datum))) %>% 
  ggplot(aes(antal_döda, color = år)) +
  geom_density() +
  labs(
    title = "Fördelning antal döda under juli"
  ) +
  theme_minimal()

Vi kan testa att göra en STL dekomposition.

tidy_data %>% 
  model(STL()) %>% 
  components() %>% 
  autoplot()

Hur exakt man ska testa hypotesen för det här inte självklart. En väg framåt skulle vara någon form av bootstrapping. Men det är ett projekt i sig att sätta upp en sån struktur och kräver nog ganska gedigen kunskap i att analysera tidsserier.

Ett enkelt alternativ är att använda en linjär modell endast på juli. Men det är en väldigt enkel modell, kanske man skulle behöva dubbelkolla och tänka vidare på.

linjär_modell <- tidy_data %>% 
  mutater = if_else(datum >= "2020-01-01", "2020", "2015-2019")) %>% 
  filter(month(datum) == 7) %>% 
  lm(antal_döda ~ år, data = .)

summary(linjär_modell)
## 
## Call:
## lm(formula = antal_döda ~ år, data = .)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -45.032 -12.032  -0.903  10.968  49.968 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  225.032      1.393 161.536   <2e-16 ***
## år2020        -5.129      3.412  -1.503    0.135    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 17.34 on 184 degrees of freedom
## Multiple R-squared:  0.01213,    Adjusted R-squared:  0.006761 
## F-statistic: 2.259 on 1 and 184 DF,  p-value: 0.1345

Vi har ett stort P-värde och även om estimatet är negativt, d.v.s. dödligheten är lägre under 2020, så är inte skillnaden signifikant.

Inspektera residualerna.

augment(linjär_modell) %>% 
  ggplot(aes(.resid)) +
  geom_density()