Exemplo n.º 1
0
    def test_scalar_ode_1_param(self):
        """Test running model for a scalar ODE with 1 parameter"""

        def system(y, t, p):
            return np.exp(-t) - p[0] * y[0]

        times = np.array(
            [0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5]
        )

        yobs = np.array(
            [0.31, 0.57, 0.51, 0.55, 0.47, 0.42, 0.38, 0.3, 0.26, 0.22, 0.22, 0.14, 0.14, 0.09, 0.1]
        )[:, np.newaxis]

        ode_model = DifferentialEquation(func=system, t0=0, times=times, n_states=1, n_theta=1)

        with pm.Model() as model:
            alpha = pm.HalfCauchy("alpha", 1)
            y0 = pm.LogNormal("y0", 0, 1)
            sigma = pm.HalfCauchy("sigma", 1)
            forward = ode_model(theta=[alpha], y0=[y0])
            y = pm.LogNormal("y", mu=pm.math.log(forward), sigma=sigma, observed=yobs)

            with aesara.config.change_flags(mode=fast_unstable_sampling_mode):
                idata = pm.sample(50, tune=0, chains=1)

        assert idata.posterior["alpha"].shape == (1, 50)
        assert idata.posterior["y0"].shape == (1, 50)
        assert idata.posterior["sigma"].shape == (1, 50)
Exemplo n.º 2
0
    def test_scalar_ode_2_param(self):
        """Test running model for a scalar ODE with 2 parameters"""

        def system(y, t, p):
            return p[0] * np.exp(-p[0] * t) - p[1] * y[0]

        times = np.array(
            [0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5]
        )

        yobs = np.array(
            [0.31, 0.57, 0.51, 0.55, 0.47, 0.42, 0.38, 0.3, 0.26, 0.22, 0.22, 0.14, 0.14, 0.09, 0.1]
        )[:, np.newaxis]

        ode_model = DifferentialEquation(func=system, t0=0, times=times, n_states=1, n_theta=2)

        with pm.Model() as model:
            alpha = pm.HalfCauchy("alpha", 1)
            beta = pm.HalfCauchy("beta", 1)
            y0 = pm.LogNormal("y0", 0, 1)
            sigma = pm.HalfCauchy("sigma", 1)
            forward = ode_model(theta=[alpha, beta], y0=[y0])
            y = pm.LogNormal("y", mu=pm.math.log(forward), sd=sigma, observed=yobs)

            idata = pm.sample(100, tune=0, chains=1)

        assert idata.posterior["alpha"].shape == (1, 100)
        assert idata.posterior["beta"].shape == (1, 100)
        assert idata.posterior["y0"].shape == (1, 100)
        assert idata.posterior["sigma"].shape == (1, 100)
    def setup_inference_mixture(self):
        #depending on the number of wavelengths
        #self.wavelengths = [self.wavelengths[len(self.wavelengths)-1]]
        wavelength_number = len(self.wavelengths)
        
        t = 1. / 2.5**2
        C_sigs = pymc.Container([pymc.HalfCauchy("c_sigs_%i_%i" % (i, x), beta = 10, alpha=1)                                  for i in range(1+2*self.N) for x in range(wavelength_number)])
        C = pymc.Container([pymc.Normal("c_%i_%i" % (i, x), mu=0, tau = 1. / C_sigs[i*wavelength_number+x]**2)                             for i in range(1+2*self.N) for x in range(wavelength_number)])
        i_ = pymc.Container([pymc.DiscreteUniform('i_%i' %i,lower=0,upper=1) for i in range(len(self.xdata))])
        @pymc.stochastic(observed=False)
        def sigma(value=1):
            return -np.log(abs(value))
        @pymc.stochastic(observed=False)
        def sigma3(value=1):
            return -np.log(abs(value))
        
        qw_sigs =  pymc.Container([pymc.HalfCauchy("qw_sigs_%i" % x, beta = 10, alpha=1)                                  for x in range(wavelength_number)])
        if self.wavelength_sd_defined:
            qw = pymc.Container([pymc.distributions.Lognormal('qw_%i' %x,mu=self.wavelengths[x],                                                        tau = 1. / self.wavelength_sd[x] ** 2)                                  for x in range(wavelength_number)])
        else:
            qw = pymc.Container([pymc.distributions.Uniform('qw_%i' %x,lower=0., upper=self.wavelengths[x]*2)                                                        for x in range(wavelength_number)])


        def fourier_series(C,N,QW,x,wavelength_number,i_):
            v = np.array(x)
            v.fill(0.0)
            v = v.astype('float')
            for ii in range(len(x)):
                for w in range(wavelength_number):
                    v += C[w]
                    for i in range(1,N+1):
                        v[ii] = v[ii] + C[(2*i-1)*wavelength_number+w]*np.cos(2*np.pi/QW[w] * i * (x[ii])) +                         C[(2*i)*wavelength_number+w]*np.sin(2*np.pi/QW[w] * i * (x[ii]))
                #if i_[ii] == 0:
                #    v[ii] = -v[ii]
            return v#np.sum(v)
        self.vector_fourier_series = np.vectorize(fourier_series)
        # Define the form of the model and likelihood
        @pymc.deterministic
        def y_model(C=C,x=self.xdata,qw=qw,nn=self.N,wavelength_number=wavelength_number,i_=i_):
            return fourier_series(C,nn,qw,x,wavelength_number,i_) 
        y = pymc.Normal('y', mu=y_model, tau=1. / sigma ** 2, observed=True, value=self.ydata)
        # package the full model in a dictionary
        self.model1 = dict(C=C, qw=qw, sigma=sigma,qw_sigs=qw_sigs,
                      y_model=y_model, y=y,x_values=self.xdata,y_values=self.ydata,i_=i_)
        self.setup = True
        self.mcmc_uptodate = False
        return self.model1
