I think I wrote this modle incorrectly but am not sure how, please advise

As you can see below, I am trying to use observed data in some of the inputs for my model but I am not sure my syntax is correct and while I am waiting for PYMC to reinstall on my work computer, I wanted some advice.

I am looking to model the probability curve of firetruck travel times. The model is based on the following function for Expected travel time:

ET = \alpha + \beta\left(\frac{A}{n-\lambda ES}\right)^\gamma

\text{where:}

\begin{align*} \alpha &= \text{scaling parameter dependednt on city characterisitcs} \\ \beta &= \text{scaling parameter dependednt on city characterisitcs} \\ \gamma &= \text{scaling parameter dependednt on city characterisitcs} \\ \lambda &= \text{expected number of alarms in an hour} \\ A &= \text{physical area of region in square miles }\\ n &= \text{number of fire companies in region} \\ ED &= \text{Expected distance traveled by closest fire company} \\ ES &= \text{Expected total service time in hours} \\ ET &= \text{Expected travel time in minutes of closest fire company} \end{align*}

With this in mind, my first model is envisioned as:

\begin{align*} \\ \alpha &\sim \mathcal{normal}(0, 100) \\ \beta &\sim \mathcal{normal}(0, 100) \\ \gamma &\sim |\mathcal{N}(0, 1)| \\ \theta &\sim \mathcal{Gamma}(\tau X) \\ \lambda &= \mathcal{Poisson}(\theta) \\ n &= 33 \\ A &= 61.13 \text{ mi}^2 \\ ES &\sim \mathcal{Student}(\nu=3,\nu =1) \text{?}\\ ET &= \alpha + \beta\left(\frac{A}{n-\lambda ES}\right)^\gamma \\ y &\sim \mathcal{normal}(ET, \sigma) \end{align*}

Which I have coded below with data which has observed values for Service Times and Travel times.

first_model = pm.Model()

with first_model:
    # Priors for unknown model parameters
    alpha = pm.Deterministic('alpha', pm.Normal(mu=0, sigma=100))
    beta = pm.Deterministic('beta', pm.Normal(mu=0, sigma=100))
    gamma = pm.Deterministic('gamma', pm.HalfNormal(sigma=1))
    theta = pm.Gamma(mu = pm.Normal(mu=0, sigma=100), sigma=pm.Normal(mu=0, sigma=100), observed = data['travel_times'])
    lambda_ = pm.Deterministic('lambda_', pm.Poisson(theta))
    ES = pm.Student(3,0,1, observed=data['service_times'])
    sigma = pm.HalfNormal(sigma=10)
                           
    # Expected value of outcome
    ET = alpha + beta*(61.13/(33-lambda_*ES))**gamma

    # Sampling distribution of observations
    Y_obs = pm.Normal("Y_obs", mu=ET, sigma=pm.Normal(mu=0, sigma=100))

Update to my last post, running the following after modifying from original model and finally getting pymc installed and working on my computer:

import pandas as pd
import numpy as np
import arviz as az
import pytensor
pytensor.config.cxx=''
pytensor.config.floatX = "float32"
import pymc as pm

first_model = pm.Model()

with first_model:
    # Priors for unknown model parameters
    alpha = pm.HalfNormal('alpha',sigma=100) #not a lot known about this varibale as it would requier experimental data
    beta = pm.HalfNormal('beta',sigma=100) #not a lot known about this varibale as it would requier experimental data
    gamma = pm.HalfNormal('gamma',sigma = 1) # has to be a fractional exponent according to Kolesar [1975]
    theta = pm.Gamma('theta', alpha=1, beta=1)
    lambda_ = pm.Poisson('lambda_', mu=theta, observed = incident_data['alarms_per_hour'])
    sigma_es = pm.InverseGamma('sigma_es', alpha=1, beta=1)
    ES = pm.HalfNormal('ES',sigma= sigma_es,observed = incident_data['service_time'])
    sigma_y = pm.HalfNormal('sigma_y', sigma=100)
                           
    # Expected value of outcome
    ET = pm.Deterministic('ET',alpha + beta*(61.13/(33-lambda_*ES))**gamma)

    # Sampling distribution of observations
    Y_obs = pm.Normal("Y_obs", mu=ET, sigma=sigma_y, observed=incident_data['travel_time'])


After I run this, I receive the following error message:

TypeError: float() argument must be a string or a real number, not 'complex'
Apply node that caused the error: Composite{switch(i7, (((-0.5 * sqr(((i4 - (i3 + (i2 * (i0 ** i1)))) / i5))) - 0.9189385175704956) - i6), -inf)}([1.8646670 ... .87899593], ExpandDims{axis=0}.0, ExpandDims{axis=0}.0, ExpandDims{axis=0}.0, Y_obs{[3. 4. 6. ... 6. 4. 7.]}, ExpandDims{axis=0}.0, Log.0, Gt.0)
Toposort index: 11
Inputs types: [TensorType(float64, shape=(50997,)), TensorType(float32, shape=(1,)), TensorType(float32, shape=(1,)), TensorType(float32, shape=(1,)), TensorType(float32, shape=(50997,)), TensorType(float32, shape=(1,)), TensorType(float32, shape=(1,)), TensorType(bool, shape=(1,))]
Inputs shapes: [(50997,), (1,), (1,), (1,), (50997,), (1,), (1,), (1,)]
Inputs strides: [(8,), (4,), (4,), (4,), (4,), (4,), (4,), (1,)]
Inputs values: ['not shown', array([1.1398649], dtype=float32), array([76.64916], dtype=float32), array([81.637985], dtype=float32), 'not shown', array([43.140366], dtype=float32), array([3.7644591], dtype=float32), array([ True])]
Outputs clients: [[Sum{axes=None}(sigma > 0)]]

