causarray 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
causarray/utils.py ADDED
@@ -0,0 +1,243 @@
1
+ import os
2
+ import random
3
+ import numpy as np
4
+ import pandas as pd
5
+
6
+ import inspect
7
+
8
+ import pprint
9
+ from tqdm import tqdm
10
+ import warnings
11
+ warnings.filterwarnings('ignore')
12
+
13
+ np.set_printoptions(threshold=10)
14
+
15
+ import matplotlib.pyplot as plt
16
+ from mpl_toolkits.axes_grid1 import host_subplot
17
+
18
+
19
+ def prep_causarray_data(Y, A, X=None, X_A=None, intercept=True):
20
+ """
21
+ Prepares the input data for the causarray model.
22
+
23
+ Parameters
24
+ ----------
25
+ Y : array-like
26
+ The response matrix.
27
+ A : array-like
28
+ The treatment matrix.
29
+ X : array-like, optional
30
+ The covariate matrix. Defaults to None.
31
+ X_A : array-like, optional
32
+ The covariate matrix for the treatment. Defaults to None.
33
+ intercept : bool, optional
34
+ Whether to include an intercept in the covariate matrix. Defaults to True.
35
+
36
+ Returns
37
+ -------
38
+ Y : array
39
+ The processed response matrix.
40
+ A : array
41
+ The processed treatment matrix.
42
+ X : array
43
+ The processed covariate matrix.
44
+ X_A : array
45
+ The processed covariate matrix with the log library size.
46
+ """
47
+ if not isinstance(Y, pd.DataFrame):
48
+ Y = np.asarray(Y)
49
+ Y = np.minimum(Y, np.round(np.quantile(np.max(Y, 0), 0.999)))
50
+ if not isinstance(A, pd.DataFrame):
51
+ A = np.asarray(A)
52
+
53
+ X = np.zeros((Y.shape[0], 0)) if X is None else np.asarray(X)
54
+ intercept_col = np.ones((X.shape[0], 1)) if intercept else np.empty((X.shape[0], 0))
55
+ X = np.hstack((intercept_col, X))
56
+
57
+ X_A = X if X_A is None else np.asarray(X_A)
58
+ loglibsize = np.log2(np.sum(np.asarray(Y), axis=1))
59
+ loglibsize = (loglibsize - np.mean(loglibsize)) / np.std(loglibsize, ddof=1)
60
+ X_A = np.hstack((X_A, loglibsize[:, None]))
61
+
62
+ return Y, A, X, X_A
63
+
64
+
65
+ def reset_random_seeds(seed):
66
+ os.environ['PYTHONHASHSEED']=str(seed)
67
+ np.random.seed(seed)
68
+ random.seed(seed)
69
+
70
+
71
+ def _filter_params(func, kwargs):
72
+ '''
73
+ Filter the parameters of a function.
74
+
75
+ Parameters
76
+ ----------
77
+ func : function
78
+ The function to filter the parameters.
79
+ kwargs : dict
80
+ The input parameters.
81
+
82
+ Returns
83
+ -------
84
+ filtered_kwargs : dict
85
+ The filtered parameters.
86
+ '''
87
+ if isinstance(func, dict):
88
+ valid_params = func.keys()
89
+ elif callable(func):
90
+ valid_params = inspect.signature(func).parameters.keys()
91
+ else:
92
+ raise ValueError("The provided func is not a callable function, or a dict.")
93
+ filtered_kwargs = {k: v for k, v in kwargs.items() if k in valid_params}
94
+
95
+ return filtered_kwargs
96
+
97
+
98
+ class Early_Stopping():
99
+ '''
100
+ The early-stopping monitor.
101
+ '''
102
+ def __init__(self, warmup=25, patience=25, tolerance=0., is_minimize=True, **kwargs):
103
+ self.warmup = warmup
104
+ self.patience = patience
105
+ self.tolerance = tolerance
106
+ self.is_minimize = is_minimize
107
+
108
+ self.step = -1
109
+ self.best_step = -1
110
+ self.best_metric = np.inf
111
+
112
+ if not self.is_minimize:
113
+ self.factor = -1.0
114
+ else:
115
+ self.factor = 1.0
116
+ self.info = None
117
+
118
+ def __call__(self, metric):
119
+ self.step += 1
120
+
121
+ if self.step < self.warmup:
122
+ return False
123
+ elif self.factor*metric<self.factor*self.best_metric-self.tolerance:
124
+ self.best_metric = metric
125
+ self.best_step = self.step
126
+ return False
127
+ elif self.step - self.best_step>self.patience:
128
+ self.info = 'Best Epoch: %d. Best Metric: %f.'%(self.best_step, self.best_metric)
129
+ return True
130
+ else:
131
+ return False
132
+
133
+ def reset_state(self):
134
+ self.best_step = self.step
135
+ self.best_metric = np.inf
136
+
137
+
138
+
139
+ def _geo_mean(x):
140
+ non_zero_x = x[x != 0]
141
+ if len(non_zero_x) == 0:
142
+ return -np.inf
143
+ else:
144
+ return np.mean(np.log(non_zero_x))
145
+
146
+ def _normalize(counts, log_geo_means):
147
+ log_cnts = np.log(counts)
148
+ diff = log_cnts - log_geo_means
149
+ mask = np.isfinite(log_geo_means) & (counts > 0)
150
+ return np.median(diff[mask])
151
+
152
+
153
+ def comp_size_factor(counts, method='geomeans', lib_size=1e4, **kwargs):
154
+ '''
155
+ Compute the size factors of the rows of the count matrix.
156
+
157
+ Parameters
158
+ ----------
159
+ counts : array-like
160
+ The input raw count matrix.
161
+ method : str
162
+ The method to compute the size factors, 'geomeans' or 'scale'.
163
+ lib_size : float
164
+ The desired library size after normalization for 'scale'.
165
+
166
+ Returns
167
+ -------
168
+ size_factor : array-like
169
+ The size factors of the rows.
170
+ '''
171
+ if method=='geomeans':
172
+ # compute the geometric mean of all genes
173
+ log_geo_means = np.apply_along_axis(_geo_mean, axis=0, arr=counts)
174
+ log_size_factor = np.apply_along_axis(_normalize, axis=1, arr=counts, log_geo_means=log_geo_means)
175
+ size_factor = np.exp(log_size_factor - np.mean(log_size_factor))
176
+ elif method=='scale':
177
+ size_factor = 1./np.sum(Y, axis=0)*lib_size
178
+ else:
179
+ raise ValueError("Method must be in {'geomeans' or 'scale'}.")
180
+
181
+ return size_factor
182
+
183
+
184
+
185
+ def plot_r(df_r, c=1):
186
+ '''
187
+ Plot the results of the estimation of the number of latent factors.
188
+
189
+ Parameters
190
+ ----------
191
+ df_r : DataFrame
192
+ Results of the number of latent factors.
193
+ c : float
194
+ The constant factor for the complexity term.
195
+
196
+ Returns
197
+ -------
198
+ fig : Figure
199
+ The figure of the plot.
200
+ '''
201
+
202
+
203
+ fig = plt.figure(figsize=[18,6])
204
+ host = host_subplot(121)
205
+ par = host.twinx()
206
+
207
+ host.set_xlabel("Number of factors $r$")
208
+ host.set_ylabel("Deviance")
209
+ # par.set_ylabel("$\nu$")
210
+
211
+
212
+ p1, = host.plot(df_r['r'], df_r['deviance'], '-o', label="Deviance")
213
+ p2, = par.plot(df_r['r'], df_r['nu']*c, '-o', label=r"$\nu$")
214
+
215
+
216
+ host.set_xticks(df_r['r'])
217
+ host.yaxis.get_label().set_color(p1.get_color())
218
+ par.tick_params(axis='y', colors=p2.get_color(), labelsize=14)
219
+ host.tick_params(axis='y', colors=p1.get_color(), labelsize=14)
220
+
221
+ p1, = host.plot(df_r['r'], df_r['deviance']+df_r['nu']*c, '-o', label="JIC")
222
+ host.legend(labelcolor="linecolor")
223
+
224
+
225
+ host = host_subplot(122)
226
+ par = host.twinx()
227
+ host.set_xlabel("Number of factors $r$")
228
+ par.set_ylabel(r"$\nu$")
229
+
230
+ p1, = host.plot(df_r['r'].iloc[1:], -np.diff(df_r['deviance']), '-o', label='diff dev')
231
+ p2, = par.plot(df_r['r'].iloc[1:], np.diff(df_r['nu'])*c, '-o', label=r'diff $\nu$')
232
+
233
+ host.legend(labelcolor="linecolor")
234
+ host.set_xticks(df_r['r'].iloc[1:])
235
+ par.set_ylim(*host.get_ylim())
236
+
237
+ par.yaxis.get_label().set_color(p2.get_color())
238
+ par.tick_params(axis='y', colors=p2.get_color(), labelsize=14)
239
+ host.tick_params(axis='y', colors=p1.get_color(), labelsize=14)
240
+
241
+ return fig
242
+
243
+
@@ -0,0 +1,70 @@
1
+ Metadata-Version: 2.4
2
+ Name: causarray
3
+ Version: 0.0.1
4
+ Summary: causarray is a Python module for A Python package for simultaneous causal inference with an array of outcomes.
5
+ Author-email: Jin-Hong Du <jinhongd@andrew.cmu.com>, Maya Shen <myshen@andrew.cmu.edu>, Hansruedi Mathys <mathysh@pitt.edu>, Kathryn Roeder <jinhongd@andrew.cmu.com>
6
+ Maintainer-email: Jin-Hong Du <jinhongd@andrew.cmu.com>
7
+ License: MIT License
8
+ License-File: LICENSE
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Requires-Python: >=3.8
13
+ Requires-Dist: joblib
14
+ Requires-Dist: matplotlib
15
+ Requires-Dist: numba
16
+ Requires-Dist: numpy
17
+ Requires-Dist: pandas
18
+ Requires-Dist: pip
19
+ Requires-Dist: scikit-learn
20
+ Requires-Dist: scipy
21
+ Requires-Dist: sklearn-ensemble-cv
22
+ Requires-Dist: statsmodels
23
+ Requires-Dist: tqdm
24
+ Description-Content-Type: text/markdown
25
+
26
+ # causarray
27
+
28
+ Advances in single-cell sequencing and CRISPR technologies have enabled detailed case-control comparisons and experimental perturbations at single-cell resolution. However, uncovering causal relationships in observational genomic data remains challenging due to selection bias and inadequate adjustment for unmeasured confounders, particularly in heterogeneous datasets. To address these challenges, we introduce `causarray` [Du25], a doubly robust causal inference framework for analyzing array-based genomic data at both bulk-cell and single-cell levels. `causarray` integrates a generalized confounder adjustment method to account for unmeasured confounders and employs semiparametric inference with flexible machine learning techniques to ensure robust statistical estimation of treatment effects.
29
+
30
+
31
+ # Requirements
32
+
33
+ The dependencies for running `causarray` method are listed in `environment.yml` and can be installed by running
34
+
35
+ ```cmd
36
+ PIP_NO_DEPS=1 conda env create -f environment.yml
37
+ ```
38
+
39
+
40
+
41
+
42
+ <!--
43
+ # Development
44
+
45
+ ## Build
46
+ ```cmd
47
+ git tag 0.0.0
48
+ git tag --delete 1.0.0
49
+ python -m pip install .
50
+ ```
51
+
52
+ ## Testing
53
+ ```cmd
54
+ python -m pytest tests/test_gcate.py
55
+ python -m pytest tests/test_DR_learner.py
56
+ ```
57
+
58
+ ## Documentation
59
+
60
+ ```cmd
61
+ mkdir docs
62
+ sphinx-quickstart
63
+ cd docs
64
+ make html # sphinx-build source build
65
+ ```
66
+ -->
67
+
68
+
69
+ # References
70
+ [Du25] Jin-Hong Du, Maya Shen, Hansruedi Mathys, and Kathryn Roeder (2025). Causal differential expression analysis under unmeasured confounders with causarray. bioRxiv, 2025-01.
@@ -0,0 +1,14 @@
1
+ causarray/DR_estimation.py,sha256=wc8jsz1XjsXX5Vp6grbwvEYV8j1MHB-VA70wYbyYUEw,9050
2
+ causarray/DR_inference.py,sha256=0r5qxXTgvw-49ItP5TePC7KCDu4b8XrzgnlJfVWRcZo,5323
3
+ causarray/DR_learner.py,sha256=DdgGbVmvNbF-TulF5XGMvf5mf7Exd2uPPOoBeyRf4Ug,9404
4
+ causarray/__about__.py,sha256=sXLh7g3KC4QCFxcZGBTpG2scR7hmmBsMjq6LqRptkRg,22
5
+ causarray/__init__.py,sha256=bTyCz9EY3NVccFb472w7gqMxrmidBsxHZjlsfMawPsk,657
6
+ causarray/gcate.py,sha256=pnx8O-OnJl6VDjCF1RkgCuruQJVymTrGljc1V0jnRsc,8478
7
+ causarray/gcate_glm.py,sha256=lpVvsH2lDsmxvqzrXA9sbRf7bZed4of_rtM10eZHE2s,8956
8
+ causarray/gcate_likelihood.py,sha256=srs2ql2uEhgn386w1lES41E_Gb0EKHT5YDIW-25YDec,4797
9
+ causarray/gcate_opt.py,sha256=w3KWQiBfwek1O8uslFXPoDBol3XWj0U2yBYZ4WmMJxM,10589
10
+ causarray/utils.py,sha256=fTrah_QX1C6FF6p2i-O1Y9_tljdjYcmxLkWE0tCbrJU,6765
11
+ causarray-0.0.1.dist-info/METADATA,sha256=AoarxDPfvp0qQv1PSSkRwZsNGaEfcPTn0lj6DJ1SirY,2425
12
+ causarray-0.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
13
+ causarray-0.0.1.dist-info/licenses/LICENSE,sha256=4zFElAgYMtL4dKsu0A1p70cEo2SXRsGEWmJFdFb2hNg,1067
14
+ causarray-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Du Jinhong
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.