Repository navigation
Conversation
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR computes the predictive variance of the reference model for the Gaussian and Student-t families with two matrix products instead of one R-level
weighted.mean()call per observation.project()with 10 000 observations and 4 000 projected draws gets about 7 times faster. For small numbers of observations, the run time does not change. The results do not change.This PR was assisted by Claude.
Overhead
predvar_gauss()andpredvar_student_t()compute, for each observation, the weighted variance ofmuacross the draws with oneweighted.mean()call per observation.get_refdist()callsfamily$predvar()once per projected draw, andget_p_clust()once per cluster, so a projection with S draws makes n × S R-level calls. In a profile ofproject()for a Gaussian model with n = 10 000 and 4 000 projected draws,get_refdist()took 88 % of the time, nearly all inweighted.mean().Changes
rowvar_wdraws()computes the same weighted variances for all observations with two matrix products.predvar_gauss()andpredvar_student_t()use it.predvar_gamma()does not compute a variance, so it does not change.Results
For random inputs (one draw, 400 draws, unequal weights, missing values), the largest relative difference to the old code is 1.1e-15, with the same missing values. For one draw, the variance term is exactly 0, as before. One call with n = 10 000 and one draw takes 0.05 ms instead of 34 ms.
Gaussian reference model with P = 50 and 4 000 draws; all results identical to master (largest relative difference 1.6e-16, identical rankings):
project(), n = 10 000, 4 000 projected drawsproject(), n = 50 000, 400 projected drawsproject(), n = 1 000, 4 000 projected drawsvarsel(), n = 10 000, 400 projected drawsFor small n (N = 50, P = 200), the run time does not change.
Tests
The new
test_predvar.Rchecks that:rowvar_wdraws()equals the row-wise weighted variance of the old code, for unequal and equal weights; that it gives exactly 0 for one draw; and that a missing value gives a missing variance for its observation only;predvar()of the extendedgaussian()andStudent_t()families equals the weighted mean of the squared dispersion (times nu / (nu - 2) for Student-t) plus the weighted variance ofmu.The first test fails on master (function not found). The second test passes on master and on this branch; it checks that the change keeps the results. The full suite passes with
NOT_CRAN=true: 255 tests, 55 813 expectations, 0 failures, the same 4 warnings as master. Tested with this change applied to master 73cf0ee (projpred 2.11.0.9000), R 4.6.1, brms 2.23.0, rstanarm 2.32.2, cmdstanr 0.9.0.9001, CmdStan 2.39.0, on CSC Roihu (Linux, AMD EPYC).Formula
For the draws$s$ in one cluster (or one projected draw), with weights $w_s$ normalized to $\sum_s w_s = 1$ , means $\mu_{is}$ and dispersions $\sigma_s$ , the predictive variance of observation $i$ is
with$c = 1$ for the Gaussian family and $c = \nu / (\nu - 2)$ for the Student-t family. The first term is the same for all $i$ .
Master
get_refdist()callspredvar()once per projected draw, andget_p_clust()once per cluster. So one projection makesweighted.mean(). ForThis PR
With$M$ the $n \times S_c$ matrix of $\mu_{is}$ for the $S_c$ draws in the cluster and $w$ the weight vector:
where$\circ$ is the elementwise product. These are two matrix-vector products with $O(n S_c)$ operations, as in master, but in compiled code.
For one draw ($S_c = 1$ , $w = 1$ ), $v^{\mu} = 0$ exactly. A missing $\mu_{is}$ gives a missing $v_i$ , as in master.