<- covid_case_death_rates x
5 Correlate signals over space and time
The epiprocess
package provides some simple functionality for computing lagged correlations between two signals, over space or time (or other variables), via epi_cor()
. This function is really just a convenience wrapper over some basic commands: it first performs specified time shifts, then computes correlations, grouped in a specified way. In this vignette, we’ll examine correlations between state-level COVID-19 case and death rates, smoothed using 7-day trailing averages.
5.1 Correlations grouped by time
The epi_cor()
function operates on an epi_df
object, and it requires further specification of the variables to correlate, in its next two arguments (var1
and var2
).
In general, we can specify any grouping variable (or combination of variables) for the correlation computations in a call to epi_cor()
, via the cor_by
argument. This potentially leads to many ways to compute correlations. There are always at least two ways to compute correlations in an epi_df
: grouping by time value, and by geo value. The former is obtained via cor_by = time_value
.
<- epi_cor(x, case_rate, death_rate, cor_by = "time_value") z1
Code
ggplot(z1, aes(x = time_value, y = cor)) +
geom_hline(yintercept = 0) +
geom_line(color = 4) +
scale_x_date(minor_breaks = "month", date_labels = "%b %Y") +
labs(x = "Date", y = "Correlation")
The above plot addresses the question: “on any given day, are case and death rates linearly associated, across the U.S. states?”. We might be interested in broadening this question, instead asking: “on any given day, do higher case rates tend to associate with higher death rates?”, removing the dependence on a linear relationship. The latter can be addressed using Spearman correlation, accomplished by setting method = "spearman"
in the call to epi_cor()
. Spearman correlation is highly robust and invariant to monotone transformations.
5.2 Lagged correlations
We might also be interested in how case rates associate with death rates in the future. Using the dt1
parameter in epi_cor()
, we can lag case rates back any number of days we want, before calculating correlations. Below, we set dt1 = -10
. This means that var1 = case_rate
will be lagged by 10 days, so that case rates on June 1st will be correlated with death rates on June 11th. (It might also help to think of it this way: death rates on a certain day will be correlated with case rates at an offset of -10 days.)
<- epi_cor(x, case_rate, death_rate, cor_by = time_value, dt1 = -10) z2
Code
<- rbind(
z %>% mutate(lag = 0),
z1 %>% mutate(lag = 10)
z2 %>%
) mutate(lag = as.factor(lag))
ggplot(z, aes(x = time_value, y = cor)) +
geom_hline(yintercept = 0) +
geom_line(aes(color = lag)) +
scale_color_brewer(palette = "Set1") +
scale_x_date(minor_breaks = "month", date_labels = "%b %Y") +
labs(x = "Date", y = "Correlation", col = "Lag")
Note that epi_cor()
takes an argument shift_by
that determines the grouping to use for the time shifts. The default is geo_value
, which makes sense in our problem at hand (but in another setting, we may want to group by geo value and another variable—say, age—before time shifting).
We can see that, generally, lagging the case rates back by 10 days improves the correlations, confirming case rates are better correlated with death rates 10 days from now.
5.3 Correlations grouped by state
The second option we have is to group by geo value, obtained by setting cor_by = geo_value
. We’ll again look at correlations for both 0- and 10-day lagged case rates.
<- epi_cor(x, case_rate, death_rate, cor_by = geo_value)
z1 <- epi_cor(x, case_rate, death_rate, cor_by = geo_value, dt1 = -10) z2
Code
<- rbind(
z %>% mutate(lag = 0),
z1 %>% mutate(lag = 10)
z2 %>%
) mutate(lag = as.factor(lag))
ggplot(z, aes(cor)) +
geom_density(aes(fill = lag, col = lag), alpha = 0.5, bounds = c(-1, 1)) +
scale_fill_brewer(palette = "Set1") +
scale_color_brewer(palette = "Set1") +
labs(x = "Correlation", y = "Density", fill = "Lag", col = "Lag")
We can again see that, generally speaking, lagging the case rates back by 10 days improves the correlations.
5.4 More systematic lag analysis
Next we perform a more systematic investigation of the correlations over a broad range of lag values.
<- 0:35
lags
<- map(
z .x = lags,
~ epi_cor(x, case_rate, death_rate, cor_by = geo_value, dt1 = -.x) %>%
mutate(lag = .x)
%>% list_rbind() )
Code
%>%
z group_by(lag) %>%
summarize(mean = mean(cor, na.rm = TRUE)) %>%
ggplot(aes(x = lag, y = mean)) +
geom_line(color = 4) +
geom_point(color = 4) +
labs(x = "Lag", y = "Mean correlation")
We can see pronounced curvature in the average correlation between case and death rates (where the correlations come from grouping by geo_value
) as a function of lag. The maximum occurs at a lag of somewhere around 17 days.