pcntoolkit 0.32.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,242 @@
1
+ from __future__ import print_function
2
+ import os
3
+ import sys
4
+ import numpy as np
5
+ from scipy import stats
6
+ import scipy.special as spp
7
+ import pickle
8
+ import matplotlib.pyplot as plt
9
+ import pandas as pd
10
+ import pymc as pm
11
+ from pcntoolkit.model.SHASH import *
12
+ from pcntoolkit.model.hbr import bspline_transform
13
+
14
+ """
15
+ @author: augub
16
+ """
17
+
18
+
19
+ def MCMC_estimate(f, trace):
20
+ """Get an MCMC estimate of f given a trace"""
21
+ out = np.zeros_like(f(trace.point(0)))
22
+ n = 0
23
+ for p in trace.points():
24
+ out += f(p)
25
+ n += 1
26
+ return out/n
27
+
28
+
29
+ def get_MCMC_zscores(X, Y, Z, model):
30
+ """Get an MCMC estimate of the z-scores of Y"""
31
+ def f(sample):
32
+ return get_single_zscores(X, Y, Z, model, sample)
33
+ return MCMC_estimate(f, model.hbr.trace)
34
+
35
+
36
+ def get_single_zscores(X, Y, Z, model, sample):
37
+ """Get the z-scores of y, given clinical covariates and a model"""
38
+ likelihood = model.configs['likelihood']
39
+ params = forward(X, Z, model, sample)
40
+ return z_score(Y, params, likelihood=likelihood)
41
+
42
+
43
+ def z_score(Y, params, likelihood="Normal"):
44
+ """Get the z-scores of Y, given likelihood parameters"""
45
+ if likelihood.startswith('SHASH'):
46
+ mu = params['mu']
47
+ sigma = params['sigma']
48
+ epsilon = params['epsilon']
49
+ delta = params['delta']
50
+ if likelihood == "SHASHo":
51
+ SHASH = (Y-mu)/sigma
52
+ Z = np.sinh(np.arcsinh(SHASH)*delta - epsilon)
53
+ elif likelihood == "SHASHo2":
54
+ sigma_d = sigma/delta
55
+ SHASH = (Y-mu)/sigma_d
56
+ Z = np.sinh(np.arcsinh(SHASH)*delta - epsilon)
57
+ elif likelihood == "SHASHb":
58
+ true_mu = m(epsilon, delta, 1)
59
+ true_sigma = np.sqrt((m(epsilon, delta, 2) - true_mu ** 2))
60
+ SHASH_c = ((Y-mu)/sigma)
61
+ SHASH = SHASH_c * true_sigma + true_mu
62
+ Z = np.sinh(np.arcsinh(SHASH) * delta - epsilon)
63
+ if likelihood == 'Normal':
64
+ Z = (Y-params['mu'])/params['sigma']
65
+ else:
66
+ exit("Unsupported likelihood")
67
+ return Z
68
+
69
+
70
+ def get_MCMC_quantiles(synthetic_X, z_scores, model, be):
71
+ """Get an MCMC estimate of the quantiles"""
72
+ """This does not use the get_single_quantiles function, for memory efficiency"""
73
+ resolution = synthetic_X.shape[0]
74
+ synthetic_X_transformed = model.hbr.transform_X(synthetic_X)
75
+ be = np.reshape(np.array(be), (1, -1))
76
+ synthetic_Z = np.repeat(be, resolution, axis=0)
77
+ z_scores = np.reshape(np.array(z_scores), (1, -1))
78
+ zs = np.repeat(z_scores, resolution, axis=0)
79
+
80
+ def f(sample):
81
+ params = forward(synthetic_X_transformed, synthetic_Z, model, sample)
82
+ q = quantile(zs, params, likelihood=model.configs['likelihood'])
83
+ return q
84
+ out = MCMC_estimate(f, model.hbr.trace)
85
+ return out
86
+
87
+
88
+ def get_single_quantiles(synthetic_X, z_scores, model, be, sample):
89
+ """Get the quantiles within a given range of covariates, given a model"""
90
+ resolution = synthetic_X.shape[0]
91
+ synthetic_X_transformed = model.hbr.transform_X(synthetic_X)
92
+ be = np.reshape(np.array(be), (1, -1))
93
+ synthetic_Z = np.repeat(be, resolution, axis=0)
94
+ z_scores = np.reshape(np.array(z_scores), (1, -1))
95
+ zs = np.repeat(z_scores, resolution, axis=0)
96
+ params = forward(synthetic_X_transformed, synthetic_Z, model, sample)
97
+ q = quantile(zs, params, likelihood=model.configs['likelihood'])
98
+ return q
99
+
100
+
101
+ def quantile(zs, params, likelihood="Normal"):
102
+ """Get the zs'th quantiles given likelihood parameters"""
103
+ if likelihood.startswith('SHASH'):
104
+ mu = params['mu']
105
+ sigma = params['sigma']
106
+ epsilon = params['epsilon']
107
+ delta = params['delta']
108
+ if likelihood == "SHASHo":
109
+ quantiles = S_inv(zs, epsilon, delta)*sigma + mu
110
+ elif likelihood == "SHASHo2":
111
+ sigma_d = sigma/delta
112
+ quantiles = S_inv(zs, epsilon, delta)*sigma_d + mu
113
+ elif likelihood == "SHASHb":
114
+ true_mu = m(epsilon, delta, 1)
115
+ true_sigma = np.sqrt((m(epsilon, delta, 2) - true_mu ** 2))
116
+ SHASH_c = ((S_inv(zs, epsilon, delta)-true_mu)/true_sigma)
117
+ quantiles = SHASH_c * sigma + mu
118
+ if likelihood == 'Normal':
119
+ quantiles = zs*params['sigma'] + params['mu']
120
+ else:
121
+ exit("Unsupported likelihood")
122
+ return quantiles
123
+
124
+
125
+ def single_parameter_forward(X, Z, model, sample, p_name):
126
+ """Get a likelihood paramameter given covariates, batch-effects and model parameters"""
127
+ outs = np.zeros(X.shape[0])[:, None]
128
+ all_bes = np.unique(Z, axis=0)
129
+ for be in all_bes:
130
+ bet = tuple(be)
131
+ idx = (Z == be).all(1)
132
+ if model.configs[f"linear_{p_name}"]:
133
+ if model.configs[f'random_slope_{p_name}']:
134
+ slope_be = sample[f"slope_{p_name}"][bet]
135
+ else:
136
+ slope_be = sample[f"slope_{p_name}"]
137
+ if model.configs[f'random_intercept_{p_name}']:
138
+ intercept_be = sample[f"intercept_{p_name}"][bet]
139
+ else:
140
+ intercept_be = sample[f"intercept_{p_name}"]
141
+
142
+ out = (X[np.squeeze(idx), :]@slope_be)[:, None] + intercept_be
143
+ outs[np.squeeze(idx), :] = out
144
+ else:
145
+ if model.configs[f'random_{p_name}']:
146
+ outs[np.squeeze(idx), :] = sample[p_name][bet]
147
+ else:
148
+ outs[np.squeeze(idx), :] = sample[p_name]
149
+
150
+ return outs
151
+
152
+
153
+ def forward(X, Z, model, sample):
154
+ """Get all likelihood paramameters given covariates and batch-effects and model parameters"""
155
+ # TODO think if this is the correct spot for this
156
+ mapfuncs = {'sigma': lambda x: np.log(
157
+ 1+np.exp(x)), 'delta': lambda x: np.log(1+np.exp(x)) + 0.3}
158
+
159
+ likelihood = model.configs['likelihood']
160
+
161
+ if likelihood == 'Normal':
162
+ parameter_list = ['mu', 'sigma']
163
+ # elif likelihood in ['SHASHb','SHASHo','SHASHo2']:
164
+ # parameter_list = ['mu','sigma','epsilon','delta']
165
+ else:
166
+ exit("Unsupported likelihood")
167
+
168
+ for i in parameter_list:
169
+ if not (i in mapfuncs.keys()):
170
+ mapfuncs[i] = lambda x: x
171
+
172
+ output_dict = {p_name: np.zeros(X.shape) for p_name in parameter_list}
173
+
174
+ for p_name in parameter_list:
175
+ output_dict[p_name] = mapfuncs[p_name](
176
+ single_parameter_forward(X, Z, model, sample, p_name))
177
+
178
+ return output_dict
179
+
180
+
181
+ def Rhats(model, thin=1, resolution=100, varnames=None):
182
+ """Get Rhat as function of sampling iteration"""
183
+ trace = model.hbr.trace
184
+
185
+ if varnames == None:
186
+ varnames = trace.varnames
187
+ chain_length = trace.get_values(
188
+ varnames[0], chains=trace.chains[0], thin=thin).shape[0]
189
+
190
+ interval_skip = chain_length//resolution
191
+
192
+ rhat_dict = {}
193
+
194
+ for varname in varnames:
195
+ testvar = np.stack(trace.get_values(varname, combine=False))
196
+ vardim = testvar.reshape(
197
+ (testvar.shape[0], testvar.shape[1], -1)).shape[2]
198
+ rhats_var = np.zeros((resolution, vardim))
199
+
200
+ var = np.stack(trace.get_values(varname, combine=False))
201
+ var = var.reshape((var.shape[0], var.shape[1], -1))
202
+ for v in range(var.shape[2]):
203
+ for j in range(resolution):
204
+ rhats_var[j, v] = pm.rhat(var[:, :j*interval_skip, v])
205
+ rhat_dict[varname] = rhats_var
206
+ return rhat_dict
207
+
208
+
209
+ def S_inv(x, e, d):
210
+ return np.sinh((np.arcsinh(x) + e) / d)
211
+
212
+
213
+ def K(p, x):
214
+ return np.array(spp.kv(p, x))
215
+
216
+
217
+ def P(q):
218
+ """
219
+ The P function as given in Jones et al.
220
+ :param q:
221
+ :return:
222
+ """
223
+ frac = np.exp(1 / 4) / np.sqrt(8 * np.pi)
224
+ K1 = K((q + 1) / 2, 1 / 4)
225
+ K2 = K((q - 1) / 2, 1 / 4)
226
+ a = (K1 + K2) * frac
227
+ return a
228
+
229
+
230
+ def m(epsilon, delta, r):
231
+ """
232
+ The r'th uncentered moment. Given by Jones et al.
233
+ """
234
+ frac1 = 1 / np.power(2, r)
235
+ acc = 0
236
+ for i in range(r + 1):
237
+ combs = spp.comb(r, i)
238
+ flip = np.power(-1, i)
239
+ ex = np.exp((r - 2 * i) * epsilon / delta)
240
+ p = P((r - 2 * i) / delta)
241
+ acc += combs * flip * ex * p
242
+ return frac1 * acc