Skip to content

Commit 4efc6c4

Browse files
committed
option to treat y_s as detetion probability
1 parent c694bc4 commit 4efc6c4

3 files changed

Lines changed: 64 additions & 22 deletions

File tree

cell2location/models/_cell2location_model.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,15 @@ def __init__(
7676
self.factor_names_ = cell_state_df.columns.values
7777

7878
if not detection_mean_per_sample:
79-
# compute expected change in sensitivity (m_g in V1 or y_s in V2)
79+
# compute expected change in sensitivity (m_g in V1 and y_s in V2)
8080
sc_total = cell_state_df.sum(0).mean()
81-
sp_total = get_from_registry(self.adata, _CONSTANTS.X_KEY).sum(1).mean()
82-
get_from_registry(adata, _CONSTANTS.BATCH_KEY)
81+
sp_total = get_from_registry(self.adata, _CONSTANTS.X_KEY).sum(1)
82+
batch = get_from_registry(self.adata, _CONSTANTS.BATCH_KEY).flatten()
83+
sp_total = np.array([sp_total[batch == b].mean() for b in range(self.summary_stats["n_batch"])])
8384
self.detection_mean_ = (sp_total / model_kwargs.get("N_cells_per_location", 1)) / sc_total
85+
if (self.detection_mean_.max() > 1.0) and (model_kwargs.get("use_detection_probability", False) is True):
86+
self.detection_mean_ = self.detection_mean_ / (self.detection_mean_.max() + 0.000001)
87+
self.detection_mean_ = self.detection_mean_.mean()
8488
self.detection_mean_ = self.detection_mean_ * detection_mean_correction
8589
model_kwargs["detection_mean"] = self.detection_mean_
8690
else:

cell2location/models/_cell2location_module.py

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def __init__(
8383
n_groups: int = 50,
8484
detection_mean=1 / 2,
8585
detection_alpha=200.0,
86+
use_detection_probability: bool = False,
8687
m_g_gene_level_prior={"mean": 1, "mean_var_ratio": 1.0, "alpha_mean": 3.0},
8788
N_cells_per_location=8.0,
8889
A_factors_per_location=7.0,
@@ -117,6 +118,7 @@ def __init__(
117118
detection_hyp_prior["mean"] = detection_mean
118119
detection_hyp_prior["alpha"] = detection_alpha
119120
self.detection_hyp_prior = detection_hyp_prior
121+
self.use_detection_probability = use_detection_probability
120122

121123
if (init_vals is not None) & (type(init_vals) is dict):
122124
self.np_init_vals = init_vals
@@ -323,27 +325,47 @@ def forward(self, x_data, idx, batch_index):
323325
) # (self.n_obs, self.n_factors)
324326

325327
# =====================Location-specific detection efficiency ======================= #
326-
# y_s with hierarchical mean prior
327-
detection_mean_y_e = pyro.sample(
328-
"detection_mean_y_e",
329-
dist.Gamma(
330-
self.ones * self.detection_mean_hyp_prior_alpha,
331-
self.ones * self.detection_mean_hyp_prior_beta,
328+
if not self.use_detection_probability:
329+
# y_s with hierarchical mean prior
330+
detection_mean_y_e = pyro.sample(
331+
"detection_mean_y_e",
332+
dist.Gamma(
333+
self.ones * self.detection_mean_hyp_prior_alpha,
334+
self.ones * self.detection_mean_hyp_prior_beta,
335+
)
336+
.expand([self.n_batch, 1])
337+
.to_event(2),
338+
)
339+
detection_hyp_prior_alpha = pyro.deterministic(
340+
"detection_hyp_prior_alpha",
341+
self.ones_n_batch_1 * self.detection_hyp_prior_alpha,
332342
)
333-
.expand([self.n_batch, 1])
334-
.to_event(2),
335-
)
336-
detection_hyp_prior_alpha = pyro.deterministic(
337-
"detection_hyp_prior_alpha",
338-
self.ones_n_batch_1 * self.detection_hyp_prior_alpha,
339-
)
340343

341-
beta = (obs2sample @ detection_hyp_prior_alpha) / (obs2sample @ detection_mean_y_e)
342-
with obs_plate:
343-
detection_y_s = pyro.sample(
344-
"detection_y_s",
345-
dist.Gamma(obs2sample @ detection_hyp_prior_alpha, beta),
346-
) # (self.n_obs, 1)
344+
beta = (obs2sample @ detection_hyp_prior_alpha) / (obs2sample @ detection_mean_y_e)
345+
with obs_plate:
346+
detection_y_s = pyro.sample(
347+
"detection_y_s",
348+
dist.Gamma(obs2sample @ detection_hyp_prior_alpha, beta),
349+
) # (self.n_obs, 1)
350+
else:
351+
# y_s with hierarchical mean prior
352+
detection_mean_y_e = pyro.sample(
353+
"detection_mean_y_e",
354+
dist.Beta(
355+
self.ones * self.detection_mean_hyp_prior_alpha,
356+
self.ones * self.detection_mean_hyp_prior_beta,
357+
)
358+
.expand([self.n_batch, 1])
359+
.to_event(2),
360+
)
361+
362+
alpha = (obs2sample @ detection_mean_y_e) * self.ones * self.detection_hyp_prior_alpha
363+
beta = (obs2sample @ (self.ones - detection_mean_y_e)) * self.ones * self.detection_hyp_prior_alpha
364+
with obs_plate:
365+
detection_y_s = pyro.sample(
366+
"detection_y_s",
367+
dist.Beta(alpha, beta),
368+
) # (self.n_obs, 1)
347369

348370
# =====================Gene-specific additive component ======================= #
349371
# per gene molecule contribution that cannot be explained by

tests/test_cell2location.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,19 @@ def test_cell2location():
120120
# export the estimated cell abundance (summary of the posterior distribution)
121121
# full data
122122
st_model.export_posterior(dataset, sample_kwargs={"num_samples": 10, "batch_size": st_model.adata.n_obs})
123+
124+
### test new cell2location models ###
125+
## detection probability rather than detection efficiency ##
126+
st_model = Cell2location(
127+
dataset,
128+
cell_state_df=inf_aver,
129+
N_cells_per_location=30,
130+
detection_alpha=200,
131+
use_detection_probability=True,
132+
detection_hyp_prior={"mean_alpha": 100.0},
133+
)
134+
# test full data training
135+
st_model.train(max_epochs=1)
136+
# export the estimated cell abundance (summary of the posterior distribution)
137+
# full data
138+
dataset = st_model.export_posterior(dataset, sample_kwargs={"num_samples": 10, "batch_size": st_model.adata.n_obs})

0 commit comments

Comments
 (0)