Skip to content
This repository was archived by the owner on Oct 21, 2025. It is now read-only.

Commit 9797135

Browse files
added unconstrained fitting of continuous models with interactions
1 parent 599bfe4 commit 9797135

2 files changed

Lines changed: 100 additions & 8 deletions

File tree

diffxpy/testing/tests.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,7 @@ def wald(
595595
np.arange(design_loc.shape[-1])[design_loc.design_info.slice(x)]
596596
for x in factor_loc_totest
597597
])
598+
print(col_indices)
598599
assert len(col_indices) > 0, "Could not find any matching columns!"
599600
if coef_to_test is not None:
600601
if len(factor_loc_totest) > 1:
@@ -1989,7 +1990,7 @@ def continuous_1d(
19891990
for x in spline_basis.columns:
19901991
sample_description[x] = spline_basis[x].values
19911992

1992-
# Add spline basis to continuous covariate list
1993+
# Add spline basis to continuous covariates list
19931994
as_numeric.extend(new_coefs)
19941995

19951996
if test.lower() == 'wald':
@@ -1999,23 +2000,34 @@ def continuous_1d(
19992000
# Adjust factors / coefficients to test:
20002001
# Note that the continuous covariate does not necessarily have to be tested,
20012002
# it could also be a condition effect or similar.
2002-
# TODO handle interactions
20032003
if continuous in factor_loc_totest:
20042004
# Create reduced set of factors to test which does not contain continuous:
2005-
factor_loc_totest_new = [x for x in factor_loc_totest if x != continuous]
2005+
factor_loc_totest_intermediate = [x for x in factor_loc_totest if x != continuous]
20062006
# Add spline basis terms in instead of continuous term:
2007-
factor_loc_totest_new.extend(new_coefs)
2007+
factor_loc_totest_intermediate.extend(new_coefs)
20082008
else:
2009-
factor_loc_totest_new = factor_loc_totest
2009+
factor_loc_totest_intermediate = factor_loc_totest
2010+
# Replace continuous factor in interaction terms with new spline factors.
2011+
factor_loc_totest_final = []
2012+
for i, x in enumerate(factor_loc_totest_intermediate):
2013+
if len(x.split(":")) > 1:
2014+
if np.any([x == continuous for x in x.split(":")]):
2015+
interaction_partner = [y for y in x.split(":") if y != continuous][0]
2016+
for y in new_coefs:
2017+
factor_loc_totest_final.append(y+":"+interaction_partner)
2018+
else:
2019+
factor_loc_totest_final.append(x)
2020+
else:
2021+
factor_loc_totest_final.append(x)
20102022

20112023
logging.getLogger("diffxpy").debug("model formulas assembled in de.test.continuos():")
2012-
logging.getLogger("diffxpy").debug("factor_loc_totest_new: " + ",".join(factor_loc_totest_new))
2024+
logging.getLogger("diffxpy").debug("factor_loc_totest_final: " + ",".join(factor_loc_totest_final))
20132025
logging.getLogger("diffxpy").debug("formula_loc_new: " + formula_loc_new)
20142026
logging.getLogger("diffxpy").debug("formula_scale_new: " + formula_scale_new)
20152027

20162028
de_test = wald(
20172029
data=data,
2018-
factor_loc_totest=factor_loc_totest_new,
2030+
factor_loc_totest=factor_loc_totest_final,
20192031
coef_to_test=None,
20202032
formula_loc=formula_loc_new,
20212033
formula_scale=formula_scale_new,
@@ -2034,6 +2046,7 @@ def continuous_1d(
20342046
dtype=dtype,
20352047
**kwargs
20362048
)
2049+
print(de_test.model_estim.input_data.loc_names)
20372050
de_test = DifferentialExpressionTestWaldCont(
20382051
de_test=de_test,
20392052
noise_model=noise_model,

diffxpy/unit_test/test_continuous_null.py

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,31 @@ def _fit_continuous(
3939
)
4040
return test
4141

42+
def _fit_continuous_interaction(
43+
self,
44+
sim,
45+
sample_description,
46+
constrained,
47+
test,
48+
spline_basis
49+
):
50+
test = de.test.continuous_1d(
51+
data=sim.input_data,
52+
sample_description=sample_description,
53+
gene_names=["gene" + str(i) for i in range(sim.input_data.num_features)],
54+
formula_loc="~ 1 + continuous + batch + continuous:batch",
55+
formula_scale="~ 1",
56+
factor_loc_totest=["continuous", "continuous:batch"],
57+
continuous="continuous",
58+
size_factors="size_factors",
59+
df=3,
60+
spline_basis=spline_basis,
61+
test=test,
62+
quick_scale=True,
63+
noise_model=self.noise_model
64+
)
65+
return test
66+
4267
def _test_basic(
4368
self,
4469
ngenes: int,
@@ -67,6 +92,34 @@ def _test_basic(
6792
)
6893
return det
6994

95+
def _test_interaction(
96+
self,
97+
ngenes: int,
98+
test: str,
99+
constrained: bool,
100+
spline_basis: str
101+
):
102+
n_timepoints = 5
103+
sim = Simulator(num_observations=n_timepoints*200, num_features=ngenes)
104+
sim.generate_sample_description(num_batches=0, num_conditions=0)
105+
sim.generate_params()
106+
sim.generate_data()
107+
108+
random_sample_description = pd.DataFrame({
109+
"continuous": np.asarray(np.random.randint(0, n_timepoints, size=sim.nobs), dtype=float)
110+
})
111+
random_sample_description["batch"] = [str(np.random.randint(0, 3))
112+
for x in random_sample_description["continuous"]]
113+
random_sample_description["size_factors"] = np.random.uniform(0.9, 1.1, sim.nobs) # TODO put into simulation.
114+
det = self._fit_continuous_interaction(
115+
sim=sim,
116+
sample_description=random_sample_description,
117+
test=test,
118+
constrained=constrained,
119+
spline_basis=spline_basis,
120+
)
121+
return det
122+
70123
def _test_null_model(
71124
self,
72125
ngenes: int,
@@ -82,6 +135,21 @@ def _test_null_model(
82135
)
83136
return self._eval(det=det)
84137

138+
def _test_null_model_interaction(
139+
self,
140+
ngenes: int,
141+
test: str,
142+
constrained: bool,
143+
spline_basis: str
144+
):
145+
det = self._test_interaction(
146+
ngenes=ngenes,
147+
test=test,
148+
constrained=constrained,
149+
spline_basis=spline_basis
150+
)
151+
return self._eval(det=det)
152+
85153
def _eval(self, det):
86154
pval_h0 = stats.kstest(det.pval, 'uniform').pvalue
87155
logging.getLogger("diffxpy").info(
@@ -145,6 +213,15 @@ def _test_null_model_all_splines(
145213
for x in ["bs", "cr", "cc"]:
146214
self._test_null_model(ngenes=ngenes, test=test, constrained=constrained, spline_basis=x)
147215

216+
def _test_null_model_all_splines_interaction(
217+
self,
218+
ngenes: int,
219+
test: str,
220+
constrained: bool
221+
):
222+
for x in ["bs", "cr", "cc"]:
223+
self._test_null_model_interaction(ngenes=ngenes, test=test, constrained=constrained, spline_basis=x)
224+
148225

149226
class TestContinuousNb(_TestContinuous, unittest.TestCase):
150227

@@ -203,7 +280,8 @@ def test_null_distribution_wald_unconstrained(self):
203280

204281
self.noise_model = "nb"
205282
np.random.seed(1)
206-
self._test_null_model_all_splines(ngenes=100, test="wald", constrained=False)
283+
#self._test_null_model_all_splines(ngenes=100, test="wald", constrained=False)
284+
self._test_null_model_all_splines_interaction(ngenes=100, test="wald", constrained=False)
207285
return True
208286

209287
def test_null_distribution_wald_constrained(self):
@@ -223,6 +301,7 @@ def test_null_distribution_wald_constrained(self):
223301
self.noise_model = "nb"
224302
np.random.seed(1)
225303
self._test_null_model_all_splines(ngenes=100, test="wald", constrained=True)
304+
# Interaction not supported yet.
226305
return True
227306

228307
def _test_null_distribution_lrt(self):

0 commit comments

Comments
 (0)