Exemplo n.º 4
0
    def test_vector_ode_2_param(self):
        """Test running model for a vector ODE with 2 parameters"""
        def system(y, t, p):
            ds = -p[0] * y[0] * y[1]
            di = p[0] * y[0] * y[1] - p[1] * y[1]
            return [ds, di]

        times = np.array(
            [0.0, 0.8, 1.6, 2.4, 3.2, 4.0, 4.8, 5.6, 6.4, 7.2, 8.0])

        yobs = np.array([
            [1.02, 0.02],
            [0.86, 0.12],
            [0.43, 0.37],
            [0.14, 0.42],
            [0.05, 0.43],
            [0.03, 0.14],
            [0.02, 0.08],
            [0.02, 0.04],
            [0.02, 0.01],
            [0.02, 0.01],
            [0.02, 0.01],
        ])

        ode_model = DifferentialEquation(func=system,
                                         t0=0,
                                         times=times,
                                         n_states=2,
                                         n_theta=2)

        with pm.Model() as model:
            beta = pm.HalfCauchy("beta", 1, initval=1)
            gamma = pm.HalfCauchy("gamma", 1, initval=1)
            sigma = pm.HalfCauchy("sigma", 1, shape=2, initval=[1, 1])
            forward = ode_model(theta=[beta, gamma], y0=[0.99, 0.01])
            y = pm.LogNormal("y",
                             mu=pm.math.log(forward),
                             sigma=sigma,
                             observed=yobs)

            with aesara.config.change_flags(mode=fast_unstable_sampling_mode):
                idata = pm.sample(50, tune=0, chains=1)

        assert idata.posterior["beta"].shape == (1, 50)
        assert idata.posterior["gamma"].shape == (1, 50)
        assert idata.posterior["sigma"].shape == (1, 50, 2)
Exemplo n.º 5
0
def radon_model():
    """Similar in shape to the Radon model"""
    n_homes = 919
    counties = 85
    uranium = np.random.normal(-0.1, 0.4, size=n_homes)
    xbar = np.random.normal(1, 0.1, size=n_homes)
    floor_measure = np.random.randint(0, 2, size=n_homes)

    d, r = divmod(919, 85)
    county = np.hstack((np.tile(np.arange(counties, dtype=int),
                                d), np.arange(r)))
    with pm.Model() as model:
        sigma_a = pm.HalfCauchy("sigma_a", 5)
        gamma = pm.Normal("gamma", mu=0.0, sigma=1e5, shape=3)
        mu_a = pm.Deterministic(
            "mu_a", gamma[0] + gamma[1] * uranium + gamma[2] * xbar)
        eps_a = pm.Normal("eps_a", mu=0, sigma=sigma_a, shape=counties)
        a = pm.Deterministic("a", mu_a + eps_a[county])
        b = pm.Normal("b", mu=0.0, sigma=1e15)
        sigma_y = pm.Uniform("sigma_y", lower=0, upper=100)

        # Anonymous SharedVariables don't show up
        floor_measure = aesara.shared(floor_measure)
        floor_measure_offset = pm.MutableData("floor_measure_offset", 1)
        y_hat = a + b * floor_measure + floor_measure_offset
        log_radon = pm.MutableData("log_radon",
                                   np.random.normal(1, 1, size=n_homes))
        y_like = pm.Normal("y_like",
                           mu=y_hat,
                           sigma=sigma_y,
                           observed=log_radon)

    compute_graph = {
        # variable_name : set of named parents in the graph
        "sigma_a": set(),
        "gamma": set(),
        "mu_a": {"gamma"},
        "eps_a": {"sigma_a"},
        "a": {"mu_a", "eps_a"},
        "b": set(),
        "sigma_y": set(),
        "y_like": {"a", "b", "sigma_y", "floor_measure_offset"},
        "floor_measure_offset": set(),
        # observed data don't have parents in the model graph, but are shown as decendants
        # of the model variables that the observations belong to:
        "log_radon": {"y_like"},
    }
    plates = {
        "": {"b", "sigma_a", "sigma_y", "floor_measure_offset"},
        "3": {"gamma"},
        "85": {"eps_a"},
        "919": {"a", "mu_a", "y_like", "log_radon"},
    }
    return model, compute_graph, plates
