def test_check_discrete_minibatch(self): disaster_data_t = tt.vector() disaster_data_t.tag.test_value = np.zeros(len(self.disaster_data)) def create_minibatches(): while True: return (self.disaster_data, ) with Model(): switchpoint = DiscreteUniform('switchpoint', lower=self.year.min(), upper=self.year.max(), testval=1900) # Priors for pre- and post-switch rates number of disasters early_rate = Exponential('early_rate', 1) late_rate = Exponential('late_rate', 1) # Allocate appropriate Poisson rates to years before and after current rate = tt.switch(switchpoint >= self.year, early_rate, late_rate) disasters = Poisson('disasters', rate, observed=disaster_data_t) with self.assertRaises(ValueError): advi_minibatch(n=10, minibatch_RVs=[disasters], minibatch_tensors=[disaster_data_t], minibatches=create_minibatches())
def test_check_discrete_minibatch(): disaster_data_t = tt.vector() disaster_data_t.tag.test_value = np.zeros(len(disaster_data)) with Model() as disaster_model: switchpoint = DiscreteUniform('switchpoint', lower=year.min(), upper=year.max(), testval=1900) # Priors for pre- and post-switch rates number of disasters early_rate = Exponential('early_rate', 1) late_rate = Exponential('late_rate', 1) # Allocate appropriate Poisson rates to years before and after current rate = switch(switchpoint >= year, early_rate, late_rate) disasters = Poisson('disasters', rate, observed=disaster_data_t) def create_minibatch(): while True: return (disaster_data, ) # This should raise ValueError assert_raises(ValueError, advi_minibatch, model=disaster_model, n=10, minibatch_RVs=[disasters], minibatch_tensors=[disaster_data_t], minibatches=create_minibatch(), verbose=False)
def test_check_discrete(self): with Model(): switchpoint = DiscreteUniform( 'switchpoint', lower=self.year.min(), upper=self.year.max(), testval=1900) # Priors for pre- and post-switch rates number of disasters early_rate = Exponential('early_rate', 1) late_rate = Exponential('late_rate', 1) # Allocate appropriate Poisson rates to years before and after current rate = tt.switch(switchpoint >= self.year, early_rate, late_rate) Poisson('disasters', rate, observed=self.disaster_data) # This should raise ValueError with self.assertRaises(ValueError): advi(n=10)
def test_check_discrete(): with Model() as disaster_model: switchpoint = DiscreteUniform('switchpoint', lower=year.min(), upper=year.max(), testval=1900) # Priors for pre- and post-switch rates number of disasters early_rate = Exponential('early_rate', 1) late_rate = Exponential('late_rate', 1) # Allocate appropriate Poisson rates to years before and after current rate = switch(switchpoint >= year, early_rate, late_rate) disasters = Poisson('disasters', rate, observed=disaster_data) # This should raise ValueError assert_raises(ValueError, advi, model=disaster_model, n=10)
def test_mixture_of_mixture(self): if theano.config.floatX == "float32": rtol = 1e-4 else: rtol = 1e-7 nbr = 4 with Model() as model: # mixtures components g_comp = Normal.dist(mu=Exponential("mu_g", lam=1.0, shape=nbr, transform=None), sigma=1, shape=nbr) l_comp = Lognormal.dist(mu=Exponential("mu_l", lam=1.0, shape=nbr, transform=None), sigma=1, shape=nbr) # weight vector for the mixtures g_w = Dirichlet("g_w", a=floatX(np.ones(nbr) * 0.0000001), transform=None, shape=(nbr, )) l_w = Dirichlet("l_w", a=floatX(np.ones(nbr) * 0.0000001), transform=None, shape=(nbr, )) # mixture components g_mix = Mixture.dist(w=g_w, comp_dists=g_comp) l_mix = Mixture.dist(w=l_w, comp_dists=l_comp) # mixture of mixtures mix_w = Dirichlet("mix_w", a=floatX(np.ones(2)), transform=None, shape=(2, )) mix = Mixture("mix", w=mix_w, comp_dists=[g_mix, l_mix], observed=np.exp(self.norm_x)) test_point = model.test_point def mixmixlogp(value, point): floatX = theano.config.floatX priorlogp = (st.dirichlet.logpdf( x=point["g_w"], alpha=np.ones(nbr) * 0.0000001, ).astype(floatX) + st.expon.logpdf(x=point["mu_g"]).sum(dtype=floatX) + st.dirichlet.logpdf( x=point["l_w"], alpha=np.ones(nbr) * 0.0000001, ).astype(floatX) + st.expon.logpdf(x=point["mu_l"]).sum(dtype=floatX) + st.dirichlet.logpdf( x=point["mix_w"], alpha=np.ones(2), ).astype(floatX)) complogp1 = st.norm.logpdf(x=value, loc=point["mu_g"]).astype(floatX) mixlogp1 = logsumexp(np.log(point["g_w"]).astype(floatX) + complogp1, axis=-1, keepdims=True) complogp2 = st.lognorm.logpdf(value, 1.0, 0.0, np.exp(point["mu_l"])).astype(floatX) mixlogp2 = logsumexp(np.log(point["l_w"]).astype(floatX) + complogp2, axis=-1, keepdims=True) complogp_mix = np.concatenate((mixlogp1, mixlogp2), axis=1) mixmixlogpg = logsumexp(np.log(point["mix_w"]).astype(floatX) + complogp_mix, axis=-1, keepdims=False) return priorlogp, mixmixlogpg value = np.exp(self.norm_x)[:, None] priorlogp, mixmixlogpg = mixmixlogp(value, test_point) # check logp of mixture assert_allclose(mixmixlogpg, mix.logp_elemwise(test_point), rtol=rtol) # check model logp assert_allclose(priorlogp + mixmixlogpg.sum(), model.logp(test_point), rtol=rtol) # check input and check logp again test_point["g_w"] = np.asarray([0.1, 0.1, 0.2, 0.6]) test_point["mu_g"] = np.exp(np.random.randn(nbr)) priorlogp, mixmixlogpg = mixmixlogp(value, test_point) assert_allclose(mixmixlogpg, mix.logp_elemwise(test_point), rtol=rtol) assert_allclose(priorlogp + mixmixlogpg.sum(), model.logp(test_point), rtol=rtol)
def __init__(self, ploidy_config: PloidyModelConfig, ploidy_workspace: PloidyWorkspace): super().__init__() # shorthands t_j = ploidy_workspace.t_j contig_exclusion_mask_jj = ploidy_workspace.contig_exclusion_mask_jj n_s = ploidy_workspace.n_s n_sj = ploidy_workspace.n_sj ploidy_k = ploidy_workspace.int_ploidy_values_k q_ploidy_sjk = tt.exp(ploidy_workspace.log_q_ploidy_sjk) eps_mapping = ploidy_config.mapping_error_rate register_as_global = self.register_as_global register_as_sample_specific = self.register_as_sample_specific # mean per-contig bias mean_bias_j = self.PositiveNormal('mean_bias_j', mu=1.0, sd=ploidy_config.mean_bias_sd, shape=(ploidy_workspace.num_contigs,)) register_as_global(mean_bias_j) # contig coverage unexplained variance psi_j = Exponential(name='psi_j', lam=1.0 / ploidy_config.psi_j_scale, shape=(ploidy_workspace.num_contigs,)) register_as_global(psi_j) # sample-specific contig unexplained variance psi_s = Exponential(name='psi_s', lam=1.0 / ploidy_config.psi_s_scale, shape=(ploidy_workspace.num_samples,)) register_as_sample_specific(psi_s, sample_axis=0) # convert "unexplained variance" to negative binomial over-dispersion alpha_sj = tt.maximum(tt.inv((tt.exp(psi_j.dimshuffle('x', 0) + psi_s.dimshuffle(0, 'x')) - 1.0)), _eps) # mean ploidy per contig per sample mean_ploidy_sj = tt.sum(tt.exp(ploidy_workspace.log_q_ploidy_sjk) * ploidy_workspace.int_ploidy_values_k.dimshuffle('x', 'x', 0), axis=2) # mean-field amplification coefficient per contig gamma_sj = mean_ploidy_sj * t_j.dimshuffle('x', 0) * mean_bias_j.dimshuffle('x', 0) # gamma_rest_sj \equiv sum_{j' \neq j} gamma_sj gamma_rest_sj = tt.dot(gamma_sj, contig_exclusion_mask_jj) # NB per-contig counts mu_num_sjk = (t_j.dimshuffle('x', 0, 'x') * mean_bias_j.dimshuffle('x', 0, 'x') * ploidy_k.dimshuffle('x', 'x', 0)) mu_den_sjk = gamma_rest_sj.dimshuffle(0, 1, 'x') + mu_num_sjk eps_mapping_j = eps_mapping * t_j / tt.sum(t_j) # average number of reads erroneously mapped to contig j # the switch is required for a single contig edge case mu_ratio_sjk = tt.switch(tt.eq(mu_den_sjk, 0.0), 0.0, mu_num_sjk / mu_den_sjk) mu_sjk = ((1.0 - eps_mapping) * mu_ratio_sjk + eps_mapping_j.dimshuffle('x', 0, 'x')) * n_s.dimshuffle(0, 'x', 'x') def _get_logp_sjk(_n_sj): _logp_sjk = commons.negative_binomial_logp( mu_sjk, # mean alpha_sj.dimshuffle(0, 1, 'x'), # over-dispersion _n_sj.dimshuffle(0, 1, 'x')) # contig counts return _logp_sjk DensityDist(name='n_sj_obs', logp=lambda _n_sj: tt.sum(q_ploidy_sjk * _get_logp_sjk(_n_sj)), observed=n_sj) # for log ploidy emission sampling Deterministic(name='logp_sjk', var=_get_logp_sjk(n_sj))
####################################### # Model definition # MEASURE = exp(ALPHA)*exp(BETA)**log(X) # mu = log(MEASURE) = ALPHA+BETA*log(X) ####################################### with Model() as cost_model: # Priors for unknown cost model parameters ALPHA = Normal('ALPHA', mu=0, sigma=1000) BETA = Normal('BETA', mu=0, sigma=1000, shape=len(ATT)) SIGMA = HalfNormal('SIGMA', sigma=100) # Model MU = ALPHA + dot(X_INPUT, BETA) NU = Deterministic('NU', Exponential('nu_', 1 / 29)) # Likelihood (sampling distribution) of observations # Y_OBS = Normal('Y_OBS', mu=mu, sigma=sigma, observed=Y_OUTPUT) Y_OBS = StudentT('Y_OBS', mu=MU, sigma=SIGMA, observed=Y_OUTPUT, nu=NU) with cost_model: TRACE = sample(SAMPLES, tune=TUNE, cores=6) traceplot(TRACE) with cost_model: Y_PRED = sample_posterior_predictive(TRACE, 1000, cost_model) Y_ = Y_PRED['Y_OBS'].mean(axis=0) PP['model_cost'] = exp(Y_) # depends on imput/output SUMMARY = df_summary(TRACE)
# plot the pulled data! returns.plot() #figsize=(10, 6)) plt.ylabel('daily returns in %') # define the model # \sig ~ exp(50) # why? stdev of returns is approx 0.02 # stdev of exp(lam=50) = 0.2 # \nu ~ exp(0.1) # the DOF for the student T...which should be sample size # mean of exp(lam=0.1) = 10 # s_i ~ normal(s_i-1, \sig^-2) # log(y_i) ~ studentT(\nu, 0, exp(-2s_i)) with Model() as sp500_model: nu = Exponential('nu', 1. / 10, testval=5.) #50, testval=5.)#results similar... sigma = Exponential('sigma', 1. / .02, testval=.1) s = GaussianRandomWalk('s', sigma**-2, shape=len(returns)) volatility_process = Deterministic('volatility_process', exp(-2 * s)) r = StudentT('r', nu, lam=1 / volatility_process, observed=returns) # fit the model using NUTS # NUTS is auto-assigned in sample()...why? # you may get an error like: # WARNING (theano.gof.compilelock): Overriding existing lock by dead process '10876' (I am process '3456') # ignore it...the process will move along with sp500_model: trace = sample(2000, progressbar=False) # plot results from model fitting... # is there a practical reason for starting the plot from 200th sample traceplot(trace[200:], [nu, sigma])
import matplotlib.pyplot as plt import numpy as np import pandas as pd returns= pd.read_csv("https://raw.githubusercontent.com/pymc-devs/pymc3/master/pymc3/examples/data/SP500.csv", header=-1, parse_dates=True)[2500:2900] #plt.style.use('ggplot') #returns.columns =['S&P500'] #returns.plot(figsize=(12,7), c="b") #plt.show() from pymc3 import Exponential, T, exp, Deterministic, Model, sample, NUTS, find_MAP, traceplot from pymc3.distributions.timeseries import GaussianRandomWalk with Model() as sp500_model: nu = Exponential('nu', 1./10, testval=5.) sigma = Exponential('sigma', 1./.02, testval=.1) s = GaussianRandomWalk('s', sigma**-2, shape=len(returns)) volatility_process = Deterministic('volatility_process', exp(-2*s)) r = T('r', nu, lam=1/volatility_process, observed=returns['S&P500'])
def test_mixture_of_mixture(self): nbr = 4 with Model() as model: # mixtures components g_comp = Normal.dist(mu=Exponential('mu_g', lam=1.0, shape=nbr, transform=None), sigma=1, shape=nbr) l_comp = Lognormal.dist(mu=Exponential('mu_l', lam=1.0, shape=nbr, transform=None), sigma=1, shape=nbr) # weight vector for the mixtures g_w = Dirichlet('g_w', a=floatX(np.ones(nbr) * 0.0000001), transform=None) l_w = Dirichlet('l_w', a=floatX(np.ones(nbr) * 0.0000001), transform=None) # mixture components g_mix = Mixture.dist(w=g_w, comp_dists=g_comp) l_mix = Mixture.dist(w=l_w, comp_dists=l_comp) # mixture of mixtures mix_w = Dirichlet('mix_w', a=floatX(np.ones(2)), transform=None) mix = Mixture('mix', w=mix_w, comp_dists=[g_mix, l_mix], observed=np.exp(self.norm_x)) test_point = model.test_point def mixmixlogp(value, point): priorlogp = st.dirichlet.logpdf(x=point['g_w'], alpha=np.ones(nbr)*0.0000001, ) + \ st.expon.logpdf(x=point['mu_g']).sum() + \ st.dirichlet.logpdf(x=point['l_w'], alpha=np.ones(nbr)*0.0000001, ) + \ st.expon.logpdf(x=point['mu_l']).sum() + \ st.dirichlet.logpdf(x=point['mix_w'], alpha=np.ones(2), ) complogp1 = st.norm.logpdf(x=value, loc=point['mu_g']) mixlogp1 = logsumexp(np.log(point['g_w']) + complogp1, axis=-1, keepdims=True) complogp2 = st.lognorm.logpdf(value, 1., 0., np.exp(point['mu_l'])) mixlogp2 = logsumexp(np.log(point['l_w']) + complogp2, axis=-1, keepdims=True) complogp_mix = np.concatenate((mixlogp1, mixlogp2), axis=1) mixmixlogpg = logsumexp(np.log(point['mix_w']) + complogp_mix, axis=-1, keepdims=True) return priorlogp, mixmixlogpg value = np.exp(self.norm_x)[:, None] priorlogp, mixmixlogpg = mixmixlogp(value, test_point) # check logp of mixture assert_allclose(mixmixlogpg, mix.logp_elemwise(test_point)) # check model logp assert_allclose(priorlogp + mixmixlogpg.sum(), model.logp(test_point)) # check input and check logp again test_point['g_w'] = np.asarray([.1, .1, .2, .6]) test_point['mu_g'] = np.exp(np.random.randn(nbr)) priorlogp, mixmixlogpg = mixmixlogp(value, test_point) assert_allclose(mixmixlogpg, mix.logp_elemwise(test_point)) assert_allclose(priorlogp + mixmixlogpg.sum(), model.logp(test_point))
plt.ylabel("Disaster count") plt.xlabel("Year") plt.show() from pymc3 import DiscreteUniform, Poisson, switch, Model, Exponential, NUTS, Metropolis, sample, traceplot with Model() as disaster_model: switchpoint = DiscreteUniform('switchpoint', lower=year.min(), upper=year.max(), testval=1900) # Priors for pre- and post-switch rates number of disasters early_rate = Exponential('early_rate', 1) late_rate = Exponential('late_rate', 1) # Allocate appropriate Poisson rates to years before and after current rate = switch(switchpoint >= year, early_rate, late_rate) disasters = Poisson('disasters', rate, observed=disaster_data) step1 = NUTS([early_rate, late_rate]) # Use Metropolis for switchpoint, and missing values since it accommodates discrete variables step2 = Metropolis([switchpoint, disasters.missing_values[0]]) trace = sample(10000, step=[step1, step2]) traceplot(trace)
def __init__(self, ploidy_config: PloidyModelConfig, ploidy_workspace: PloidyWorkspace): super().__init__() # shorthands t_j = ploidy_workspace.t_j contig_exclusion_mask_jj = ploidy_workspace.contig_exclusion_mask_jj n_s = ploidy_workspace.n_s n_sj = ploidy_workspace.n_sj ploidy_k = ploidy_workspace.int_ploidy_values_k q_ploidy_sjk = tt.exp(ploidy_workspace.log_q_ploidy_sjk) eps = ploidy_config.mapping_error_rate register_as_global = self.register_as_global register_as_sample_specific = self.register_as_sample_specific # mean per-contig bias mean_bias_j = self.PositiveNormal('mean_bias_j', mu=1.0, sd=ploidy_config.mean_bias_sd, shape=(ploidy_workspace.num_contigs,)) register_as_global(mean_bias_j) # contig coverage unexplained variance psi_j = Exponential(name='psi_j', lam=1.0 / ploidy_config.psi_j_scale, shape=(ploidy_workspace.num_contigs,)) register_as_global(psi_j) # sample-specific contig unexplained variance psi_s = Exponential(name='psi_s', lam=1.0 / ploidy_config.psi_j_scale, shape=(ploidy_workspace.num_samples,)) register_as_sample_specific(psi_s, sample_axis=0) # convert "unexplained variance" to negative binomial over-dispersion alpha_sj = tt.inv((tt.exp(psi_j.dimshuffle('x', 0) + psi_s.dimshuffle(0, 'x')) - 1.0)) # mean ploidy per contig per sample mean_ploidy_sj = tt.sum(tt.exp(ploidy_workspace.log_q_ploidy_sjk) * ploidy_workspace.int_ploidy_values_k.dimshuffle('x', 'x', 0), axis=2) # mean-field amplification coefficient per contig gamma_sj = mean_ploidy_sj * t_j.dimshuffle('x', 0) * mean_bias_j.dimshuffle('x', 0) # gamma_rest_sj \equiv sum_{j' \neq j} gamma_sj gamma_rest_sj = tt.dot(gamma_sj, contig_exclusion_mask_jj) # NB per-contig counts mu_num_sjk = (t_j.dimshuffle('x', 0, 'x') * mean_bias_j.dimshuffle('x', 0, 'x') * ploidy_k.dimshuffle('x', 'x', 0)) mu_den_sjk = gamma_rest_sj.dimshuffle(0, 1, 'x') + mu_num_sjk eps_j = eps * t_j / tt.sum(t_j) # average number of reads erroneously mapped to contig j mu_sjk = ((1.0 - eps) * (mu_num_sjk / mu_den_sjk) + eps_j.dimshuffle('x', 0, 'x')) * n_s.dimshuffle(0, 'x', 'x') def _get_logp_sjk(_n_sj): _logp_sjk = commons.negative_binomial_logp( mu_sjk, # mean alpha_sj.dimshuffle(0, 1, 'x'), # over-dispersion _n_sj.dimshuffle(0, 1, 'x')) # contig counts return _logp_sjk DensityDist(name='n_sj_obs', logp=lambda _n_sj: tt.sum(q_ploidy_sjk * _get_logp_sjk(_n_sj)), observed=n_sj) # for log ploidy emission sampling Deterministic(name='logp_sjk', var=_get_logp_sjk(n_sj))
def mcmc_changepoint(dates, ratings, mcmc_iter=1000, discrete=0, plot_result=1): """This function models Yelp reviews as coming from two normal distributions with a switch point somewhere between them. When left of the switch point then reviews are drawn from the first normal distribution. To the right of the switch point reviews are drawn from the second normal distribution. Normal distributions are used if the reviews have been normalized to the user's average rating; otherwise if analyzing in terms of 1-5 stars set discrete=1 and the function will do the same estimation on Poisson distributions. This function then finds the most likely distribution for where the switchpoint is and the most likely parameters for the two generator distributions by using Metropolis-Hastings sampling and Hamiltonian Monte Carlo.""" # dates: Array of dates when the reviews were posted # ratings: Array of the ratings given by each review # mcmc_iter: How many iterations of the MCMC to run? # discrete: Should I use Normal or Poisson distributions to model the ratings? # (i.e. are the user-averaged or 1-5 stars) # plot_result: Should the function output a plot? number_of_ratings = np.arange(0, len(ratings)) if discrete == 0: with Model() as switch_model: switchpoint = DiscreteUniform('switchpoint', lower=0, upper=len(dates)) before_intensity = Normal('before_intensity', mu=0, sd=1) after_intensity = Normal('after_intensity', mu=0, sd=1) intensity = switch(switchpoint >= number_of_ratings, before_intensity, after_intensity) sigma = HalfNormal('sigma', sd=1) rating = Normal('rating', mu=intensity, sd=sigma, observed=ratings) elif discrete == 1: with Model() as switch_model: switchpoint = DiscreteUniform('switchpoint', lower=0, upper=len(dates)) before_intensity = Exponential('before_intensity', 1) after_intensity = Exponential('after_intensity', 1) intensity = switch(switchpoint >= number_of_ratings, before_intensity, after_intensity) rating = Poisson('rating', intensity, observed=ratings) with switch_model: trace = sample(mcmc_iter) if plot_result == 1: traceplot(trace) plt.show() switch_posterior = trace['switchpoint'] N_MCs = switch_posterior.shape[0] before_intensity_posterior = trace['before_intensity'] after_intensity_posterior = trace['after_intensity'] expected_stars = np.zeros(len(ratings)) for a_rating in number_of_ratings: where_switch = a_rating < switch_posterior expected_stars[a_rating] = ( before_intensity_posterior[where_switch].sum() + after_intensity_posterior[~where_switch].sum()) / N_MCs if plot_result == 1: plt.plot(dates, ratings, 'o') plt.plot(dates, expected_stars, 'b-') plt.show() # Return the mode and it's frequency / mcmc_iter b_mean, b_count = scipy.stats.mode(trace['before_intensity']) a_mean, a_count = scipy.stats.mode(trace['after_intensity']) modal_switch, count = scipy.stats.mode(trace['switchpoint']) sigma_est, sigma_count = scipy.stats.mode(trace['sigma']) differential = b_mean - a_mean return differential, modal_switch, expected_stars, sigma_est, switch_posterior
X = log(PP[ATT]).copy() X = X X_INPUT = shared(X.values) # numpy array Y = log(PP[MEASURE]).copy() Y_OUTPUT = shared(Y.values) # numpy array ######################################## # Model definition # MEASURE = exp(ALPHA)*X**BETA # Log(MEASURE) = ALPHA+BETA*log(X) ######################################## with Model() as cost_model: # Priors for unknown cost model parameters ALPHA = Exponential('ALPHA', 0.1) BETA = Normal('BETA', mu=0.0, sigma=1, shape=len(ATT)) SIGMA = HalfNormal('SIGMA', sigma=1) # Model MU = ALPHA + dot(X, BETA) # Likelihood (sampling distribution) of observations Y_OBS = Normal('Y_OBS', mu=MU, sigma=SIGMA, observed=Y_OUTPUT) with cost_model: TRACE = sample(SAMPLES, tune=TUNE, cores=6) traceplot(TRACE) with cost_model: Y_PRED = sample_posterior_predictive(TRACE, 1000, cost_model)