Hello,
I’m trying to implement a right-censored model. However, I need the distribution which will be censored to be a normal distribution left-truncated at zero. I’m stuck with the following error.
NotImplementedError: LogCDF method not implemented for truncated_normal_rv{0, (0, 0, 0, 0), floatX, False}
What I understand is that there’s no logcdf
defined for the truncated normal, but I saw a merged pull request here, and it seems that logcdf
is in fact implemented?
Censoring a truncated distribution
Following is a prior predictive illustration:
import pymc as pm
import arviz as az
import numpy as np
from copy import copy
with pm.Model() as m:
a_normal = pm.Normal("n", 1, 1)
normal_dist = pm.Normal.dist(mu=1.0, sigma=1.0)
truncated_normal = pm.Truncated("truncated_normal", normal_dist, lower=0)
truncated_normal_dist = pm.Truncated.dist(normal_dist, lower=0)
cs_normal = pm.Censored("cs_n", normal_dist, lower=0, upper=3)
cs_truncated_normal = pm.Censored("cs_tn", truncated_normal_dist, lower=None, upper=3)
with m:
idata = pm.sample_prior_predictive(samples=10000)
az.plot_dist(idata.prior.stack(samples=("chain", "draw")).n, color='k', label="the normal")
az.plot_dist(idata.prior.stack(samples=("chain", "draw")).truncated_normal, color='b', label="lower-truncated at 0")
az.plot_dist(idata.prior.stack(samples=("chain", "draw")).cs_tn, color='r', label="truncated-censored")
az.plot_dist(idata.prior.stack(samples=("chain", "draw")).cs_n, color='g', label="non-truncated-censored")
Which will output:
So, I can’t use a normal distribution (black) and censor it from both sides (green), what I need is a truncated distribution (blue) to be right-censored (red).
Generate Data
N = 1 # one trial is enough to illustrate the problem
mu, sigma = 1, 2
upper_bounds = np.random.randint(0, 3, N)
y = np.random.normal(loc=mu, scale=sigma, size=N)
def right_censor(y, upper_bounds):
cy = copy(y)
censor_index = cy >= upper_bounds
cy[censor_index] = upper_bounds[censor_index]
return cy
cy = right_censor(y, upper_bounds)
print(y, upper_bounds, cy)
Inference model
with pm.Model() as m1:
mu = pm.Normal("mu", 0, 1)
sigma = pm.Normal("sigma", 0, 1)
normal_ = pm.Normal.dist(mu, sigma)
trunc_normal = pm.Truncated.dist(normal_, lower=0)
censored = pm.Censored("censored", trunc_normal, lower=None, upper=upper_bounds, observed=cy)
Error
Following gives the error.
with m1:
idata_m1 = pm.sample()
NotImplementedError: LogCDF method not implemented for truncated_normal_rv{0, (0, 0, 0, 0), floatX, False}
- The watermark:
Last updated: Thu Nov 09 2023
Python implementation: CPython
Python version : 3.11.6
IPython version : 8.16.1
scipy : 1.11.3
arviz : 0.16.1
pytensor : 2.13.1
pymc : 5.9.0
numpy : 1.25.2
matplotlib: 3.8.0
pandas : 2.1.1
Watermark: 2.4.3
Question
So I want to ask:
- Is this the correct approach? Is this error really because the
logcdf
is not implemented, or is there a user error in model creation part? - What may be a workaround if it’s not implemented yet? What would you suggest?