Exemplo n.º 6
0
def glm_hierarchical_model(random_seed=123):
    """Sample glm hierarchical model to use in benchmarks"""
    np.random.seed(random_seed)
    data = pd.read_csv(pm.get_data("radon.csv"))
    data["log_radon"] = data["log_radon"].astype(aesara.config.floatX)
    county_idx = data.county_code.values

    n_counties = len(data.county.unique())
    with pm.Model() as model:
        mu_a = pm.Normal("mu_a", mu=0.0, sd=100**2)
        sigma_a = pm.HalfCauchy("sigma_a", 5)
        mu_b = pm.Normal("mu_b", mu=0.0, sd=100**2)
        sigma_b = pm.HalfCauchy("sigma_b", 5)
        a = pm.Normal("a", mu=0, sd=1, shape=n_counties)
        b = pm.Normal("b", mu=0, sd=1, shape=n_counties)
        a = mu_a + sigma_a * a
        b = mu_b + sigma_b * b
        eps = pm.HalfCauchy("eps", 5)
        radon_est = a[county_idx] + b[county_idx] * data.floor.values
        pm.Normal("radon_like", mu=radon_est, sd=eps, observed=data.log_radon)
    return model
Exemplo n.º 7
0
    def data(self, eight_schools_params, draws, chains):
        with pm.Model() as model:
            mu = pm.Normal("mu", mu=0, sd=5)
            tau = pm.HalfCauchy("tau", beta=5)
            eta = pm.Normal("eta", mu=0, sd=1, size=eight_schools_params["J"])
            theta = pm.Deterministic("theta", mu + tau * eta)
            pm.Normal(
                "obs",
                mu=theta,
                sd=eight_schools_params["sigma"],
                observed=eight_schools_params["y"],
            )
            trace = pm.sample(draws, chains=chains, return_inferencedata=False)

        return self.Data(model, trace)
Exemplo n.º 8
0
    def track_1var_2par_ode_ess(self):
        def freefall(y, t, p):
            return 2.0 * p[1] - p[0] * y[0]

        # Times for observation
        times = np.arange(0, 10, 0.5)
        y = np.array([
            -2.01,
            9.49,
            15.58,
            16.57,
            27.58,
            32.26,
            35.13,
            38.07,
            37.36,
            38.83,
            44.86,
            43.58,
            44.59,
            42.75,
            46.9,
            49.32,
            44.06,
            49.86,
            46.48,
            48.18,
        ]).reshape(-1, 1)

        ode_model = pm.ode.DifferentialEquation(func=freefall,
                                                times=times,
                                                n_states=1,
                                                n_theta=2,
                                                t0=0)
        with pm.Model() as model:
            # Specify prior distributions for some of our model parameters
            sigma = pm.HalfCauchy("sigma", 1)
            gamma = pm.LogNormal("gamma", 0, 1)
            # If we know one of the parameter values, we can simply pass the value.
            ode_solution = ode_model(y0=[0], theta=[gamma, 9.8])
            # The ode_solution has a shape of (n_times, n_states)
            Y = pm.Normal("Y", mu=ode_solution, sd=sigma, observed=y)

            t0 = time.time()
            idata = pm.sample(500, tune=1000, chains=2, cores=2, random_seed=0)
            tot = time.time() - t0
        ess = az.ess(idata)
        return np.mean([ess.sigma, ess.gamma]) / tot
Exemplo n.º 9
0
    def test_edge_case(self):
        # Edge case discovered in #2948
        ndim = 3
        with pm.Model() as m:
            pm.LogNormal("sigma",
                         mu=np.zeros(ndim),
                         tau=np.ones(ndim),
                         shape=ndim)  # variance for the correlation matrix
            pm.HalfCauchy("nu", beta=10)
            step = pm.NUTS()

        func = step._logp_dlogp_func
        func.set_extra_values(m.initial_point)
        q = func.dict_to_array(m.initial_point)
        logp, dlogp = func(q)
        assert logp.size == 1
        assert dlogp.size == 4
        npt.assert_allclose(dlogp, 0.0, atol=1e-5)
Exemplo n.º 10
0
    def test_vector_ode_1_param(self):
        """Test running model for a vector ODE with 1 parameter"""
        def system(y, t, p):
            ds = -p[0] * y[0] * y[1]
            di = p[0] * y[0] * y[1] - y[1]
            return [ds, di]

        times = np.array(
            [0.0, 0.8, 1.6, 2.4, 3.2, 4.0, 4.8, 5.6, 6.4, 7.2, 8.0])

        yobs = np.array([
            [1.02, 0.02],
            [0.86, 0.12],
            [0.43, 0.37],
            [0.14, 0.42],
            [0.05, 0.43],
            [0.03, 0.14],
            [0.02, 0.08],
            [0.02, 0.04],
            [0.02, 0.01],
            [0.02, 0.01],
            [0.02, 0.01],
        ])

        ode_model = DifferentialEquation(func=system,
                                         t0=0,
                                         times=times,
                                         n_states=2,
                                         n_theta=1)

        with pm.Model() as model:
            R = pm.LogNormal("R", 1, 5, initval=1)
            sigma = pm.HalfCauchy("sigma", 1, shape=2, initval=[0.5, 0.5])
            forward = ode_model(theta=[R], y0=[0.99, 0.01])
            y = pm.LogNormal("y",
                             mu=pm.math.log(forward),
                             sd=sigma,
                             observed=yobs)

            idata = pm.sample(100, tune=0, chains=1)

        assert idata.posterior["R"].shape == (1, 100)
        assert idata.posterior["sigma"].shape == (1, 100, 2)
