Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plot projections and eval scores #115

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open

Plot projections and eval scores #115

wants to merge 4 commits into from

Conversation

Fuhan-Yang
Copy link
Contributor

@Fuhan-Yang Fuhan-Yang commented Feb 3, 2025

Add diagnostic plots of time-varying projections compared with data, and evaluation scores differed by forecast dates. Minor bugs showed up when using different forecast periods. Worth to try multiple forecast periods to ensure the robustness of the pipeline.

@Fuhan-Yang Fuhan-Yang linked an issue Feb 3, 2025 that may be closed by this pull request
@Fuhan-Yang Fuhan-Yang removed a link to an issue Feb 3, 2025
@Fuhan-Yang Fuhan-Yang linked an issue Feb 3, 2025 that may be closed by this pull request
@Fuhan-Yang Fuhan-Yang requested review from swo and eschrom February 3, 2025 16:51
@Fuhan-Yang Fuhan-Yang marked this pull request as ready for review February 3, 2025 16:52
Copy link
Collaborator

@eschrom eschrom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work, @Fuhan-Yang! I apologize that I'm not well-versed in altair, so I cannot review the actual plotting with much detail. But I did find one spot that I think needs a change - the forecasts are saved in long, not wide, format now. Otherwise, there are just some questions peppered throughout.

data = pl.scan_parquet(args.obs).collect()

# Drop all samples and just use mean estimate, for now
pred = pred.drop([col for col in pred.columns if "estimate_" in col])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line expects the forecasts in wide format, but they are now in long format. See Line ~592 in iup/models.py, which returns predictions from a model as SampleForecasts (with sample_id and estimate columns), and then see Line ~85 in scripts/forecast.py, which averages over samples to get the mean of the posterior predictive distribution at each time_end before saving the forecasts.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forget if this was being discussed elsewhere, but I have a strong preference for long format for these things

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was, and we fixed it!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching that! This line may adapt from previous version and didn't raise error because the condition didn't meet. We indeed switched to long format, and just average over for now. This line is deleted.


charts = []

forecast_starts = [date for date in pred["forecast_start"].unique()]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check that the pred frame is already sorted by forecast_start to make sure that the plot panels come out in a sensible order? I am unfamiliar with altair plotting, so maybe panel ordering is done automatically - just wanted to check.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

altair won't mind if the rows in the input data frame aren't sorted in the order that the points will be left-to-right plotted

obs: polars.Dataframe
The observed uptake data frame, indicating the cumulative vaccine uptake as of `time_end`.
pred: polars.Dataframe
The predicted daily uptake, differed by forecast date, must include columns `forecast_start` and `estimate`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say, "The predicted cumulative uptake, ..." since the predictions taken here are cumulative, whereas daily average uptake is a separate that actually appears in some of the model fitting.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

pred: polars.Dataframe
The predicted daily uptake, differed by forecast date, must include columns `forecast_start` and `estimate`.
config: dict
config.yaml to define the number of columns in the graph, the saving path and the saving name.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The config doesn't actually have the path or name for saving, does it?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above; agree I would drop config

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this was my trial but it got deprecated. Thanks for catching that

scores: polars.DataFrame
The evaluation scores data frame.
config: dict
config.yaml to define the saving path and the saving name.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, the config doesn't really have the path or name for saving, right? I thought those were in the makefile. The config has the full names of the evaluation metrics, though.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above; agree that I would drop config

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Thanks for catching

Copy link
Collaborator

@swo swo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My big things are:

  • Making sure that config is not passed to the postprocessing plot scripts
  • Simplifying the plots using existing facet or grid systems

I also don't think it's crazy to have a single postprocessing.py that plots the forecasts and the scores. Because at some point we'll also want some csv (or whatever) reports of some of these values. Rather than have a different script for each of them, we could just stick them all together. There aren't that many outputs being made, that this shouldn't be too slow? (Unless it is slow to make some of these plots, in which case, we should keep them separate!)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would put all of these options right in the scripts themselves

Like, the config is most important for articulating what analyses the pipeline is going to run, so the model names, model parameters, score funs, etc. are all important

But "plot: True" is something that should really be in the Makefile, and how many columns in the subplot is something we can just leave in the script and tweak there as needed

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto with the score function -> name dictionary

I'd rather just have this defined somewhere in the plotting script, because changing it shouldn't trigger a re-run of the upstream forecasts

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm comparing against the flowchart in #61

I think this PR introduces dependencies from config.yaml to proj_plot.py and score_plot.py, when we don't really need those dependencies. I'd like to be able to iterate on the postprocessing without triggering a re-run of the upstream stuff

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, looking at Makefile, it looks like the config is not passed to these scripts

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But "plot: True" is something that should really be in the Makefile, and how many columns in the subplot is something we can just leave in the script and tweak there as needed

Thanks for pointing out what are important for config file, which I found vague so far. How to put "plot: True" in Makefile to let users choose to plot or not? I will put the number of subplot columns in the script, and would like you to demo the plotting option in Makefile!


forecast_starts = [date for date in pred["forecast_start"].unique()]

for forecast_start in forecast_starts:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just use a grid chart with .encode(row=etc, column=etc) or a facet chart with .facet()?

See https://altair-viz.github.io/user_guide/compound_charts.html#repeated-charts for explanations of how to avoid constructing these kinds of grids manually

(I'm not even sure you need layers here, to do data and projection; you might be able to just unpivot and use .encode(color=)

scores: polars.DataFrame
The evaluation scores data frame.
config: dict
config.yaml to define the saving path and the saving name.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above; agree that I would drop config

pred: polars.Dataframe
The predicted daily uptake, differed by forecast date, must include columns `forecast_start` and `estimate`.
config: dict
config.yaml to define the number of columns in the graph, the saving path and the saving name.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above; agree I would drop config

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks right!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Plots for point estimates
3 participants