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

Redesign of MCSE #63

Merged
merged 49 commits into from
Jan 19, 2023
Merged

Redesign of MCSE #63

merged 49 commits into from
Jan 19, 2023

Conversation

sethaxen
Copy link
Member

Following #39 (comment) and #53, this PR redesigns mcse:

  • mcse now requires the user provide an estimator to make it less ambiguous what is estimated.
  • the vector methods to mcse have been removed and replaced with 3d array methods similar to ess_rhat, which also allow for eltypes to include Missing. This allows MCSEs to be computed for many parameters with one function call and also allows for improved ESS estimates when multiple chains are provided
  • a subsampling bootstrap method has been added as a fallback, since unlike batch means or overlapping batch means, it works for any estimator.
  • custom estimators have been added for mean, std, and quantile using the ESS methods
  • batch-means, initial monotone sequence, and initial positive sequence methods have been removed. These estimators only can estimate the MCSE of mean. From the Geyer reference in the docstrings, IMSE is better than IPSE, and both are better than batch-means, which tends to underestimate MCSE more severely. IMSE is used in the ess_rhat(::typeof(mean), x) call used in the new ess_rhat implementations.

Marked as a draft for now until I add tests.

@coveralls
Copy link

coveralls commented Jan 17, 2023

Pull Request Test Coverage Report for Build 3939266728

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 57 of 58 (98.28%) changed or added relevant lines in 5 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.06%) to 95.828%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/mcse.jl 39 40 97.5%
Totals Coverage Status
Change from base Build 3939418215: 0.06%
Covered Lines: 689
Relevant Lines: 719

💛 - Coveralls

@codecov
Copy link

codecov bot commented Jan 17, 2023

Codecov Report

Base: 95.76% // Head: 96.16% // Increases project coverage by +0.40% 🎉

Coverage data is based on head (69fe0a1) compared to base (2e07d21).
Patch coverage: 100.00% of modified lines in pull request are covered.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #63      +/-   ##
==========================================
+ Coverage   95.76%   96.16%   +0.40%     
==========================================
  Files          10       10              
  Lines         732      757      +25     
==========================================
+ Hits          701      728      +27     
+ Misses         31       29       -2     
Impacted Files Coverage Δ
src/ess.jl 100.00% <100.00%> (ø)
src/gewekediag.jl 100.00% <100.00%> (ø)
src/heideldiag.jl 100.00% <100.00%> (ø)
src/mcse.jl 100.00% <100.00%> (+4.44%) ⬆️
src/utils.jl 100.00% <100.00%> (ø)

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

src/mcse.jl Outdated
T = promote_type(eltype(x), typeof(zero(eltype(x)) / 1))
values = similar(x, T, (axes(x, 3),))
for (i, xi) in zip(eachindex(values), eachslice(x; dims=3))
values[i] = _mcse_sbm(f, vec(xi); batch_size=batch_size)
Copy link
Member Author

Choose a reason for hiding this comment

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

I haven't seen in the literature a study of how best to combine MCMC chains when estimating MCSE with SBM. I benchmarked a few alternatives and found this one underestimated the MCSE the least: arviz-devs/arviz#1974 (comment)

@sethaxen sethaxen marked this pull request as ready for review January 17, 2023 00:33
for size in (51, 75, 100, 153)
@test_logs (:warn,) mcse(samples; method=:bm, size=size)
@testset "mcse.jl" begin
@testset "estimand is within interval defined by MCSE estimate" begin
Copy link
Member Author

@sethaxen sethaxen Jan 17, 2023

Choose a reason for hiding this comment

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

For mean, std, and quantile, these tests are somewhat redundant with those for ess_rhat, since the only difference is that for ess_rhat we compute the exact asymptotic variance of the estimator since we know the stationary distribution, whereas for mcse we estimate the asymptotic variance of the estimator. If we want to speed up our test suite, it may be better to remove the corresponding ess_rhat tests and use these as integration tests.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've opted to speed up our test suite by decreasing the number of replicates (params) for each suite to 100 instead of 1,000.

src/mcse.jl Outdated
Comment on lines 95 to 96
SBM tends to underestimate the MCSE, especially for highly autocorrelated chains.
SBM should only be used as a fallbeck when a specific [`mcse`](@ref) method for
Copy link
Member Author

Choose a reason for hiding this comment

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

This begs the question whether we should include mcse_sbm at all. On the one hand it's useful to have a fallback, and I don't know of any other general-purpose methods for estimating MCSE. On the other hand, we would prefer a fallback that errs on the side of overestimating MCSE instead of overestimating.

I lean towards including it with this caveat clearly documented.

Copy link
Member

Choose a reason for hiding this comment

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

Since we only want it to be used as a fallback, maybe we do not even want to add another function for it but also call it mcse? And just document there that it is used as a fallback but one should be aware of its limitations.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good idea

Copy link
Member Author

Choose a reason for hiding this comment

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

On second thought, it's useful to have it as a standalone method so if we want, we can compare its results with those of the specific estimators. But we can make the function internal and copy the documentation to mcse.

@@ -480,7 +482,7 @@ function _expectand_proxy(::typeof(StatsBase.mad), x)
return _expectand_proxy(Statistics.median, x_folded)
end
function _expectand_proxy(f::Base.Fix2{typeof(Statistics.quantile),<:Real}, x)
y = similar(x, Bool)
y = similar(x)
Copy link
Member Author

@sethaxen sethaxen Jan 18, 2023

Choose a reason for hiding this comment

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

Necessary because otherwise our transformation discards the type of x, so a Float32 eltype x will get a Float64 ESS/R-hat/MCSE.

src/heideldiag.jl Outdated Show resolved Hide resolved
src/mcse.jl Outdated Show resolved Hide resolved
src/mcse.jl Outdated Show resolved Hide resolved
src/mcse.jl Outdated Show resolved Hide resolved
src/mcse.jl Outdated Show resolved Hide resolved
src/mcse.jl Outdated Show resolved Hide resolved
src/mcse.jl Outdated Show resolved Hide resolved
src/mcse.jl Outdated
Comment on lines 95 to 96
SBM tends to underestimate the MCSE, especially for highly autocorrelated chains.
SBM should only be used as a fallbeck when a specific [`mcse`](@ref) method for
Copy link
Member

Choose a reason for hiding this comment

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

Since we only want it to be used as a fallback, maybe we do not even want to add another function for it but also call it mcse? And just document there that it is used as a fallback but one should be aware of its limitations.

src/mcse.jl Outdated Show resolved Hide resolved
src/utils.jl Show resolved Hide resolved
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.

3 participants