A Phase III Study to Assess the Immunogenicity and Safety of SARS-CoV-2 GBP5 in Adults Aged 18 Years and Older.
Dose 1 at Visit 2, dose 2 at Visit 4. Test for immunogenocity at Visit 6, 2 weeks after the second dose.
Data for this analysis is from Vietnamese subjects.
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.3 ✔ readr 2.1.4
## ✔ forcats 1.0.0 ✔ stringr 1.5.0
## ✔ ggplot2 3.4.4 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.0
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(dplyr)
library(janitor)
##
## Attaching package: 'janitor'
##
## The following objects are masked from 'package:stats':
##
## chisq.test, fisher.test
df = read_csv("/Users/nnthieu/Downloads/GBP510/GBP510_final.csv")
## Rows: 9122 Columns: 14
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (7): treatment, screeningno, visit, methodoftest, results, sex, sitename
## dbl (3): age, barcodeid, result2
## date (3): dob, barcodedate, dateofbloodsampling
## time (1): samplingtime
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(df)
## # A tibble: 6 × 14
## treatment screeningno visit methodoftest results sex dob age
## <chr> <chr> <chr> <chr> <chr> <chr> <date> <dbl>
## 1 GBP510 401-0002 Visit 2 ELISA 34 Female 1983-10-29 37
## 2 GBP510 401-0002 Visit 4 ELISA 335 Female 1983-10-29 37
## 3 GBP510 401-0002 Visit 6 ELISA 7599 Female 1983-10-29 37
## 4 GBP510 401-0002 Visit 7 ELISA 4792 Female 1983-10-29 37
## 5 GBP510 401-0002 Visit 8 ELISA NULL Female 1983-10-29 37
## 6 GBP510 401-0002 Visit 9 ELISA NULL Female 1983-10-29 37
## # ℹ 6 more variables: barcodedate <date>, barcodeid <dbl>, sitename <chr>,
## # dateofbloodsampling <date>, samplingtime <time>, result2 <dbl>
glimpse(df)
## Rows: 9,122
## Columns: 14
## $ treatment <chr> "GBP510", "GBP510", "GBP510", "GBP510", "GBP510", …
## $ screeningno <chr> "401-0002", "401-0002", "401-0002", "401-0002", "4…
## $ visit <chr> "Visit 2", "Visit 4", "Visit 6", "Visit 7", "Visit…
## $ methodoftest <chr> "ELISA", "ELISA", "ELISA", "ELISA", "ELISA", "ELIS…
## $ results <chr> "34", "335", "7599", "4792", "NULL", "NULL", "8.08…
## $ sex <chr> "Female", "Female", "Female", "Female", "Female", …
## $ dob <date> 1983-10-29, 1983-10-29, 1983-10-29, 1983-10-29, 1…
## $ age <dbl> 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37…
## $ barcodedate <date> 2021-12-28, 2021-12-28, 2021-12-28, 2021-12-28, 2…
## $ barcodeid <dbl> 103009, 103009, 103009, 103009, 103009, 103009, 10…
## $ sitename <chr> "GBP510_003(401)", "GBP510_003(401)", "GBP510_003(…
## $ dateofbloodsampling <date> 2021-12-09, 2021-12-09, 2021-12-09, 2021-12-09, 2…
## $ samplingtime <time> 09:05:00, 09:05:00, 09:05:00, 09:05:00, 09:05:00,…
## $ result2 <dbl> 0.09, 0.09, 0.09, 0.09, 0.09, 0.09, 0.09, 0.09, 0.…
summary(df)
## treatment screeningno visit methodoftest
## Length:9122 Length:9122 Length:9122 Length:9122
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
## results sex dob age
## Length:9122 Length:9122 Min. :1970-01-01 Min. :18.00
## Class :character Class :character 1st Qu.:1980-01-01 1st Qu.:31.00
## Mode :character Mode :character Median :1990-08-16 Median :41.00
## Mean :2003-11-01 Mean :41.93
## 3rd Qu.:2003-10-27 3rd Qu.:51.00
## Max. :2069-12-11 Max. :79.00
## barcodedate barcodeid sitename dateofbloodsampling
## Min. :2021-12-28 Min. :103001 Length:9122 Min. :2021-12-09
## 1st Qu.:2021-12-28 1st Qu.:103143 Class :character 1st Qu.:2021-12-10
## Median :2021-12-28 Median :103290 Mode :character Median :2021-12-16
## Mean :2021-12-28 Mean :103284 Mean :2021-12-14
## 3rd Qu.:2021-12-28 3rd Qu.:103422 3rd Qu.:2021-12-17
## Max. :2021-12-28 Max. :103558 Max. :2021-12-18
## samplingtime result2
## Length:9122 Min. :0.06000
## Class1:hms 1st Qu.:0.06000
## Class2:difftime Median :0.07000
## Mode :numeric Mean :0.08224
## 3rd Qu.:0.07000
## Max. :0.87000
## # A tibble: 6 × 4
## treatment visit methodoftest results
## <chr> <chr> <chr> <chr>
## 1 GBP510 Visit 6 FRNT 966.35
## 2 GBP510 Visit 6 FRNT 170.62
## 3 GBP510 Visit 6 FRNT 218.82
## 4 GBP510 Visit 6 FRNT 292.5
## 5 GBP510 Visit 6 FRNT 366.98
## 6 GBP510 Visit 6 FRNT 367.68
frnt_visit6_df <- frnt_visit6_df %>%
mutate(results = as.numeric(results))
summary_frnt_v6 <- frnt_visit6_df %>%
group_by(treatment) %>%
summarize(
mean = mean(results, na.rm = TRUE),
SE = sd(results, na.rm = TRUE) / sqrt(n()),
lower_CI = mean(results, na.rm = TRUE) - qt(0.975, df = n() - 1) * (sd(results, na.rm = TRUE) / sqrt(n())),
upper_CI = mean(results, na.rm = TRUE) + qt(0.975, df = n() - 1) * (sd(results, na.rm = TRUE) / sqrt(n()))
)
print(summary_frnt_v6)
## # A tibble: 2 × 5
## treatment mean SE lower_CI upper_CI
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 ChAdOx1-S 170. 10.0 150. 190.
## 2 GBP510 447. 20.7 407. 488.
t.test(results ~ treatment, data = frnt_visit6_df)
##
## Welch Two Sample t-test
##
## data: results by treatment
## t = -12.081, df = 496.38, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group ChAdOx1-S and group GBP510 is not equal to 0
## 95 percent confidence interval:
## -322.5894 -232.3424
## sample estimates:
## mean in group ChAdOx1-S mean in group GBP510
## 169.8788 447.3447
The neutrolized antibodies of GBP510 to virus is significantly higher than that of ChAdOx1-S at visit 6, 2 weeks after the second dose.
# Calculate means and standard deviations for each treatment group
summary_stats <- frnt_visit6_df %>%
group_by(treatment) %>%
summarize(
mean = mean(results, na.rm = TRUE),
sd = sd(results, na.rm = TRUE),
n = n()
)
# Calculate the ratio of means
ratio_means <- summary_stats$mean[summary_stats$treatment == 'GBP510'] / summary_stats$mean[summary_stats$treatment == 'ChAdOx1-S']
# Calculate the standard error of the ratio using the delta method
se_ratio <- ratio_means * sqrt(
(summary_stats$sd[summary_stats$treatment == 'ChAdOx1-S']^2 / (summary_stats$mean[summary_stats$treatment == 'ChAdOx1-S']^2 * summary_stats$n[summary_stats$treatment == 'ChAdOx1-S'])) +
(summary_stats$sd[summary_stats$treatment == 'GBP510']^2 / (summary_stats$mean[summary_stats$treatment == 'GBP510']^2 * summary_stats$n[summary_stats$treatment == 'GBP510']))
)
# Calculate the 95% confidence interval for the ratio
z_value <- qnorm(0.975) # 1.96 for 95% CI
lower_CI <- ratio_means - z_value * se_ratio
upper_CI <- ratio_means + z_value * se_ratio
# Print the results
cat("Ratio of means:", ratio_means, "\n")
## Ratio of means: 2.633317
cat("Standard Error of the ratio:", se_ratio, "\n")
## Standard Error of the ratio: 0.1974595
cat("95% Confidence Interval of the ratio: [", lower_CI, ", ", upper_CI, "]\n")
## 95% Confidence Interval of the ratio: [ 2.246304 , 3.020331 ]
# Percentage of participants with ≥ 4-fold rise in wild-type virus neutralizing antibody titer from baseline to Visit 6
frnt_visit26_df = df %>% select(treatment, screeningno, visit, methodoftest, results) %>%
filter((visit == "Visit 2" | visit == "Visit 6") & methodoftest == "FRNT")
head(frnt_visit26_df)
## # A tibble: 6 × 5
## treatment screeningno visit methodoftest results
## <chr> <chr> <chr> <chr> <chr>
## 1 GBP510 401-0002 Visit 2 FRNT 8.08
## 2 GBP510 401-0002 Visit 6 FRNT 966.35
## 3 GBP510 401-0016 Visit 2 FRNT 8.08
## 4 GBP510 401-0016 Visit 6 FRNT 170.62
## 5 GBP510 401-0019 Visit 2 FRNT 8.08
## 6 GBP510 401-0019 Visit 6 FRNT 218.82
frnt_visit26_df$visit <- ifelse(frnt_visit26_df$visit == "Visit 2", "Visit2", "Visit6")
frnt_visit26_df <- frnt_visit26_df %>%
pivot_wider( names_from = visit, values_from = results)
head(frnt_visit26_df)
## # A tibble: 6 × 5
## treatment screeningno methodoftest Visit2 Visit6
## <chr> <chr> <chr> <chr> <chr>
## 1 GBP510 401-0002 FRNT 8.08 966.35
## 2 GBP510 401-0016 FRNT 8.08 170.62
## 3 GBP510 401-0019 FRNT 8.08 218.82
## 4 GBP510 401-0030 FRNT 8.08 292.5
## 5 GBP510 401-0033 FRNT 8.08 366.98
## 6 GBP510 401-0035 FRNT 8.08 367.68
frnt_visit26_df <- frnt_visit26_df %>% mutate(Visit2 = as.numeric(Visit2))
frnt_visit26_df <- frnt_visit26_df %>% mutate(Visit6 = as.numeric(Visit6))
frnt_visit26_df = frnt_visit26_df %>% mutate(rise4 = case_when(
(Visit6 / Visit2) >= 4 ~ "1",
TRUE ~ "0"
))
# head(frnt_visit26_df)
# Create a contingency table of counts
count_tb_frnt26 <- frnt_visit26_df %>%
tabyl(treatment, rise4)
print(count_tb_frnt26)
## treatment 0 1
## ChAdOx1-S 11 171
## GBP510 7 355
# Convert counts to percentages
percentage_table_frnt26 <- count_tb_frnt26 %>%
adorn_percentages("row") %>%
adorn_pct_formatting(digits = 1)
# View the percentage table
print(percentage_table_frnt26)
## treatment 0 1
## ChAdOx1-S 6.0% 94.0%
## GBP510 1.9% 98.1%
# Filter the dataset for the specified conditions
filtered_df <- df %>% select(treatment, screeningno, visit, methodoftest, results) %>%
filter(visit %in% c("Visit 2", "Visit 4", "Visit 6") & methodoftest == "FRNT")
filtered_df = filtered_df %>% mutate(results = as.numeric(results))
## Warning: There was 1 warning in `mutate()`.
## ℹ In argument: `results = as.numeric(results)`.
## Caused by warning:
## ! NAs introduced by coercion
head(filtered_df )
## # A tibble: 6 × 5
## treatment screeningno visit methodoftest results
## <chr> <chr> <chr> <chr> <dbl>
## 1 GBP510 401-0002 Visit 2 FRNT 8.08
## 2 GBP510 401-0002 Visit 4 FRNT NA
## 3 GBP510 401-0002 Visit 6 FRNT 966.
## 4 GBP510 401-0016 Visit 2 FRNT 8.08
## 5 GBP510 401-0016 Visit 4 FRNT 8.08
## 6 GBP510 401-0016 Visit 6 FRNT 171.
# Filter the dataset for the specified conditions
filtered_df = filtered_df %>% mutate(results = as.numeric(results))
# Create the boxplot
ggplot(filtered_df, aes(x = visit, y = results, fill = treatment)) +
geom_boxplot() +
scale_y_log10() +
labs(
y = "GMT by FRNT (log10 scale)",
title = "GMT of FRNT by Visit and Treatment"
) +
theme_minimal()
## Warning: Removed 422 rows containing non-finite values (`stat_boxplot()`).
Vaccine GBO510 is superior to ChAdOx1-S at visit 6, 2 weeks after the second dose.