Hi, I have a set of observations which are individuals. Each individual is represented by a vector of features which should follow Poisson distributions. My goal is to cluster these individuals.
Each cluster then defines the Poisson parameters of each feature of each individual in the cluster.
This is for example 5 individuals, each of them having 8 features
simu_ind = array([[151, 176, 181, 146, 135, 134, 136, 180],
[ 62, 80, 132, 105, 138, 88, 70, 108],
[141, 192, 178, 123, 120, 156, 155, 154],
[ 17, 41, 16, 18, 23, 21, 13, 11],
[ 18, 33, 14, 16, 16, 19, 15, 21]])
Let’s assume that we know the Poisson mean of each feature for each cluster (we have here 3 clusters and 5 possible Poisson distributions)
exp_mean = array([[ 18., 25., 20.],
[ 36., 49., 40.],
[ 54., 74., 60.],
[ 72., 98., 79.],
[ 90., 123., 99.]]))
I came up with this MarginalModel to model my problem
with MarginalModel() as full_model_marg_test:
cluster_weights = pm.Dirichlet("cluster_weights", a=np.ones(nb_clusters))
ind2cluster = [pm.Categorical('ind'+str(k), p=cluster_weights) for k in range(nb_ind)]
poisson_component_weights = [pm.Dirichlet("poisson_component_weights"+str(k), a=pt.tensor.ones(5)) for k in range(nb_clusters)]
feat2component = [pm.Categorical('obscomp'+str(idx),p=poisson_component_weights[idx],shape=nb_amp) for idx in range(nb_clusters)]
observation = []
for k in range(nb_clusters):
observation += [pm.Poisson('obs'+str(k),mu=expect_mean[:,ind2cluster[k]][pt.tensor.as_tensor(feat2component)[ind2cluster[k]]],observed=simu_ind[k,:])]
for j in pt.tensor.unique(ind2cluster).eval():
full_model_marg_test.marginalize([feat2component[j]])
for k in range(nb_ind):
full_model_marg_test.marginalize([ind2cluster[k]])
I wanted to use the automatic way to marginalised the discrete latent variables of the model i.e the assignment of individual to cluster ind2cluster and the assignment of feature to their appropriate Poisson distribution given the cluster assignment feat2component.
I tried to do it in the most explicit and splitted way but got this error:
NotImplementedError: Marginalization through operation Join(0, ExpandDims{axis=0}.0, ExpandDims{axis=0}.0, ExpandDims{axis=0}.0) not supported.
NotImplementedError: The graph between the marginalized and dependent RVs cannot be marginalized efficiently. You can try splitting the marginalized RV into separate components and marginalizing them separately.
I then tried to marginalize only ind2cluster given deterministic feat2component and reciprocally.
Given
feat2component = array([[0, 3, 0],
[0, 3, 1],
[1, 3, 0],
[2, 3, 1],
[2, 3, 1],
[0, 3, 1],
[0, 4, 4],
[1, 0, 1]])
Here it means that for cluster 0, features 0 for every individual of this cluster should follow a poisson distribution with mean exp_mean[:,0][0] = 18
with MarginalModel() as try_marg_ind:
cluster_weights = pm.Dirichlet("cluster_weights", a=np.ones(nb_clusters))
ind2cluster = [pm.Categorical('ind'+str(k), p=cluster_weights) for k in range(nb_ind)]
observation = pm.Poisson('obs', mu=[pt.shared(expect_mean)[:,ind2cluster[k]][pt.shared(feat2component)[:,ind2cluster[k]]] for k in range(nb_ind)],observed=simu_ind)
for k in range(nb_ind):
try_marg_ind.marginalize([ind2cluster[k]])
This bit work if I split ind2cluster.
Now, then given,
ind2cluster = array([0, 2, 0, 0, 0])
with MarginalModel() as try_marg:
poisson_component_weights = [pm.Dirichlet("poisson_component_weights"+str(k), a=pt.tensor.ones(max_cns)) for k in range(nb_clusters)]
feat2component = [pm.Categorical('obscomp'+str(idx),p=poisson_component_weights[idx],shape=nb_amp) for idx in range(nb_clusters)]
observation = []
for k in range(nb_clusters):
observation += [pm.Poisson('obs'+str(k),mu=expect_mean[:,ind2cluster[k]][feat2component[ind2cluster[k]]],observed=simu_ind[k,:])]
for j in np.unique(ind2cluster):
try_marg.marginalize([feat2component[j]])
It work eventhough I got the following warning:
UserWarning: There are multiple dependent variables in a FiniteDiscreteMarginalRV. Their joint logp terms will be assigned to the first RV: obs0
warnings.warn
It does not work if I have one Poisson for all observations as I did in try_marg_ind
Can someone help me understand why I can’t marginalize automatically the full model or what I am doing wrong please. I wonder if it’s related to this bit, where I convert a list to a tensor leading to a Join operation ?
pt.tensor.as_tensor(feat2component)