Exemplo n.º 11
0
def make_poisson_hmm(y_data, X_data, initial_params):
    r""" Construct a PyMC2 scalar poisson-emmisions HMM model.

    TODO: Update to match normal model design.

    The model takes the following form:

    .. math::

        y_t &\sim \operatorname{Poisson}(\exp(x_t^{(S_t)\top} \beta^{(S_t)})) \\
        \beta^{(S_t)}_i &\sim \operatorname{N}(m^{(S_t)}, C^{(S_t)}),
        \quad i \in \{1,\dots,M\} \\
        S_t \mid S_{t-1} &\sim \operatorname{Categorical}(\pi^{(S_{t-1})}) \\
        \pi^{(S_t-1)} &\sim \operatorname{Dirichlet}(\alpha^{(S_{t-1})})

    where :math:`C^{(S_t)} = \lambda_i^{(S_t) 2} \tau^{(S_t) 2}` and

    .. math::

        \lambda^{(S_t)}_i &\sim \operatorname{Cauchy}^{+}(0, 1) \\
        \tau^{(S_t)} &\sim \operatorname{Cauchy}^{+}(0, 1)

    for observations :math:`y_t` in :math:`t \in \{0, \dots, T\}`,
    features :math:`x_t^{(S_t)} \in \mathbb{R}^M`,
    regression parameters :math:`\beta^{(S_t)}`, state sequences
    :math:`\{S_t\}^T_{t=1}` and
    state transition probabilities :math:`\pi \in [0, 1]^{K}`.
    :math:`\operatorname{Cauchy}^{+}` is the standard half-Cauchy distribution
    and :math:`\operatorname{N}` is the normal/Gaussian distribution.

    The set of random variables,
    :math:`\mathcal{S} = \{\{\beta^{(k)}, \lambda^{(k)}, \tau^{(k)}, \tau^{(k)}, \pi^{(k)}\}_{k=1}^K, \{S_t\}^T_{t=1}\}`,
    are referred to as "stochastics" throughout the code.


    Parameters
    ==========
    y_data: pandas.DataFrame
        Usage/response observations :math:`y_t`.
    X_data: list of pandas.DataFrame
        List of design matrices for each state, i.e. :math:`x_t^{(S_t)}`.  Each
        must span the entire length of observations (i.e. `y_data`).
    initial_params: NormalHMMInitialParams
        The initial parameters, which include
        :math:`\pi_0, m^{(k)}, \alpha^{(k)}, V^{(k)}`.
        Ignores `V` parameters.
        FIXME: using the "Normal" initial params objects is only temporary.

    Returns
    =======
    A ``pymc.Model`` object used for sampling.
    """

    N_states = len(X_data)
    N_obs = X_data[0].shape[0]

    alpha_trans = initial_params.alpha_trans

    trans_mat = TransProbMatrix("trans_mat",
                                alpha_trans,
                                value=initial_params.trans_mat)

    states = HMMStateSeq("states",
                         trans_mat,
                         N_obs,
                         p0=initial_params.p0,
                         value=initial_params.states)

    betas = []
    etas = []
    lambdas = []
    for s in range(N_states):

        initial_beta = None
        if initial_params.betas is not None:
            initial_beta = initial_params.betas[s]

        size_s = X_data[s].shape[1]
        size_s = size_s if size_s > 1 else None

        lambda_s = pymc.HalfCauchy('lambda-{}'.format(s), 0., 1., size=size_s)

        eta_s = pymc.HalfCauchy('tau-{}'.format(s), 0., 1.)

        beta_s = pymc.Normal('beta-{}'.format(s),
                             0., (lambda_s * eta_s)**(-2),
                             value=initial_beta,
                             size=size_s)

        betas += [beta_s]
        etas += [eta_s]
        lambdas += [lambda_s]

    mu_reg = HMMLinearCombination('mu', X_data, betas, states, trace=False)

    @pymc.deterministic(trace=True, plot=False)
    def mu(mu_reg_=mu_reg):
        return np.exp(mu_reg_)

    if y_data is not None:
        y_data = np.ma.masked_invalid(y_data).astype(np.object)
        y_data.set_fill_value(None)

    y_rv = pymc.Poisson('y',
                        mu,
                        value=y_data,
                        observed=True if y_data is not None else False)

    del initial_params, s, beta_s, size_s, lambda_s, eta_s

    return pymc.Model(locals())
