Skip to content

Commit 67a0f95

Browse files
authored
Merge pull request #144 from cmu-delphi/release_v3.0
Release v3.0
2 parents 019a2a4 + 27f14a1 commit 67a0f95

File tree

9 files changed

+273
-145
lines changed

9 files changed

+273
-145
lines changed

.github/workflows/s3_upload.yml

Lines changed: 0 additions & 49 deletions
This file was deleted.

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: forecast-eval
22
Title: Forecast Evaluation Dashboard
3-
Version: 2.1
3+
Version: 3
44
Authors@R: person("Kate", "Harwood",
55
role = c("cre")),
66
person("Chris", "Scott",

Makefile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ S3_BUCKET=s3://forecast-eval
55
build: build_dashboard
66

77
r_build:
8-
docker build -t forecast-eval-build docker_build
8+
docker build --no-cache --pull -t forecast-eval-build docker_build
99

1010
predictions_cards.rds score_cards_state_deaths.rds score_cards_state_cases.rds score_cards_nation_cases.rds score_cards_nation_deaths.rds: dist
1111
test -f dist/$@ || curl -o dist/$@ $(S3_URL)/$@
@@ -32,18 +32,18 @@ deploy: score_forecast
3232

3333
# Starts a docker image with a full preconfigured R environment
3434
start_dev: r_build
35-
docker run -ti --rm \
35+
docker run --pull=always -ti --rm \
3636
-v ${PWD}/Report:/var/forecast-eval \
3737
-v ${PWD}/dashboard:/var/forecast-eval-dashboard \
3838
-v ${PWD}/dist:/var/dist \
3939
-w /var/forecast-eval \
4040
ghcr.io/cmu-delphi/forecast-eval:latest bash
4141

4242
build_dashboard_dev: pull_data
43-
docker build -t ghcr.io/cmu-delphi/forecast-eval:latest -f docker_dashboard/Dockerfile .
43+
docker build --no-cache --pull -t ghcr.io/cmu-delphi/forecast-eval:latest -f docker_dashboard/Dockerfile .
4444

4545
build_dashboard: pull_data
46-
docker build --no-cache=true -t ghcr.io/cmu-delphi/forecast-eval:$(imageTag) -f docker_dashboard/Dockerfile .
46+
docker build --no-cache=true --pull -t ghcr.io/cmu-delphi/forecast-eval:$(imageTag) -f docker_dashboard/Dockerfile .
4747

4848
deploy_dashboard: build_dashboard
4949
docker push ghcr.io/cmu-delphi/forecast-eval:$(imageTag)

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ git tag -a v1.0 -m "Version 1.0"
4949
git push origin release_v1.0
5050
git push origin v1.0
5151
```
52+
Create a PR into `main`.
53+
After code is merged to `main`, perform cleanup by merging `main` into `dev` so that `dev` stays up to date.
5254

5355
## Note on Scoring Script
5456

Report/create_reports.R

Lines changed: 73 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,45 @@ prediction_cards_filepath = case_when(
2323
TRUE~prediction_cards_filename
2424
)
2525

26-
forecasters = c(get_covidhub_forecaster_names(designations = "primary"),
27-
"COVIDhub-baseline")
26+
forecasters = unique(c(get_covidhub_forecaster_names(designations = c("primary", "secondary")),
27+
"COVIDhub-baseline", "COVIDhub-trained_ensemble"))
2828
locations = covidHubUtils::hub_locations
2929

3030
# also includes "us", which is national level data
3131
state_geos = locations %>%
3232
filter(nchar(.data$geo_value) == 2) %>%
3333
pull(.data$geo_value)
3434
signals = c("confirmed_incidence_num",
35-
"deaths_incidence_num")
35+
"deaths_incidence_num",
36+
"confirmed_admissions_covid_1d")
3637

3738
predictions_cards = get_covidhub_predictions(forecasters,
3839
signal = signals,
40+
ahead = 1:28,
3941
geo_values = state_geos,
4042
verbose = TRUE,
41-
use_disk = TRUE)
43+
use_disk = TRUE) %>%
44+
filter(!(incidence_period == "epiweek" & ahead > 4))
45+
46+
predictions_cards = predictions_cards %>%
47+
filter(!is.na(target_end_date)) %>%
48+
filter(target_end_date < today())
49+
50+
# For hospitalizations, drop all US territories except Puerto Rico and the
51+
# Virgin Islands; HHS does not report data for any territories except PR and VI.
52+
territories <- c("as", "gu", "mp", "fm", "mh", "pw", "um")
4253
predictions_cards = predictions_cards %>%
43-
filter(!is.na(predictions_cards$target_end_date))
44-
predictions_cards = predictions_cards %>% filter(target_end_date < today())
54+
filter(!(geo_value %in% territories & data_source == "hhs"))
4555

46-
# Only accept forecasts made Monday or earlier
56+
# For epiweek predictions, only accept forecasts made Monday or earlier.
57+
# target_end_date is the date of the last day (Saturday) in the epiweek
58+
# For daily predictions, accept any forecast where the target_end_date is later
59+
# than the forecast_date.
4760
predictions_cards = predictions_cards %>%
48-
filter(target_end_date - (forecast_date + 7 * ahead) >= -2)
61+
filter(
62+
(incidence_period == "epiweek" & target_end_date - (forecast_date + 7 * ahead) >= -2) |
63+
(incidence_period == "day" & target_end_date > forecast_date)
64+
)
4965

5066
# And only a forecaster's last forecast if multiple were made
5167
predictions_cards = predictions_cards %>%
@@ -56,7 +72,7 @@ class(predictions_cards) = c("predictions_cards", class(predictions_cards))
5672

5773
print("Saving predictions...")
5874
saveRDS(predictions_cards,
59-
file = "predictions_cards.rds",
75+
file = prediction_cards_filepath,
6076
compress = "xz")
6177
print("Predictions saved")
6278

@@ -76,7 +92,10 @@ err_measures = c(wis = weighted_interval_score,
7692
underprediction = underprediction,
7793
sharpness = sharpness,
7894
ae = absolute_error,
79-
coverage_functions)
95+
coverage_functions,
96+
value_20 = get_quantile_prediction_factory(0.2),
97+
value_50 = get_quantile_prediction_factory(0.5),
98+
value_80 = get_quantile_prediction_factory(0.8))
8099

81100
nation_predictions = predictions_cards %>% filter(geo_value == "us")
82101
state_predictions = predictions_cards %>% filter(geo_value != "us")
@@ -91,22 +110,54 @@ state_scores = evaluate_covid_predictions(state_predictions,
91110
geo_type = "state")
92111

93112
source("score.R")
94-
print("Saving state confirmed incidence...")
95-
save_score_cards(state_scores, "state", signal_name = "confirmed_incidence_num",
96-
output_dir = opt$dir)
97-
print("Saving state deaths incidence...")
98-
save_score_cards(state_scores, "state", signal_name = "deaths_incidence_num",
99-
output_dir = opt$dir)
113+
if ( "confirmed_incidence_num" %in% unique(state_scores$signal)) {
114+
print("Saving state confirmed incidence...")
115+
save_score_cards(state_scores, "state", signal_name = "confirmed_incidence_num",
116+
output_dir = opt$dir)
117+
} else {
118+
warning("State confirmed incidence should generally be available. Please
119+
verify that you expect not to have any cases incidence forecasts")
120+
}
121+
if ( "deaths_incidence_num" %in% unique(state_scores$signal)) {
122+
print("Saving state deaths incidence...")
123+
save_score_cards(state_scores, "state", signal_name = "deaths_incidence_num",
124+
output_dir = opt$dir)
125+
} else {
126+
warning("State deaths incidence should generally be available. Please
127+
verify that you expect not to have any deaths incidence forecasts")
128+
}
129+
if ( "confirmed_admissions_covid_1d" %in% unique(state_scores$signal)) {
130+
print("Saving state hospitalizations...")
131+
save_score_cards(state_scores, "state", signal_name = "confirmed_admissions_covid_1d",
132+
output_dir = opt$dir)
133+
}
134+
100135

101136
print("Evaluating national forecasts")
102137
# COVIDcast does not return national level data, using CovidHubUtils instead
138+
103139
nation_scores = evaluate_chu(nation_predictions, signals, err_measures)
104140

105-
print("Saving nation confirmed incidence...")
106-
save_score_cards(nation_scores, "nation",
107-
signal_name = "confirmed_incidence_num", output_dir = opt$dir)
108-
print("Saving nation deaths incidence...")
109-
save_score_cards(nation_scores, "nation", signal_name = "deaths_incidence_num",
110-
output_dir = opt$dir)
141+
if ( "confirmed_incidence_num" %in% unique(state_scores$signal)) {
142+
print("Saving nation confirmed incidence...")
143+
save_score_cards(nation_scores, "nation",
144+
signal_name = "confirmed_incidence_num", output_dir = opt$dir)
145+
} else {
146+
warning("Nation confirmed incidence should generally be available. Please
147+
verify that you expect not to have any cases incidence forecasts")
148+
}
149+
if ( "deaths_incidence_num" %in% unique(state_scores$signal)) {
150+
print("Saving nation deaths incidence...")
151+
save_score_cards(nation_scores, "nation", signal_name = "deaths_incidence_num",
152+
output_dir = opt$dir)
153+
} else {
154+
warning("Nation deaths incidence should generally be available. Please
155+
verify that you expect not to have any deaths incidence forecasts")
156+
}
157+
if ( "confirmed_admissions_covid_1d" %in% unique(state_scores$signal)) {
158+
print("Saving nation hospitalizations...")
159+
save_score_cards(nation_scores, "nation", signal_name = "confirmed_admissions_covid_1d",
160+
output_dir = opt$dir)
161+
}
111162

112163
print("Done")

Report/error_measures.R

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,23 @@ find_quantile_match <- function(quantiles, val_to_match, tol=1e-8){
7272
return(abs(quantiles - val_to_match) < tol & !is.na(quantiles))
7373
}
7474

75+
get_quantile_prediction_factory <- function(val_to_match, tol=1e-8) {
76+
get_quantile_prediction <- function(quantile, value, actual_value) {
77+
if (all(is.na(quantile))) return(NA)
78+
79+
value <- value[!is.na(quantile)]
80+
quantile <- quantile[!is.na(quantile)]
81+
82+
val <- value[find_quantile_match(quantile, val_to_match, tol)]
83+
84+
if (length(val) != 1L) return(NA)
85+
86+
return(val)
87+
}
88+
89+
return(get_quantile_prediction)
90+
}
91+
7592
score_func_param_checker <- function(quantiles, values, actual_value, id = ""){
7693
id_str = paste0(id, ": ")
7794
if (length(actual_value) > 1) {

Report/score.R

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ library("assertthat")
33

44
save_score_cards = function(score_card, geo_type = c("state", "nation"),
55
signal_name = c("confirmed_incidence_num",
6-
"deaths_incidence_num"),
6+
"deaths_incidence_num",
7+
"confirmed_admissions_covid_1d"),
78
output_dir = ".") {
89
signal_name = match.arg(signal_name)
910
geo_type = match.arg(geo_type)
@@ -13,11 +14,11 @@ save_score_cards = function(score_card, geo_type = c("state", "nation"),
1314
assert_that(signal_name %in% signals,
1415
msg = "signal is not in score_card")
1516
score_card = score_card %>% filter(signal == signal_name)
16-
if (signal_name == "confirmed_incidence_num") {
17-
sig_suffix = "cases"
18-
} else {
19-
sig_suffix = "deaths"
20-
}
17+
18+
type_map <- list("confirmed_incidence_num" = "cases",
19+
"deaths_incidence_num" = "deaths",
20+
"confirmed_admissions_covid_1d" = "hospitalizations")
21+
sig_suffix <- type_map[[signal_name]]
2122
output_file_name = file.path(output_dir,
2223
paste0("score_cards_", geo_type, "_",
2324
sig_suffix, ".rds"))
@@ -37,20 +38,25 @@ save_score_cards = function(score_card, geo_type = c("state", "nation"),
3738

3839
evaluate_chu = function(predictions, signals, err_measures) {
3940
allowed_signals = c("confirmed_incidence_num",
40-
"deaths_incidence_num")
41+
"deaths_incidence_num",
42+
"confirmed_admissions_covid_1d")
4143
assert_that(all(signals %in% allowed_signals),
4244
msg = paste("Signal not allowed:",
4345
setdiff(signals, allowed_signals)))
46+
47+
target_map <- list("confirmed_incidence_num" = "inc case",
48+
"deaths_incidence_num" = "inc death",
49+
"confirmed_admissions_covid_1d" = "inc hosp")
50+
source_map <- list("confirmed_incidence_num" = "JHU",
51+
"deaths_incidence_num" = "JHU",
52+
"confirmed_admissions_covid_1d" = "HealthData")
4453
scores = c()
4554
for (signal_name in signals) {
4655
preds_signal = predictions %>%
4756
filter(signal == signal_name)
48-
if (signal_name == "confirmed_incidence_num") {
49-
jhu_signal = "inc case"
50-
} else {
51-
jhu_signal = "inc death"
52-
}
53-
chu_truth = covidHubUtils::load_truth("JHU", jhu_signal)
57+
signal <- target_map[[signal_name]]
58+
source <- source_map[[signal_name]]
59+
chu_truth = covidHubUtils::load_truth(source, signal)
5460
chu_truth = chu_truth %>%
5561
rename(actual = value) %>%
5662
select(-c(model,

0 commit comments

Comments
 (0)