COVID vaccination effectiveness
library(tidyverse)
library(dplyr)
library(magrittr)
library(lubridate)
library(kableExtra)
library(ggplot2)
library(RColorBrewer)
Objective
Is Astra-Zeneca doses administered (at least a single dose) - as a proportion of all COVID vaccination administered - related to a national reduction in COVID-19 cases and death?
Data
# from "Our World in Data"
= read_csv(
owid "https://covid.ourworldindata.org/data/owid-covid-data.csv",
col_names=TRUE,
col_types="ccc?nnnnnnnnnnnnnnnnnnnnnnnnnnnnncnnnnnnnnnnnnnnnnnnnnnnnnn",
skip_empty_rows = FALSE
)
# European Center for Disease Prevention and Control, Week 19 of 2021
# used to derive use of different vaccine brands in Hungary
<- read_csv("~/Rprojects/coHealthKensington/Hungary_COVIDvax_dataset_2021-W19.csv")
hungary_vax <- read_csv("~/Rprojects/coHealthKensington/Germany_COVIDvax_dataset_2021-W19.csv") germany_vax
Country selection
Selection criteria:
- high rate of overall coverage (35% as of May 2021), including vaccines which are not Astra-Zeneca
- the availability of COVID case and death data at least two (preferably three) weeks after 35% single-dose COVID vaccination coverage achieved
- high rates of COVID-19 cases/mortality in a December 2020 to January 2021 peak
- At least 50 deaths daily (seven day rolling average)
%>%
owid select(location, date, people_vaccinated_per_hundred) %>%
filter(people_vaccinated_per_hundred >= 35, date <= (Sys.Date() - weeks(2))) %>%
# at least 35% vaccination, at least 2 weeks before today
group_by(location) %>% #
arrange(people_vaccinated_per_hundred) %>%
slice(1) %>% # the earliest date of reaching 35%
ungroup() %>%
inner_join(
%>%
owid select(location, date, new_deaths_smoothed) %>%
filter(date >= as.Date("2020-12-01") & date <= as.Date("2021-01-31")) %>%
filter(new_deaths_smoothed >= 50) %>%
group_by(location) %>%
arrange(desc(new_deaths_smoothed)) %>%
slice(1) %>% # choose the maximum death rate from Dec 20 to Jan 21
ungroup() %>%
select(location, new_deaths_smoothed)
%>%
) select(location, date, new_deaths_smoothed) %>%
kbl(
caption = "Countries with greater than 35% vaccine coverage as of May 2021 and significant mortality in Dec 20/Jan 21",
col.names = c("Country", "Date of 35% coverage", "Peak deaths Dec 20/Jan 21"),
digits = 1
%>%
) kable_styling()
Country | Date of 35% coverage | Peak deaths Dec 20/Jan 21 |
---|---|---|
Canada | 2021-05-05 | 152.9 |
Chile | 2021-03-31 | 74.1 |
Germany | 2021-05-12 | 894.4 |
Hungary | 2021-04-21 | 176.4 |
Israel | 2021-01-30 | 64.9 |
United Kingdom | 2021-03-13 | 1253.0 |
United States | 2021-04-10 | 3432.6 |
Canada, Chile and Hungary experienced additional ‘peaks’ after January 2021.
Canada achieved 35% single-dose coverage on 5th May 2021. Germany achieved 35% single-dose coverage on 12th May 2021. (As of 25th May 2021, it is not quite yet three weeks since either of those two dates)
Daily number of cases (seven day rolling average), daily number of deaths (seven day rolling average) and proportion of population vaccinated derived from Our World in Data.
Timepoints
- Day of maximum cases in December 2020 to January 2021
- Day of maximum deaths in December 2020 to January 2021
- Day of 35% single-dose COVID vaccination coverage (any COVID-19 vaccine)
- At least two, preferably three, weeks after the day of 35% single-dose COVID vaccination coverage
- vaccines are considered effective one to two weeks after delivery of dose
- COVID deaths tend to lag case-finding by one to two weeks
<- owid %>%
countries select(location, date, new_cases_smoothed, new_deaths_smoothed, people_vaccinated_per_hundred) %>%
filter(
== "Canada" | location == "Israel" |
location == "United States" | location == "United Kingdom" |
location == "Hungary" | location == "Germany" | location == "Chile")
location
# Iceland only had approximately 10 cases per month in Dec-January 2021
# (and even less cases at the time of 35% vaccination)
# Finland had less than 10 deaths per months in Dec-January 2021
# Cyprus reached 35% vaccination 14th May 2021, and had
# less than 10 deaths per day in Dec-January 2021
# Unable to find data on Uruguay vaccine brand numbers,
# though in Uruguay peak deaths in Dec-Jan 2021 was also approximately 10/day
<- countries[FALSE,] # 'empty' version of countries data
cases
for (i in unique(countries$location)) {
<- countries %>% filter(location == i)
country
# days of max cases and deaths in December/January 2021
<- country %>%
max_cases filter(date >= ymd("2020-12-01") & date <= ymd("2021-01-31")) %>%
slice_max(new_cases_smoothed)
<- country %>%
max_deaths filter(date >= ymd("2020-12-01") & date <= ymd("2021-01-31")) %>%
slice_max(new_deaths_smoothed)
# day of 35% single-dose vaccination coverage, and three weeks after that
<- country %>%
vax_35_date filter(people_vaccinated_per_hundred >= 35 & people_vaccinated_per_hundred < 40) %>%
slice_min(people_vaccinated_per_hundred)
<- country %>%
post35_3week filter(date == nth(date, which.min(abs(date - (vax_35_date$date + weeks(3))))))
<- cases %>%
cases add_row(as.data.frame(max_cases)) %>%
add_row(as.data.frame(max_deaths)) %>%
add_row(as.data.frame(vax_35_date)) %>%
add_row(as.data.frame(post35_3week))
}
<- cases %>%
cases rename(
country = location,
cases = new_cases_smoothed,
# 7-day rolling average
deaths = new_deaths_smoothed,
# 7-day rolling average
vaccinated = people_vaccinated_per_hundred
# Total number of people who received at least one vaccine dose per 100 people in the total population
)
%>%
cases arrange(country, date) %>%
group_by(country, date) %>%
slice(1) %>% # remove duplicates
ungroup() %>%
kbl(
caption = "December/January peak cases/deaths (7-day smoothed) and 3-weeks after 35% single-dose coverage",
col.names = c("Country", "Date", "Daily cases", "Daily deaths", "Vaccinated (at least one dose) per hundred"),
digits = 1
%>%
) kable_styling()
Country | Date | Daily cases | Daily deaths | Vaccinated (at least one dose) per hundred |
---|---|---|---|---|
Canada | 2021-01-09 | 9626.9 | 152.9 | 0.8 |
Canada | 2021-05-05 | 7904.4 | 46.7 | 35.5 |
Canada | 2021-05-25 | 3694.0 | 38.6 | 52.8 |
Chile | 2021-01-25 | 4204.0 | 64.6 | 0.3 |
Chile | 2021-01-31 | 3999.9 | 74.1 | 0.3 |
Chile | 2021-03-31 | 6822.1 | 104.7 | 35.6 |
Chile | 2021-04-21 | 6733.7 | 115.0 | 41.0 |
Germany | 2020-12-23 | 25757.0 | 662.3 | NA |
Germany | 2021-01-13 | 21809.1 | 894.4 | 1.1 |
Germany | 2021-05-12 | 11391.3 | 187.1 | 35.4 |
Germany | 2021-05-25 | 6667.4 | 151.7 | 40.7 |
Hungary | 2020-12-03 | 5685.3 | 156.4 | NA |
Hungary | 2020-12-23 | 2813.6 | 176.4 | NA |
Hungary | 2021-04-21 | 3669.3 | 217.4 | 35.4 |
Hungary | 2021-05-12 | 1116.7 | 102.1 | 45.8 |
Israel | 2021-01-17 | 8624.3 | 47.7 | 25.5 |
Israel | 2021-01-25 | 6117.1 | 64.9 | 31.5 |
Israel | 2021-01-30 | 6404.0 | 56.7 | 35.0 |
Israel | 2021-02-20 | 3238.1 | 25.0 | 49.4 |
United Kingdom | 2021-01-09 | 59828.6 | 902.6 | NA |
United Kingdom | 2021-01-23 | 37239.4 | 1253.0 | 9.4 |
United Kingdom | 2021-03-13 | 5872.7 | 149.6 | 35.6 |
United Kingdom | 2021-04-03 | 4046.7 | 36.4 | 46.4 |
United States | 2021-01-08 | 251056.9 | 3112.4 | 2.0 |
United States | 2021-01-13 | 245674.9 | 3432.6 | NA |
United States | 2021-01-14 | 239591.6 | 3432.6 | 2.9 |
United States | 2021-04-10 | 68192.0 | 985.1 | 35.0 |
United States | 2021-05-01 | 49594.4 | 675.6 | 43.7 |
Reduction in cases and deaths after 35% of single-dose coverage achieved
Calculate ratio of reduction in cases and deaths (seven day rolling average) three weeks after single-dose coverage is achieved.
<- data.frame(
effectiveness country = character(),
max_cases = numeric(),
max_deaths = numeric(),
post35_3wk = ymd(),
post35_3wk_cases = numeric(),
post35_3wk_deaths = numeric(),
astrazeneca_proportion = numeric()
)
for (i in unique(cases$country)) {
<- cases %>% filter(country == i)
country_cases <- country_cases %>%
peak_cases filter(date >= ymd("2020-12-01") & date <= ymd("2021-01-31")) %>%
filter(cases == max(cases)) %>%
pull(cases)
<- country_cases %>%
peak_deaths filter(date >= ymd("2020-12-01") & date <= ymd("2021-01-31")) %>%
filter(deaths == max(deaths)) %>%
pull(deaths)
<- country_cases %>%
vax_35_date filter(vaccinated >= 35 & vaccinated < 36) %>%
pull(date) # date of vaccinations between 0.35 and 0.36
<- country_cases[which.min(abs((vax_35_date + weeks(3)) - country_cases$date)),]
post35_3week # closest date to 3 weeks post vax_35_date
<- effectiveness %>%
effectiveness add_row(
country = i,
max_cases = peak_cases,
max_deaths = peak_deaths,
post35_3wk = post35_3week$date,
post35_3wk_cases = post35_3week$cases,
post35_3wk_deaths = post35_3week$deaths
)
}
<- effectiveness %>%
effectiveness mutate(
case_reduction_ratio = max_cases/post35_3wk_cases,
death_reduction_ratio = max_deaths/post35_3wk_deaths
%>%
) mutate(
log_case_reduction = log(case_reduction_ratio),
log_death_reduction = log(death_reduction_ratio)
)
%>%
effectiveness select(country, case_reduction_ratio, death_reduction_ratio) %>%
kbl(
caption = "Reduction in COVID-19 cases and deaths after 35% single-dose vaccination coverage",
col.names = c("Country", "Case reduction ratio", "Death reduction ratio"),
digits = 2
%>%
) kable_styling()
Country | Case reduction ratio | Death reduction ratio |
---|---|---|
Canada | 2.61 | 3.96 |
Canada | 2.61 | 3.96 |
Chile | 0.62 | 0.64 |
Germany | 3.86 | 5.90 |
Hungary | 5.09 | 1.73 |
Israel | 2.66 | 2.59 |
United Kingdom | 14.78 | 34.40 |
United States | 5.06 | 5.08 |
United States | 5.06 | 5.08 |
Astra-Zeneca usage
Neither Israel or United States used Astra-Zeneca vaccines at all.
Chile received its first shipment of Astra-Zeneca vaccines on April 23, several weeks after Chile first achieved 35% coverage (March 30, 2021). Until April, Chile used CoronaVac and Pfizer COVID vaccinations.
Hungary and German vaccination brand delivery available via the European Centre for Disease and Control.
Vaccines codes (ECDC):
- COM - Pfizer/Comirnaty
- BECNBG - CNBG/Sinopharm
- SPU - Sputnik V
- AZ - Astra-Zeneca
- MOD - Moderna
- JANSS - Janssen
Hungary reached 35% single-dose vaccine coverage on 21st April 2021 (week 16 of 2021).
Germany reached 35% single-dose vaccine coverage on 12th May 2021 (week 19 of 2021).
$country == "United States", "astrazeneca_proportion"] <- 0
effectiveness[effectiveness$country == "Israel", "astrazeneca_proportion"] <- 0
effectiveness[effectiveness$country == "Chile", "astrazeneca_proportion"] <- 0
effectiveness[effectiveness
# sourced from European Centre for Disease Prevention and Control
# week 19 of 2021
<- hungary_vax %>%
hungary_summary filter(Week != "2021-17" & Week != "2021-18" & Week != "2021-19") %>%
# Hungary reached 35% single-dose vaccine coverage on 21st April 2021 (week 16 of 2021).
# so exclude week 17, 18 and 19
select(`Vaccine brand`, `First dose`) %>%
rename(Vaccine = `Vaccine brand`, Doses = `First dose`) %>%
group_by(Vaccine) %>%
summarize(Doses = sum(Doses))
# unlike most other European countries, Hungary sourced more than a third
# of its COVID vaccines from Russian or Chinese brands
$country == "Hungary", "astrazeneca_proportion"] <-
effectiveness[effectiveness$Vaccine == "AZ", "Doses"]/sum(hungary_summary$Doses)
hungary_summary[hungary_summary
%>%
hungary_summary arrange(desc(Doses)) %>%
kbl(caption = "Hungary cumulative first-dose administered COVID vaccine brands, week 19 of 2021") %>%
kable_styling()
Vaccine | Doses |
---|---|
COM | 1521273 |
SPU | 758476 |
AZ | 577000 |
BECNBG | 543357 |
MOD | 204781 |
JANSS | 0 |
# sourced from European Centre for Disease Prevention and Control
# week 19 of 2021
<- germany_vax %>%
germany_summary select(`Vaccine brand`, `First dose`) %>%
rename(Vaccine = `Vaccine brand`, Doses = `First dose`) %>%
group_by(Vaccine) %>%
summarize(Doses = sum(Doses))
$country == "Germany", "astrazeneca_proportion"] <-
effectiveness[effectiveness$Vaccine == "AZ", "Doses"]/sum(germany_summary$Doses)
germany_summary[germany_summary
%>%
germany_summary arrange(desc(Doses)) %>%
kbl(caption = "Germany cumulative first-dose administered COVID vaccine brands, week 19 of 2021") %>%
kable_styling()
Vaccine | Doses |
---|---|
COM | 21314356 |
AZ | 7324805 |
MOD | 2117049 |
JANSS | 49226 |
The United Kingdom reached 35% single-dose vaccine coverage on 13th March 2021.
From Coronavirus Vaccine - summary of Yellow Card Reporting (data included: 09/12/2020 to 14/03/2021) - old edition accessed using Wayback Machine:
- ‘As of 14 March, an estimated 10.9 million first doses of the Pfizer/BioNTech vaccine and 13.7 million doses of the Oxford University/AstraZeneca vaccine, had been administered, and around 1.3 million second doses, mostly the Pfizer/BioNTech vaccine, had been administered.’
Canada reached 35% single-dose vaccine coverage on 5th May 2021.
A CTV news report “Risks of rare blood clot even lower with second dose of AstraZeneca, experts say”, dated 20th May 2021, reports:
- ‘Britain, which has had the AstraZeneca shot in circulation much longer than Canada, has administered more than 23 million first doses of the vaccine’
- note that this report (20th May 2021) is two months after the date of the United Kingdom achieving 35% single-dose vaccine coverage.
- ‘In Canada, approximately 2.1 million people have received one dose of the AstraZeneca vaccine’
# CTV news report dated May 20, 2021
# 'Britain, which has had the AstraZeneca shot in circulation much longer than Canada, has administered more than 23 million first doses of the vaccine'
# 'In Canada, approximately 2.1 million people have received one dose of the AstraZeneca vaccine'
$country == "United Kingdom", "astrazeneca_proportion"] <-
effectiveness[effectiveness13.7/(10.9 + 13.7)
$country == "Canada", "astrazeneca_proportion"] <-
effectiveness[effectiveness2100000/(owid %>%
filter(location == "Canada", date == as.Date("2021-05-20")) %>%
pull(people_vaccinated))
%>%
owid filter(location == "United Kingdom" | location == "Canada") %>%
filter(date == as.Date("2021-05-20")) %>%
select(location, people_vaccinated) %>%
rename(Country = location, `Total vaccinated` = people_vaccinated) %>%
kbl(caption = "Total vaccinated, as of 20th May 2021 (source 'Our World in Data')") %>%
kable_styling()
Country | Total vaccinated |
---|---|
Canada | 18312021 |
United Kingdom | 37518614 |
Relationship between AstraZeneca vaccine usage and reduction in COVID-19 cases and deaths
Comparing the rates of cases and deaths from peak of December 2020-January 2021 to three weeks after 35% single-dose coverage has been achieved.
ggplot(
effectiveness,aes(
x = astrazeneca_proportion, y = log_case_reduction,
color = astrazeneca_proportion + log_case_reduction,
label = country
+
)) xlim(-0.05, .75) +
geom_point(shape = 16, size = 2, show.legend = FALSE) +
theme_minimal() +
theme(legend.position = "none") +
scale_color_gradient(low = "#0091ff", high = "#f0650e") +
geom_text(aes(label = country), hjust = -0.1, vjust = 0) +
ggtitle("Reduction in COVID-19 cases compared to December 2020/January 2021 peak", subtitle = "Three weeks after 35% single-dose coverage") +
xlab("Astra-Zeneca as proportion of administered vaccines") +
ylab("Ratio of case reduction (log)")
ggplot(
effectiveness,aes(
x = astrazeneca_proportion, y = log_death_reduction,
color = astrazeneca_proportion + log_death_reduction,
label = country
+
)) xlim(-0.05, .75) +
geom_point(shape = 16, size = 2, show.legend = FALSE) +
theme_minimal() +
theme(legend.position = "none") +
scale_color_gradient(low = "#0091ff", high = "#f0650e") +
geom_text(aes(label = country), hjust = -0.1, vjust = 0) +
ggtitle("Reduction in COVID-19 deaths compared to December 2020/January 2021 peak", subtitle = "Three weeks after 35% single-dose coverage") +
xlab("Astra-Zeneca as proportion of administered vaccines") +
ylab("Ratio of death reduction (log)")