And just ran model.debug(verbose=True) to get:

point={'alpha_log__': array(4.6051702, dtype=float32), 'beta_log__': array(4.6051702, dtype=float32), 'gamma_log__': array(0., dtype=float32), 'theta_log__': array(0., dtype=float32), 'sigma_es_log__': array(-0.6931472, dtype=float32), 'sigma_y_log__': array(4.6051702, dtype=float32)}

The variable ES has the following parameters:
0: [0.] [id A] <Vector(float32, shape=(1,))>
1: Exp [id B] <Vector(float32, shape=(1,))>
 └─ ExpandDims{axis=0} [id C] <Vector(float32, shape=(1,))>
    └─ sigma_es_log__ [id D] <Scalar(float32, shape=())>
The parameters evaluate to:
0: [0.]
1: [0.5]
Some of the observed values of variable ES are associated with a non-finite logp:
 value = -7055.2666015625 -> logp = -inf
 value = -6574.7998046875 -> logp = -inf
 value = -7534.10009765625 -> logp = -inf

Can you format code blocks with triple bacticks ```

It’s nearly impossible to read like this

ricardo, thank you. I had no idea how to do that.

after much work trying to isolate the problem, and rethinking some assumptions, I am working on isolating all of the issues with my model in pieces. I did some reading and decided a Weibull distribution would be better to model my service_time data concerning how long fire fighters are responding to an alarm. Using some ideas from here, I have the following model:

second_model = pm.Model()

experiment = incident_data['service_time']/incident_data['service_time'].max() #normalizing data
experiment.loc[experiment == 0] =1e-15 #I suspected that having 0's n my data were causing issues with the model. This did not work
with second_model:
    mu = pm.Normal('mu', mu=0,sigma=1)
    alpha_raw = pm.Normal("a0", mu=0, sigma=0.1)
    alpha = pm.Deterministic("alpha", pyt.exp(alpha_raw))
    beta = pm.Deterministic("beta", pyt.exp(mu / alpha))
    #beta_backtransformed = pm.Deterministic("beta_backtransformed", beta * np.max(y))

    latent = pm.Weibull('latent',alpha=alpha, beta=beta, observed = experiment)
    
    trace2 = pm.sample(draws=4000, chains=4, nuts_sampler="pymc")
az.plot_trace(trace2)

this results in the model failing with the message:

Logp initial evaluation results:
{'mu': -0.96, 'a0': -6.64, 'latent': -inf}

and when I run model.debug(), I see the following:

The variable latent has the following parameters:
0: Exp [id A] <Vector(float32, shape=(1,))>
 └─ ExpandDims{axis=0} [id B] <Vector(float32, shape=(1,))>
    └─ a0 [id C] <Scalar(float32, shape=())>
1: Exp [id D] <Vector(float32, shape=(1,))>
 └─ True_div [id E] <Vector(float32, shape=(1,))>
    ├─ ExpandDims{axis=0} [id F] <Vector(float32, shape=(1,))>
    │  └─ mu [id G] <Scalar(float32, shape=())>
    └─ Exp [id A] <Vector(float32, shape=(1,))>
       └─ ···
The parameters evaluate to:
0: [1.]
1: [1.]
Some of the observed values of variable latent are associated with a non-finite logp:
 value = 0.0 -> logp = nan

the data, when enterd into the model is described as:

count    5.099700e+04
mean     2.759238e-03
std      7.350712e-03
min      1.000000e-15
25%      7.611403e-04
50%      1.453086e-03
75%      2.906172e-03
max      1.000000e+00
Name: service_time, dtype: float64

and the untransformed version is:

count    50997.000000
mean         0.664608
std          1.770541
min          0.000000
25%          0.183333
50%          0.350000
75%          0.700000
max        240.866667
Name: service_time, dtype: float64

Any guidace on where I am going wrong would be appreciated

thanks to @cluhmann for the edits to previous posts and @ricardoV94 for telling me how to properly enter code. Hopefully I can find a solution to my issues someday. :slight_smile:

1 Like

Is that debug output saying some value = 0.0, done with the data with epsilon? That’s strange

@ricardoV94 is it possible, I chose the wrong distribution for the data? I assumed Weibull as my input is hours fire trucks spend at a fire incident and a ked plot of the data generated by:

experiment = incident_data['service_time']/incident_data['service_time'].max()
experiment = experiment + (1/3600)

looks like:

To split up model problems from data problems, and as a check of parameter identification, it is very good practice to use prior draws from your model as data. You can do this by removing the observed argument from latent and use pm.observe:

with pm.Model() as second_model:
    mu = pm.Normal('mu', mu=0,sigma=1)
    alpha_raw = pm.Normal("a0", mu=0, sigma=0.1)
    alpha = pm.Deterministic("alpha", pm.math.exp(alpha_raw))
    beta = pm.Deterministic("beta", pm.math.exp(mu / alpha))

    latent = pm.Weibull('latent',alpha=alpha, beta=beta, shape=(100,))
    prior = pm.sample_prior_predictive()

sample_data = prior.prior.isel(chain=0, draw=123)
with pm.observe(second_model, {'latent': sample_data.latent}) as second_obs:
    idata = pm.sample(init='jitter+adapt_diag_grad')
    idata = pm.sample_posterior_predictive(idata, extend_inferencedata=True)

This samples without issue, and produces the following results:

axes = az.plot_trace(idata, var_names=[x.name for x in second_obs.free_RVs])
for axis in axes[:, 0]:
    param = axis.get_title()
    axis.axvline(sample_data[param].item(), ls='--', c='k')
plt.tight_layout()


So on artificial data, where you know the correct answer and the proposed model is really the right model, everything works fine. This points to you data as having issues. I would start by checking for missing or NaN values.

Edit: Also there is no reason to switch pytensor to half precision, so I recommend not doing that.

@jessegrabowski Thank you for this, the change to float 32 was prompted by another error message I have long forgotten at this moment. Could this also be due to having large outliers in my data–because it does have those as well.

@jessegrabowski & @ricardoV94 Thank you for your help so far. I have gotten the model to work so far except tor the final expected travel time (ET) component. For context, this is derived from a Rand corporation paper from 1975, linked here, where they arrive at a model for predicting fire engine arrival times defined as ET = \alpha + \beta\left(\frac{A}{n-\lambda ES}\right)^\gamma with \alpha, \beta, \text{and } \gamma possibly determined experimentally but the paper did provide some baseline vales of 0,2.2, and .3 respectively. The data I have relates to number of alarms, service time, and travel times and I am attempting to use these data to derive the probability function to describe fire engine arrival times. Unfortunately when I attempt to use ET as a mu my for my travel_time_obs as shown below, the model suffers the error

RuntimeWarning: invalid value encountered in scalar power
  return x**y

I suspect it is because I am defining something improperly but I don’t know what. The model will run if I comment out travel_time_obs but I am also worried that ET may not have enough information from the data as it is supposed to be the expected value of the travel_time.

second_model = pm.Model()



with second_model:
    #constants
    A = pm.Data('A', 61.13) #miles square
    n = pm.Data('n', 33) #number of engine companies
    
    # Priors for unknown model parameters
    α = 0 #pm.Uniform('α',0,50) #pm.HalfNormal('α',sigma=100) #not a lot known about this varibale as it would requier experimental data
    β = 2.2 #pm.Uniform('β',1,10)  #pm.HalfNormal('β',sigma=100) #not a lot known about this varibale as it would requier experimental data
    γ = .3 #pm.HalfNormal('gamma',sigma = 1) # has to be a fractional exponent according to Kolesar [1975]
    λ = pm.Gamma('λ', alpha=1, beta=1)
    alarms_obs = pm.Poisson('alarms_obs', mu= λ, observed = incident_data['alarms_per_hour'])

    ϕ = pm.HalfNormal('sigma_y', sigma=1) #shape parameter for Wald distribution is likely to be less than 1 given the sharp peak seen in the  travel time data



    #ES
    mu = pm.Normal('mu', mu=0,sigma=1)
    alpha_raw = pm.Normal("alpha_raw", mu=0, sigma=0.1)
    alpha_w = pm.Deterministic("alpha_w", pt.exp(alpha_raw))
    beta_n_w = pm.Deterministic("beta_n_w", pt.exp(mu / alpha_w))
    beta_w = pm.Deterministic("beta_w", (beta_n_w * incident_data['service_time'].max())-(1/3600))
    
    # Sampling distribution of observed service times
    latent = pm.Weibull('latent',alpha=alpha_w, beta=beta_n_w, observed = experiment)

    ES = pm.Deterministic('ES', beta_w*pt.gamma(1 + 1/alpha_w))

    # Expected value of travel_time
    ET = pm.Deterministic('ET',α + β*(A/(n-λ*ES))**γ)

    # Sampling distribution of observed travel times
    #travel_time_obs = pm.Wald('travel_time_obs', mu=ET, phi=ϕ, observed=travel_time_norm) 
    
  
    trace2 = pm.sample(draws=4000, chains=4, nuts_sampler="blackjax")
az.plot_trace(trace2, var_names=['ES','λ','ET'])

@jessegrabowski For further information on why I changed pytensor to use float32, it was do to a runtime error caused by an issue with blackjax referenced here and float32 was the recommended solution

Ok, I changed the sampler to nutpie and suddenly it is working. Dear god this has been a long few weeks. Than you all for your help as now I have more investigation to do.

1 Like