-
-
Notifications
You must be signed in to change notification settings - Fork 385
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
Draft plot_bpv (bayesian p-value) #1222
Conversation
The basic elements are in place. So this is ready for review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me! I didn't check the bokeh code at all, and most of the comments were on naming.
CHANGELOG.md
Outdated
@@ -10,6 +10,7 @@ | |||
* `plot_trace` now supports multiple aesthetics to identify chain and variable | |||
shape and support matplotlib aliases (#1253) | |||
* `plot_hdi` can now take already computed HDI values (#1241) | |||
* `plot_bpv`. A new plot intented to plot Bayesian p-values (#1222) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* `plot_bpv`. A new plot intented to plot Bayesian p-values (#1222) | |
* `plot_bpv`. A new plot for Bayesian p-values (#1222) |
arviz/plots/bpvplot.py
Outdated
data : az.InferenceData object | ||
InferenceData object containing the observed and posterior/prior predictive data. | ||
kind : str | ||
Type of plot to display (u_value, p_value, t_stat). Defaults to u_value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add what u_value
, p_value
, t_stat
are (or references)
arviz/plots/bpvplot.py
Outdated
acepted, see examples section for details. | ||
bpv : bool | ||
If True (default) add the bayesian p_value to the legend when kind = t_stat. | ||
mean : bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a strong feeling, but maybe change to plot_mean
?
Whether or not to plot the mean T statistic. Defaults to True. | ||
reference : str | ||
How to compute the distributions used as reference for u_values or p_values. Allowed values | ||
are "analytical" (default) and "samples". Use `None` to do not plot any reference. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are "analytical" (default) and "samples". Use `None` to do not plot any reference. | |
are "analytical" (default) and "samples". Use `None` to do not plot any reference. Defaults to "samples". |
arviz/plots/bpvplot.py
Outdated
How to compute the distributions used as reference for u_values or p_values. Allowed values | ||
are "analytical" (default) and "samples". Use `None` to do not plot any reference. | ||
n_ref : int, optional | ||
Number of reference distributions to sample when `reference=samples` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Number of reference distributions to sample when `reference=samples` | |
Number of reference distributions to sample when `reference=samples`. Defaults to 100. |
"""Check if value is a number between 0 and 1.""" | ||
try: | ||
value = float(value) | ||
return 0 < value < 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you want this return after the except, since you are watching for a ValueError while casting to float, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this works ok.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will work as written
import arviz as az | ||
|
||
data = az.load_arviz_data("regression1d") | ||
az.plot_bpv(data, kind="t_stat", t_stat="0.5", backend="bokeh") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
az.plot_bpv(data, kind="t_stat", t_stat="0.5", backend="bokeh") | |
az.plot_bpv(data, kind="t_stat", t_stat=0.5, backend="bokeh") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing a string is actually valid
az.style.use("arviz-darkgrid") | ||
|
||
data = az.load_arviz_data("regression1d") | ||
az.plot_bpv(data, kind="t_stat", t_stat="0.5") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
az.plot_bpv(data, kind="t_stat", t_stat="0.5") | |
az.plot_bpv(data, kind="t_stat", t_stat=0.5) |
@@ -0,0 +1,10 @@ | |||
""" | |||
Bayesian p-value Posterior plot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this have a different name from the other, to indicate it is using a T stat?
@@ -0,0 +1,15 @@ | |||
""" | |||
Bayesian p-value Posterior plot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question on naming here
…ment to plot_mean, fix English
maybe @ahartikainen wants to improve the bokeh code in a future PR ;-) |
Codecov Report
@@ Coverage Diff @@
## master #1222 +/- ##
==========================================
- Coverage 93.21% 93.08% -0.14%
==========================================
Files 98 101 +3
Lines 9734 9995 +261
==========================================
+ Hits 9074 9304 +230
- Misses 660 691 +31
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great and very useful, looking forward to the section on EABM too :)
There are many documentation nits that do not need to be addressed straight away, they could well be recommendations for future functions to slowly move towards numpydoc best practices and recommendations. On noting the default for example, I have noticed pandas uses both:
engine : {‘c’, ‘python’}, optional
Parser engine to use. The C engine is faster while the python engine is currently more feature-complete.
where the user has to understand that c
is the default. And
compression : {‘infer’, ‘gzip’, ‘bz2’, ‘zip’, ‘xz’, None}, default ‘infer’
where the user has to understand that having a default means its optional.
---------- | ||
data : az.InferenceData object | ||
InferenceData object containing the observed and posterior/prior predictive data. | ||
kind : str |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I would modify this following numpydoc advise:
When a parameter can only assume one of a fixed set of values, those values can be listed in braces, with the default appearing first:
order : {'C', 'F', 'A'} Description of `order`.
If True (default) add the bayesian p_value to the legend when kind = t_stat. | ||
plot_mean : bool | ||
Whether or not to plot the mean T statistic. Defaults to True. | ||
reference : str |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
computing u_values. Should be in the interval (0, 1]. Defaults to | ||
0.94. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
defaults to stats.hdi_prob
rcParam
For "u_value" we compute pi := p(yi* ≤ yi | y). i.e. like a p_value but per observation yi. | ||
This is also known as marginal p_value. The ideal distribution is uniform. This is similar | ||
to the LOO-pit calculation/plot, the difference is than in LOO-pit plot we compute | ||
pi = p(yi* r ≤ yi | y-i ), where y-i, is all other data except yi. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there is one extra r
before the lower or equal than sign
backend_kwargs : bool, optional | ||
These are kwargs specific to the backend being used. For additional documentation | ||
check the plotting method of the backend. | ||
group : {"prior", "posterior"}, optional |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
along the idea of comments above, this should be inverted to show the default first
ax : numpy array-like of matplotlib axes or bokeh figures, optional | ||
A 2D array of locations into which to plot the densities. If not supplied, Arviz will create | ||
its own array of plot areas (and return it). | ||
backend : str, optional |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
@@ -0,0 +1,294 @@ | |||
"""Bayesian p-value Posterior/Prior predictive plot.""" | |||
import numpy as np | |||
from matplotlib.colors import to_hex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can use az.plots.plot_utils.vectorized_to_hex
. It basically calls matplotlib.colors.to_hex
but works with lists of colors too (not relevant here) and we could at some point (far future) make a version of the function not requiring matplotlib, i.e. try importing from matplotlib and if not possible use bokeh version (as far as I know bokeh has no function that does this yet)
for idx in range(shape[1]): | ||
density, xmin, xmax = _fast_kde(dist_rvs[:, idx]) | ||
x_s = np.linspace(xmin, xmax, len(density)) | ||
x_ss.append(x_s) | ||
densities.append(density) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should check memory performance and see if its possible to preallocate. Not sure how it will perform, but specially the append looks suspicious.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my memory is foggy but I think that was my first attempt, but then I changed because the size of the grid used by _fast_kde is not fixed and this make cause trouble. That should be fixed with the new upcoming kde. Nevertheless I agree this is something we need to revisit.
@@ -966,3 +967,18 @@ def test_plot_rank(models, kwargs): | |||
def test_plot_dist_comparison_warn(models): | |||
with pytest.raises(NotImplementedError, match="The bokeh backend.+Use matplotlib bakend."): | |||
plot_dist_comparison(models.model_1, backend="bokeh") | |||
|
|||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think everything will work with multidimensional data (that is chain, draw, *shape
with shape
being multidimensional) thanks to the skip_dims and careful reshaping, however, it would be great to test on multidimensional models too. Should be the same as test below but using multidim_models
fixture instead, probably a couple cases are enough for multidim.
pi = p(yi* r ≤ yi | y-i ), where y-i, is all other data except yi. | ||
For "t_stat" we compute := p(T(y)* ≤ T(y) | y) where T is any T statistic. See t_stat | ||
argument below for details of available options. | ||
t_stat : str, float, or callable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about adding a "identity"
option too to encourage users to calculate T statistics manually and store them in idata object and then use these new variables as variable names with t_stat="identity"
?
I know it is already possible to do using t_stat=lambda x: x
, hence the encourage above. This would be helpful if T statistic function was expensive to calculate or for convenience to use T statistic with both plot_bpv
and loo_pit
Thanks for the comments @OriolAbril! |
This is a new kind of posterior predictive check plot, focused toward p_values. This a super early draft (the code is still a mess). I have doubts about the arguments names, suggestions are more than welcome. What do you think of these examples. We could also add other like ecdf, but I prefer to concentrate first on getting these right.
BTW, the first too are the same as loo-pit, but using the data instead of the IS weights.
A few examples
kind="u_value", reference="analytical". We want a uniform distribution over the [0, 1] interval
kind="u_value", reference="samples" We want a uniform distribution over the [0, 1] interval
kind="p_value", reference="analytical", t_stat=None. We want a symmetric distribution centered at 0.5
kind="p_value", reference="samples", t_stat=None We want a symmetric distribution centered at 0.5
kind="t_stat", reference=None, t_stat="median", other values are "mean", "std", quantiles can be passed as string of number between 0 and 1. Finally the user can pass an arbitrary function. The density is the distribution of sampled T_stat. The dot represent the mean of the observed T_stat. The legend shows the bayesian p_value (bpv)