|
1 | 1 | import theano.tensor as tt
|
2 | 2 | import numpy as np
|
3 | 3 | from numpy.random import multivariate_normal
|
4 |
| - |
5 | 4 | import pymc3 as pm
|
6 | 5 |
|
7 | 6 | # Generate some multivariate normal data:
|
8 | 7 | n_obs = 1000
|
9 | 8 |
|
10 | 9 | # Mean values:
|
11 |
| -mu = np.linspace(0, 2, num=4) |
12 |
| -n_var = len(mu) |
| 10 | +mu_r = np.linspace(0, 2, num=4) |
| 11 | +n_var = len(mu_r) |
13 | 12 |
|
14 | 13 | # Standard deviations:
|
15 | 14 | stds = np.ones(4) / 2.0
|
16 | 15 |
|
17 | 16 | # Correlation matrix of 4 variables:
|
18 |
| -corr = np.array([[1., 0.75, 0., 0.15], |
19 |
| - [0.75, 1., -0.06, 0.19], |
20 |
| - [0., -0.06, 1., -0.04], |
21 |
| - [0.15, 0.19, -0.04, 1.]]) |
22 |
| -cov_matrix = np.diag(stds).dot(corr.dot(np.diag(stds))) |
23 |
| - |
24 |
| -dataset = multivariate_normal(mu, cov_matrix, size=n_obs) |
25 |
| - |
| 17 | +corr_r = np.array([[1., 0.75, 0., 0.15], |
| 18 | + [0.75, 1., -0.06, 0.19], |
| 19 | + [0., -0.06, 1., -0.04], |
| 20 | + [0.15, 0.19, -0.04, 1.]]) |
| 21 | +cov_matrix = np.diag(stds).dot(corr_r.dot(np.diag(stds))) |
26 | 22 |
|
27 |
| -# In order to convert the upper triangular correlation values to a complete |
28 |
| -# correlation matrix, we need to construct an index matrix: |
29 |
| -n_elem = int(n_var * (n_var - 1) / 2) |
30 |
| -tri_index = np.zeros([n_var, n_var], dtype=int) |
31 |
| -tri_index[np.triu_indices(n_var, k=1)] = np.arange(n_elem) |
32 |
| -tri_index[np.triu_indices(n_var, k=1)[::-1]] = np.arange(n_elem) |
| 23 | +dataset = multivariate_normal(mu_r, cov_matrix, size=n_obs) |
33 | 24 |
|
34 | 25 | with pm.Model() as model:
|
35 | 26 |
|
36 | 27 | mu = pm.Normal('mu', mu=0, sd=1, shape=n_var)
|
37 | 28 |
|
38 |
| - # We can specify separate priors for sigma and the correlation matrix: |
39 |
| - sigma = pm.Uniform('sigma', shape=n_var) |
40 |
| - corr_triangle = pm.LKJCorr('corr', n=1, p=n_var) |
41 |
| - corr_matrix = corr_triangle[tri_index] |
42 |
| - corr_matrix = tt.fill_diagonal(corr_matrix, 1) |
| 29 | + # Note that we access the distribution for the standard |
| 30 | + # deviations, and do not create a new random variable. |
| 31 | + sd_dist = pm.HalfCauchy.dist(beta=2.5) |
| 32 | + packed_chol = pm.LKJCholeskyCov('chol_cov', n=n_var, eta=1, sd_dist=sd_dist) |
| 33 | + # compute the covariance matrix |
| 34 | + chol = pm.expand_packed_triangular(n_var, packed_chol, lower=True) |
| 35 | + cov = tt.dot(chol, chol.T) |
43 | 36 |
|
44 |
| - cov_matrix = tt.diag(sigma).dot(corr_matrix.dot(tt.diag(sigma))) |
| 37 | + # Extract the standard deviations etc |
| 38 | + sd = pm.Deterministic('sd', tt.sqrt(tt.diag(cov))) |
| 39 | + corr = tt.diag(sd**-1).dot(cov.dot(tt.diag(sd**-1))) |
| 40 | + r = pm.Deterministic('r', corr[np.triu_indices(n_var, k=1)]) |
45 | 41 |
|
46 |
| - like = pm.MvNormal('likelihood', mu=mu, cov=cov_matrix, observed=dataset) |
| 42 | + like = pm.MvNormal('likelihood', mu=mu, chol=chol, observed=dataset) |
47 | 43 |
|
48 | 44 |
|
49 | 45 | def run(n=1000):
|
50 | 46 | if n == "short":
|
51 | 47 | n = 50
|
52 | 48 | with model:
|
53 |
| - start = pm.find_MAP() |
54 |
| - step = pm.NUTS(scaling=start) |
55 |
| - trace = pm.sample(n, step=step, start=start) |
56 |
| - return trace |
| 49 | + trace = pm.sample(n) |
| 50 | + pm.traceplot(trace, varnames=['mu', 'r'], |
| 51 | + lines={'mu': mu_r, 'r': corr_r[np.triu_indices(n_var, k=1)]}) |
57 | 52 |
|
58 | 53 | if __name__ == '__main__':
|
59 | 54 | run()
|
0 commit comments