Exemplo n.º 12
0
def make_normal_hmm(y_data,
                    X_data,
                    initial_params=None,
                    single_obs_var=False,
                    include_ppy=False):
    r""" Construct a PyMC2 scalar normal-emmisions HMM model of the form

    .. math::

        y_t &\sim \operatorname{N}^{+}(x_t^{(S_t)\top} \beta^{(S_t)}, V^{(S_t)}) \\
        \beta^{(S_t)}_i &\sim \operatorname{N}(m^{(S_t)}, C^{(S_t)}),
        \quad i \in \{1,\dots, M\} \\
        S_t \mid S_{t-1} &\sim \operatorname{Categorical}(\pi^{(S_{t-1})}) \\
        \pi^{(S_t-1)} &\sim \operatorname{Dirichlet}(\alpha^{(S_{t-1})})

    where :math:`\operatorname{N}_{+}` is the positive (truncated below zero)
    normal distribution, :math:`S_t \in \{1, \ldots, K\}`,
    :math:`C^{(S_t)} = \lambda_i^{(S_t) 2} \tau^{(S_t) 2}` and

    .. math::

        \lambda^{k}_i &\sim \operatorname{Cauchy}^{+}(0, 1) \\
        \tau^{(k)} &\sim \operatorname{Cauchy}^{+}(0, 1) \\
        V^{(k)} &\sim \operatorname{Gamma}(n_0/2, n_0 S_0/2)

    for :math:`k \in \{1, \ldots, K\}`.


    for observations :math:`y_t` in :math:`t \in \{0, \dots, T\}`,
    features :math:`x_t^{(S_t)} \in \mathbb{R}^M`,
    regression parameters :math:`\beta^{(S_t)}`, state sequences :math:`\{S_t\}^T_{t=1}` and
    state transition probabilities :math:`\pi \in [0, 1]^{K}`.
    :math:`\operatorname{Cauchy}^{+}` is the standard half-Cauchy distribution
    and :math:`\operatorname{N}` is the normal/Gaussian distribution.

    The set of random variables,
    :math:`\mathcal{S} = \{\{\beta^{(k)}, \lambda^{(k)}, \tau^{(k)}, \tau^{(k)}, \pi^{(k)}\}_{k=1}^K, \{S_t\}^T_{t=1}\}`,
    are referred to as "stochastics" throughout the code.


    Parameters
    ==========
    y_data: pandas.DataFrame
        Usage/response observations :math:`y_t`.
    X_data: list of pandas.DataFrame
        List of design matrices for each state, i.e. :math:`x_t^{(S_t)}`.  Each
        must span the entire length of observations (i.e. `y_data`).
    initial_params: NormalHMMInitialParams
        The initial parameters, which include
        :math:`\pi_0, m^{(k)}, \alpha^{(k)}, V^{(k)}`.
    single_obs_var: bool, optional
        Determines whether there are multiple observation variances or not.
        Only used when not given intial parameters.
    include_ppy: bool, optional
        If `True`, then include an unobserved observation Stochastic that can
        be used to produce posterior predicitve samples.  The Stochastic
        will have the name `y_pp`.

    Returns
    =======
    A ``pymc.Model`` object used for sampling.
    """

    N_states = len(X_data)
    N_obs = X_data[0].shape[0]

    alpha_trans = getattr(initial_params, 'alpha_trans', None)
    trans_mat_0 = getattr(initial_params, 'trans_mat', None)
    states_p_0 = getattr(initial_params, 'p0', None)
    states_0 = getattr(initial_params, 'states', None)
    betas_0 = getattr(initial_params, 'betas', None)
    V_invs_n_0 = getattr(initial_params, 'Vs_n', None)
    V_invs_S_0 = getattr(initial_params, 'Vs_S', None)
    V_invs_0 = getattr(initial_params, 'Vs', None)

    #
    # Some parameters can be set to arguably generic values
    # when no initial parameters are explicitly given.
    #
    if alpha_trans is None:
        alpha_trans = np.ones((N_states, N_states))

    if trans_mat_0 is None:
        trans_mat_0 = np.tile(1. / N_states, (N_states, N_states - 1))

    if betas_0 is None:
        betas_0 = [np.zeros(X_.shape[1]) for X_ in X_data]

    if V_invs_n_0 is None or V_invs_S_0 is None:
        V_invs_shape = (1 if single_obs_var else N_states, )
        if y_data is not None:
            V_invs_n_0 = np.tile(1, V_invs_shape)
            S_obs = np.clip(float(np.var(y_data)), 1e-4, np.inf)
            V_invs_S_0 = np.tile(S_obs, V_invs_shape)
            V_invs_0 = np.tile(S_obs, V_invs_shape)
        else:
            V_invs_n_0 = np.ones(1)
            V_invs_S_0 = np.tile(1e-3, V_invs_shape)
            V_invs_0 = np.tile(1e-3, V_invs_shape)

    # Transition probability stochastic:
    trans_mat = TransProbMatrix("trans_mat", alpha_trans, value=trans_mat_0)

    # State sequence stochastics:
    states = HMMStateSeq("states",
                         trans_mat,
                         N_obs,
                         p0=states_p_0,
                         value=states_0)

    # Observation precision distributions:
    V_inv_list = [
        pymc.Gamma('V-{}'.format(k), n_0 / 2., n_0 * S_0 / 2., value=V_inv_0)
        for k, (V_inv_0, n_0,
                S_0) in enumerate(zip(V_invs_0, V_invs_n_0, V_invs_S_0))
    ]

    V_invs = pymc.ArrayContainer(np.array(V_inv_list, dtype=np.object))

    beta_list = ()
    eta_list = ()
    lambda_list = ()
    beta_tau_list = ()

    # This is a dynamic list of the time indices allocated to each state.
    # Very useful for breaking quantities mixtures into separate,
    # easy to handle problems.
    state_obs_idx = ()

    # Now, initialize all the intra-state terms:
    for k in range(N_states):

        def k_idx_func(s_=states, k_=k):
            return np.flatnonzero(k_ == s_)

        # XXX: Can't trace these Deterministics, since they change shape.
        k_idx = pymc.Lambda("state-idx-{}".format(k), k_idx_func, trace=False)

        state_obs_idx += (k_idx, )

        size_k = X_data[k].shape[1]
        size_k = size_k if size_k > 1 else None

        # Local shrinkage terms:
        lambda_k = pymc.HalfCauchy('lambdas-{}'.format(k), 0., 1., size=size_k)

        # We're initializing the scale of the global
        # shrinkage parameter's distribution with a decent,
        # asymptotically motivated value:
        if size_k is not None:
            k_V = k if len(V_invs) == N_states else 0
            eta_k_scale = pymc.Lambda('eta-{}-scale'.format(k),
                                      lambda V_i=V_invs[k_V], s_=size_k: np.
                                      sqrt(1 / V_i) / np.sqrt(np.log(s_)),
                                      trace=False)
            # Global shrinkage term:
            eta_k = pymc.HalfCauchy('eta-{}'.format(k), 0., eta_k_scale)
            eta_list += (eta_k, )

            beta_tau_k = (lambda_k * eta_k)**(-2)
        else:
            beta_tau_k = (lambda_k)**(-2)

        # Consider using just pymc.Cauchy; that way, there's
        # no support restriction that could make things difficult
        # for naive samplers, etc.

        beta_k = pymc.Normal('beta-{}'.format(k),
                             0.,
                             beta_tau_k,
                             value=betas_0[k],
                             size=size_k)

        #beta_k = pymc.TruncatedNormal('beta-{}'.format(k),
        #                              0, beta_tau_k,
        #                              0, np.inf,
        #                              value=betas_0[k],
        #                              size=size_k)

        beta_list += (beta_k, )
        lambda_list += (lambda_k, )
        beta_tau_list += (beta_tau_k, )

    # These containers are handy, but not necessary.
    betas = pymc.TupleContainer(beta_list)
    etas = pymc.TupleContainer(eta_list)
    lambdas = pymc.TupleContainer(lambda_list)
    beta_taus = pymc.TupleContainer(beta_tau_list)

    mu = HMMLinearCombination('mu', X_data, betas, states)

    if np.alen(V_invs) == 1:
        V_inv = V_invs[0]
    else:
        # This is a sort of hack...
        for k, V_ in enumerate(V_invs):
            V_.obs_idx = state_obs_idx[k]

        @pymc.deterministic(trace=False, plot=False)
        def V_inv(states_=states, V_invs_=V_invs):
            return V_invs_[states_].astype(np.float)

    y_observed = False
    if y_data is not None:
        y_observed = True
        y_data = np.ma.masked_invalid(y_data).astype(np.object)
        y_data.set_fill_value(None)

    y_rv = pymc.Normal('y', mu, V_inv, value=y_data, observed=y_observed)

    #y_rv = pymc.TruncatedNormal('y', mu, V_inv,
    #                            0., np.inf,
    #                            value=y_data,
    #                            observed=y_observed)

    if y_observed and include_ppy:
        y_pp_rv = pymc.Normal('y_pp', mu, V_inv, trace=True)

    return pymc.Model(locals())
    def setup_inference(self):
        #depending on the number of wavelengths
        wavelength_number = len(self.wavelengths)
        l = []
        i = 0
        #add c0
        t = 1. / 5.**2
        #mu_ = np.mean(self.ydata)
        l.append(pymc.Normal("c_%i" % (i), mu=0, tau=t))
        i += 1
        for x in range(wavelength_number):
            for _ in range(2 * self.N):
                t = 1. / 5.**2
                mu_ = 0
                l.append(pymc.Normal("c_%i" % (i), mu=mu_, tau=t))
                i += 1
        C = pymc.Container(l)  #\
        #for i in range(1+2*self.N) for x in range(wavelength_number)])
        #C[0]
        @pymc.stochastic(observed=False)
        def sigma(value=1):
            return -np.log(abs(value))

        @pymc.stochastic(observed=False)
        def sigma3(value=1):
            return -np.log(abs(value))

        qw_sigs =  pymc.Container([pymc.HalfCauchy("qw_sigs_%i" % x, beta = 10, alpha=1) \
                                 for x in range(wavelength_number)])
        if self.wavelength_sd_defined:
            qw = pymc.Container([pymc.distributions.Lognormal('qw_%i' %x,mu=self.wavelengths[x], \
                                                       tau = 1. / self.wavelength_sd[x] ** 2) \
                                 for x in range(wavelength_number)])
        else:
            qw = pymc.Container([pymc.distributions.TruncatedNormal('qw_%i' %x,mu=self.wavelengths[x],\
                                                           tau = 1. / self.wavelengths[x]/3.,a=0,b=np.inf) \
                                                       for x in range(wavelength_number)])

        def fourier_series(C, N, QW, x, wavelength_number):
            v = np.array(x)
            v.fill(0.0)
            v = v.astype('float')

            for ii in range(len(x)):
                v[ii] += C[0]
                for w in range(wavelength_number):
                    for i in range(1, N + 1):
                        v[ii] = v[ii] + C[(2*i-1)+2*N*w]*np.cos(2*np.pi/QW[w] * i * (x[ii])) + \
                        C[(2*i)+2*N*w]*np.sin(2*np.pi/QW[w] * i * (x[ii]))
            return v

        self.vector_fourier_series = np.vectorize(fourier_series)
        # Define the form of the model and likelihood
        @pymc.deterministic
        def y_model(C=C,
                    x=self.xdata,
                    qw=qw,
                    nn=self.N,
                    wavelength_number=wavelength_number):
            return fourier_series(C, nn, qw, x, wavelength_number)

        y = pymc.Normal('y',
                        mu=y_model,
                        tau=1. / sigma**2,
                        observed=True,
                        value=self.ydata)
        # package the full model in a dictionary
        self.model1 = dict(C=C,
                           qw=qw,
                           sigma=sigma,
                           qw_sigs=qw_sigs,
                           y_model=y_model,
                           y=y,
                           x_values=self.xdata,
                           y_values=self.ydata)
        self.model_e = pymc.Model([C, qw, sigma, y])
        if len(self.vergence) > 0:

            @pymc.deterministic
            def vergence_values(c=C, qw=qw, y=np.array(self.vergence)[:, 0]):
                return np.sign(fourier_series2(c, qw, y))

            @pymc.stochastic(observed=True)
            def vergence(value=np.array(self.vergence)[:, 1],
                         mu=vergence_values):
                loglike = 0.
                loglike += pymc.distributions.normal_like((mu[value == 1]),
                                                          mu=1,
                                                          tau=1.)
                loglike += pymc.distributions.normal_like((mu[value == -1]),
                                                          mu=-1,
                                                          tau=1.)
                if loglike < float(-1.7876931348623157e+308):
                    return float(-1.7876931348623157e+308)
                return loglike

            self.model1.update({'vergence': vergence})
        if len(self.asymmetry_likelihoods) > 0:

            @pymc.deterministic
            def y_model_asym(c=C, qw=qw):
                x = np.linspace(-np.max(qw), np.max(qw))
                v = np.rad2deg(np.arctan(fourier_series2(c, qw, x)))
                m = np.median(v)  #-np.min(v)
                return m  #np.max(v)-np.min(v)

            @pymc.stochastic(observed=True)
            def y_asym(mu=y_model_asym,
                       value=self.asymmetry_likelihoods[0],
                       tau=1. / self.asymmetry_sigma**2):
                loglike = pymc.distributions.normal_like(x=value,
                                                         mu=mu,
                                                         tau=tau)
                return loglike * 10

            #y_interlimb = pymc.Normal('y_interlimb',mu=y_model_interlimb,value=self.interlimb_likelihoods[0],
            #tau = 1. / self.interlimb_sigma**2 )
            self.model1.update({'y_asym': y_asym})
        if len(self.interlimb_likelihoods) > 0:

            @pymc.deterministic
            def y_model_interlimb(c=C, qw=qw):
                x = np.linspace(-np.max(qw), np.max(qw))
                v = np.rad2deg(np.arctan(fourier_series2(c, qw, x)))
                d = np.max(v) - np.min(v)
                return d  #np.max(v)-np.min(v)

            @pymc.stochastic(observed=True)
            def y_interlimb(mu=y_model_interlimb,
                            value=self.interlimb_likelihoods[0],
                            tau=1. / self.interlimb_sigma**2):
                loglike = pymc.distributions.normal_like(x=value,
                                                         mu=y_model_interlimb,
                                                         tau=tau)
                return loglike * 10

            #y_interlimb = pymc.Normal('y_interlimb',mu=y_model_interlimb,value=self.interlimb_likelihoods[0],
            #tau = 1. / self.interlimb_sigma**2 )
            self.model1.update({'y_interlimb': y_interlimb})
        if len(self.axial_trace_likelihoods) > 0:
            d = self.wavelengths[
                0]  #np.max(self.axial_trace_likelihoods_limb) - np.min(self.axial_trace_likelihoods_limb)
            x_at = np.linspace(
                np.min(self.axial_trace_likelihoods) - d,
                np.max(self.axial_trace_likelihoods) + d, 300)

            @pymc.stochastic(observed=False)
            def at_sigma(value=1):
                return -np.log(abs(value))

            @pymc.deterministic
            def z_model_axial_t(c=C, wl=qw, z_at=x_at):
                return np.array(fourier_series_x_intercepts(c, wl, z_at))

            @pymc.stochastic(observed=True)
            def z_at(mu=z_model_axial_t,
                     sigma=at_sigma,
                     value=self.axial_trace_likelihoods):
                loglike = 0.
                mu = np.array(mu)
                #print mu
                if not np.array(mu).size:
                    return float(-1.7876931348623157e+308)  #-99999#-np.2inf
                for v in value:
                    m = 0.
                    if mu.shape:
                        dif = np.sort(np.abs(mu - v))
                        #if there are two hinges for the same axial trace penalise this!
                        if dif[1] < sigma:
                            loglike += -99999
                        m = mu[(np.abs(mu - v)).argmin()]

                        #m = mu[(np.abs(mu-v)).argmin()]
                    else:
                        m = mu
                    #print 'm', m
                    loglike += pymc.distributions.normal_like(x=v,
                                                              mu=m,
                                                              tau=1. /
                                                              sigma**2)
                loglike
                if loglike < float(-1.7876931348623157e+308):
                    return float(-1.7876931348623157e+308)
                return loglike

            #z_at = pymc.Normal('z_at',mu=z_model_axial_t,tau = 1. / self.axial_trace_limb_sigma,value=self.axial_trace_likelihoods_limb)
            self.model1.update({'z_at': z_at, 'at_sigma': at_sigma})
        self.setup = True
        self.mcmc_uptodate = False
        return True
    def setup_inference_mixture(self):
        #depending on the number of wavelengths
        wavelength_number = len(self.wavelengths)
        l = []
        i = 0
        #add c0
        t = 1. / 5.**2
        mu_ = np.mean(self.ydata)
        l.append(pymc.Normal("c_%i" % (i), mu=mu_, tau=t))
        i += 1
        for x in range(wavelength_number):
            for _ in range(2 * self.N):
                t = 1. / 5.**2
                mu_ = 0
                l.append(pymc.Normal("c_%i" % (i), mu=mu_, tau=t))
                i += 1
        C = pymc.Container(l)  #\
        #for i in range(1+2*self.N) for x in range(wavelength_number)])
        #C[0]
        i_ = pymc.Container([
            pymc.DiscreteUniform('i_%i' % i, lower=0, upper=1)
            for i in range(len(self.xdata))
        ])

        @pymc.stochastic(observed=False)
        def sigma(value=1):
            return -np.log(abs(value))

        @pymc.stochastic(observed=False)
        def sigma3(value=1):
            return -np.log(abs(value))

        qw_sigs =  pymc.Container([pymc.HalfCauchy("qw_sigs_%i" % x, beta = 10, alpha=1) \
                                 for x in range(wavelength_number)])
        if self.wavelength_sd_defined:
            qw = pymc.Container([pymc.distributions.Lognormal('qw_%i' %x,mu=self.wavelengths[x], \
                                                       tau = 1. / self.wavelength_sd[x] ** 2) \
                                 for x in range(wavelength_number)])
        else:
            qw = pymc.Container([pymc.distributions.Normal('qw_%i' %x,mu=self.wavelengths[x],\
                                                           tau = 1. / self.wavelengths[x]/3.) \
                                                       for x in range(wavelength_number)])

        def fourier_series(C, N, QW, x, wavelength_number, i_):
            v = np.array(x)
            v.fill(0.0)
            v = v.astype('float')

            for ii in range(len(x)):
                v[ii] += C[0]
                for w in range(wavelength_number):
                    for i in range(1, N + 1):
                        v[ii] = v[ii] + C[(2*i-1)+2*N*w]*np.cos(2*np.pi/QW[w] * i * (x[ii])) + \
                        C[(2*i)+2*N*w]*np.sin(2*np.pi/QW[w] * i * (x[ii]))
                if i_[ii] == 0:
                    v[ii] = -v[ii]
            return v

        self.vector_fourier_series = np.vectorize(fourier_series)
        # Define the form of the model and likelihood
        @pymc.deterministic
        def y_model(C=C,
                    x=self.xdata,
                    qw=qw,
                    nn=self.N,
                    wavelength_number=wavelength_number,
                    i_=i_):
            return fourier_series(C, nn, qw, x, wavelength_number, i_)

        y = pymc.Normal('y',
                        mu=y_model,
                        tau=1. / sigma**2,
                        observed=True,
                        value=self.ydata)
        # package the full model in a dictionary
        self.model1 = dict(C=C,
                           qw=qw,
                           sigma=sigma,
                           qw_sigs=qw_sigs,
                           y_model=y_model,
                           y=y,
                           x_values=self.xdata,
                           y_values=self.ydata,
                           i_=i_)
        self.model_e = pymc.Model([C, qw, sigma, y])

        self.setup = True
        self.mcmc_uptodate = False
        return True
Exemplo n.º 15
0
import pandas as pd
import pymc as pm

d = pd.read_csv("data/gp.csv")
d.shape

D = np.array([ np.abs(xi - d.x) for xi in d.x])
I = (D == 0).astype("double")

with pm.Model() as gp:
  nugget = pm.HalfCauchy("nugget", beta=5)
  sigma2 = pm.HalfCauchy("sigma2", beta=5)
  ls     = pm.HalfCauchy("ls",     beta=5)

  Sigma = I * nugget + sigma2 * np.exp(-0.5 * D**2 * ls**2)
  
  y = pm.MvNormal(
    "y", 
    mu=np.zeros(d.shape[0]), 
    cov=Sigma, observed=d.y
  )

with gp:
    post_nuts = pm.sample(
        return_inferencedata = True,
        chains = 2
    )