ScreenPro2 0.2.2__py2.py3-none-any.whl → 0.2.2.dev0__py2.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ScreenPro2
3
- Version: 0.2.2
3
+ Version: 0.2.2.dev0
4
4
  Summary: Analyze pooled CRISPR screens
5
5
  Requires-Python: >=3.8
6
6
  License-File: LICENSE
@@ -0,0 +1,9 @@
1
+ screenpro/__init__.py,sha256=W5BLfOHj3Erjw5RRqw6q4ofJikfy2kW-wUBflZmNqeQ,4547
2
+ screenpro/__version__.py,sha256=fOKWLKpu5Xtkvy8PKHXIlkrE5ExJD3i6TGBg_27cSG0,26
3
+ screenpro/load.py,sha256=M6d7jEWp_MIj2e6zK9X0DmthMTKHH3TIaWx3EQ1LP0U,2009
4
+ screenpro/phenoScore.py,sha256=R-jassjPokhbnzHJHyclYjr2CPHdiBiQAH8tRty2zyo,6494
5
+ ScreenPro2-0.2.2.dev0.dist-info/LICENSE,sha256=IHBn522sDxLGxi5EfDS9CZdqnW11ZeDrUxqkRfIbJR4,1072
6
+ ScreenPro2-0.2.2.dev0.dist-info/METADATA,sha256=ONEbQhfYXGi7Y1EGAu-qyZ-yOS6eZHdREoijxBiA-GA,144
7
+ ScreenPro2-0.2.2.dev0.dist-info/WHEEL,sha256=bb2Ot9scclHKMOLDEHY6B2sicWOgugjFKaJsT7vwMQo,110
8
+ ScreenPro2-0.2.2.dev0.dist-info/top_level.txt,sha256=uOEhN69bjK8D-lUo9aFehqGZQiGp8ouTSdzTDvZ4aek,10
9
+ ScreenPro2-0.2.2.dev0.dist-info/RECORD,,
screenpro/__init__.py CHANGED
@@ -1,2 +1,111 @@
1
+ import pandas as pd
1
2
  from .__version__ import __version__
2
- from . import phenoScore
3
+ from .phenoScore import seqDepthNormalization, matrixStat, matrixTest
4
+
5
+
6
+ def runPhenoScoreByReps(adata,
7
+ cond1, cond2, growth_rate=1, n_reps=2,
8
+ ctrl_label='negCtrl', test='ttest', math='log2(x+1)'):
9
+ """Calculate phenotype score and p-values comparing `cond2` vs `cond1`
10
+ """
11
+ result_name = f'{cond2}_vs_{cond1}'
12
+ print(f'\t{cond2} vs {cond1}')
13
+
14
+ count_layer = 'seq_depth_norm'
15
+ # check if count_layer exists
16
+ if 'seq_depth_norm' not in adata.layers.keys():
17
+ seqDepthNormalization(adata)
18
+ # prep counts for phenoScore calculation
19
+ df_cond1 = adata[adata.obs.query(f'condition=="{cond1}"').index[:n_reps], ].to_df(count_layer).T
20
+ df_cond2 = adata[adata.obs.query(f'condition=="{cond2}"').index[:n_reps], ].to_df(count_layer).T
21
+
22
+ x = df_cond1.to_numpy()
23
+ y = df_cond2.to_numpy()
24
+
25
+ x_ctrl = df_cond1[adata.var.targetType.eq(ctrl_label)].to_numpy()
26
+ y_ctrl = df_cond2[adata.var.targetType.eq(ctrl_label)].to_numpy()
27
+
28
+ # calculate growth score and p_value
29
+ scores, p_values = matrixTest(
30
+ x=x, y=y, x_ctrl=x_ctrl, y_ctrl=y_ctrl,
31
+ math=math, ave_reps=True, test=test, growth_rate=growth_rate
32
+ )
33
+
34
+ return scores, p_values, result_name
35
+
36
+
37
+ def runPhenoScoreByGuideSet(adata,
38
+ cond1, cond2, growth_rate=1, n_reps=2,
39
+ ctrl_label='negCtrl', test='ttest', math='log2(x+1)'
40
+ ):
41
+ """Calculate phenotype score and p-values comparing `cond2` vs `cond1`
42
+ """
43
+ print(f'\t{cond2} vs {cond1}')
44
+
45
+ count_layer = 'seq_depth_norm'
46
+ # check if count_layer exists
47
+ if 'seq_depth_norm' not in adata.layers.keys():
48
+ seqDepthNormalization(adata)
49
+ # prep counts for phenoScore calculation
50
+ pass
51
+
52
+
53
+ def convertResultsToDataFrame(adata, targets, scores, pvalues):
54
+ return pd.concat([
55
+ pd.Series(targets, index=adata.var.index, name='target'),
56
+ pd.Series(scores, index=adata.var.index, name='score'),
57
+ pd.Series(pvalues, index=adata.var.index, name='pvalue')
58
+ ], axis=1)
59
+
60
+
61
+ class ScreenPro(object):
62
+ """`ScreenPro` class for processing CRISPR screen datasets
63
+ """
64
+
65
+ def __init__(self, adata, math='log2(x+1)'):
66
+ self.phenotypes = {}
67
+ self.adata = adata
68
+ self.math = math
69
+
70
+ def __repr__(self):
71
+ descriptions = ''
72
+ for scoreLevel in self.phenotypes.keys():
73
+ scores = "', '".join(self.phenotypes[scoreLevel].columns.get_level_values(0).unique().to_list())
74
+ descriptions += f"Phenotypes in scoreLevel = '{scoreLevel}':\n scores: '{scores}'\n"
75
+
76
+ return f'obs->samples\nvar->oligos\n\n{self.adata.__repr__()}\n\n{descriptions}'
77
+
78
+ def calculateDrugScreen(self,
79
+ t0, untreated, treated, growth_rate,
80
+ scoreLevel, method):
81
+ """Calculate gamma, rho, and tau phenotype scores using given `method` in `scoreLevel`
82
+ """
83
+ if method == 'ByReps':
84
+ gamma, gamma_pv, gamma_name= runPhenoScoreByReps(
85
+ self.adata, cond1=t0, cond2=untreated, growth_rate=growth_rate, math=self.math)
86
+ tau, tau_pv, tau_name = runPhenoScoreByReps(
87
+ self.adata, cond1=t0, cond2=treated, growth_rate=growth_rate, math=self.math)
88
+ rho, rho_pv, rho_name = runPhenoScoreByReps(
89
+ self.adata, cond1=untreated, cond2=treated, growth_rate=growth_rate, math=self.math)
90
+ targets = self.adata.var.index.str.split('_[-,+]_').str[0].to_list()
91
+
92
+ self.phenotypes[scoreLevel] = pd.concat({
93
+ f'rho:{rho_name}': convertResultsToDataFrame(self.adata, targets, rho, rho_pv),
94
+ f'gamma:{gamma_name}': convertResultsToDataFrame(self.adata, targets, gamma, gamma_pv),
95
+ f'tau:{tau_name}': convertResultsToDataFrame(self.adata, targets, tau, tau_pv)
96
+ }, axis=1)
97
+
98
+ elif method == 'ByGuideSet':
99
+ pass
100
+
101
+ else:
102
+ raise ValueError('Method not recognized')
103
+
104
+ # adata.var[f'condition_{cond2}_vs_{cond1}_pvalue'] = pvalues
105
+ # adata.var[f'condition_{cond2}_vs_{cond1}_delta'] = phenotype_score
106
+ ## calculate FDR
107
+ # Calculate the adjusted p-values using the Benjamini-Hochberg method
108
+ # _, adj_pvalues, _, _ = multipletests(adata.var[f'condition_{cond1}_vs_{cond2}_pvalue'], alpha=0.05, method='fdr_bh')
109
+ # adata.var[f'condition_{cond1}_vs_{cond2}_adj_pvalue'] = adj_pvalues
110
+
111
+
screenpro/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.2.2"
1
+ __version__ = "0.2.2-dev"
screenpro/phenoScore.py CHANGED
@@ -3,7 +3,6 @@
3
3
 
4
4
  import numpy as np
5
5
  import pandas as pd
6
- import anndata as ad
7
6
 
8
7
  from pydeseq2 import preprocessing
9
8
  from scipy.stats import ttest_rel
@@ -12,64 +11,147 @@ from scipy.stats import ttest_rel
12
11
 
13
12
 
14
13
  def seqDepthNormalization(adata):
14
+ """Normalize counts by sequencing depth
15
+ """
15
16
  norm_counts, size_factors = preprocessing.deseq2_norm(adata.X)
16
17
 
17
18
  adata.obs['size_factors'] = size_factors
18
19
  adata.layers['seq_depth_norm'] = norm_counts
19
20
 
20
21
 
21
- def getDelta(x, y, math='log2'):
22
- """log ratio of y / x, averaged across replicates
22
+ def addPseudoCount():
23
+ pass
24
+ # # pseudocount
25
+ # if pseudocountBehavior == 'default' or pseudocountBehavior == 'zeros only':
26
+ # def defaultBehavior(row):
27
+ # return row if min(
28
+ # row) != 0 else row + pseudocountValue
29
+ #
30
+ # combinedCountsPseudo = combinedCounts.apply(defaultBehavior, axis=1)
31
+ # elif pseudocountBehavior == 'all values':
32
+ # combinedCountsPseudo = combinedCounts.apply(
33
+ # lambda row: row + pseudocountValue, axis=1)
34
+ # elif pseudocountBehavior == 'filter out':
35
+ # combinedCountsPseudo = combinedCounts.copy()
36
+ # zeroRows = combinedCounts.apply(lambda row: min(row) <= 0, axis=1)
37
+ # combinedCountsPseudo.loc[zeroRows, :] = np.nan
38
+ # else:
39
+ # raise ValueError(
40
+ # 'Pseudocount behavior not recognized or not implemented')
41
+
42
+
43
+ def getDelta(x, y, math, ave):
44
+ """log ratio of y / x
45
+ `ave` == 'all' – i.e. averaged across all values, oligo and replicates
46
+ `ave` == 'col' – i.e. averaged across columns, replicates)
47
+ """
48
+ if ave == 'all':
49
+ # average across all values
50
+ if math == 'log2(x+1)':
51
+ return np.mean(np.log2(y+1) - np.log2(x+1))
52
+ elif math == 'log10':
53
+ return np.mean(np.log10(y) - np.log10(x))
54
+ elif math == 'log1p':
55
+ return np.mean(np.log1p(y) - np.log1p(x))
56
+ elif ave == 'row':
57
+ # average across rows
58
+ if math == 'log2(x+1)':
59
+ return np.mean(np.log2(y+1) - np.log2(x+1), axis=0)
60
+ elif math == 'log10':
61
+ return np.mean(np.log10(y) - np.log10(x), axis=0)
62
+ elif math == 'log1p':
63
+ return np.mean(np.log1p(y) - np.log1p(x), axis=0)
64
+ elif ave == 'col':
65
+ # average across columns
66
+ if math == 'log2(x+1)':
67
+ return np.mean(np.log2(y+1) - np.log2(x+1), axis=1)
68
+ elif math == 'log10':
69
+ return np.mean(np.log10(y) - np.log10(x), axis=1)
70
+ elif math == 'log1p':
71
+ return np.mean(np.log1p(y) - np.log1p(x), axis=1)
72
+
73
+
74
+ def getScore(x, y, x_ctrl, y_ctrl, growth_rate, math, ave):
75
+ """Calculate phenotype score normalized by negative control and growth rate
23
76
  """
24
- if math == 'log2':
25
- return np.mean(np.log2(y) - np.log2(x), axis=1)
26
- elif math == 'log10':
27
- return np.mean(np.log10(y) - np.log10(x), axis=1)
28
- elif math == 'log1p':
29
- return np.mean(np.log1p(y) - np.log1p(x), axis=1)
77
+ ctrl_std = np.std(getDelta(x=x_ctrl, y=y_ctrl, math=math, ave=ave))
78
+ ctrl_median = np.median(getDelta(x=x_ctrl, y=y_ctrl, math=math, ave=ave))
79
+ delta = getDelta(x=x, y=y, math=math, ave=ave)
80
+
81
+ return ((delta - ctrl_median) / growth_rate) / ctrl_std
30
82
 
31
83
 
32
- def getScore(x, y, x_ctrl, y_ctrl, growth_rate):
84
+ def generatePseudoGeneLabels(adata, num_pseudogenes=None, ctrl_label='negCtrl'):
85
+ """Generate new labels per `num_pseudogenes` randomly selected non targeting oligo in `adata.var`
33
86
  """
87
+ if num_pseudogenes is None:
88
+ num_pseudogenes = len(adata.var[adata.var.targetType.eq(ctrl_label)]) // 2
89
+ # get non-targeting oligos
90
+ ctrl_oligos = adata.var[adata.var.targetType.eq(ctrl_label)].index
91
+ adata.var['pseudoLabel'] = ''
92
+ # check if there are more than 1 non-targeting oligos to label as pseudogenes
93
+ if len(ctrl_oligos) / 2 <= num_pseudogenes:
94
+ raise TypeError("Define `num_pseudogenes` to be less than total number of non-targeting oligos / 2")
95
+ else:
96
+ while len(ctrl_oligos) > num_pseudogenes:
97
+ # randomly select `num` non-targeting oligos
98
+ pseudo_oligos = np.random.choice(ctrl_oligos, num_pseudogenes, replace=False)
99
+ # generate new labels
100
+ pseudo_labels = [f'pseudo_{i}' for i in range(num_pseudogenes)]
101
+ # update adata.var
102
+ adata.var.loc[pseudo_oligos, 'pseudoLabel'] = pseudo_labels
103
+ # ...
104
+ ctrl_oligos = ctrl_oligos.drop(pseudo_oligos)
105
+
106
+ adata.var.loc[adata.var.targetType.eq('gene'), 'pseudoLabel'] = 'gene'
107
+ adata.var.loc[adata.var.pseudoLabel.eq(''), 'pseudoLabel'] = np.nan
108
+
109
+
110
+ def matrixStat(x, y, test, ave_reps):
111
+ """Get p-values comparing `y` vs `x` matrices
34
112
  """
35
- ctrl_std = np.std(getDelta(x_ctrl, y_ctrl))
36
- ctrl_median = np.median(getDelta(x_ctrl, y_ctrl))
113
+ # calculate p-values
114
+ if test == 'MW':
115
+ # run Mann-Whitney U rank test
116
+ pass
117
+ elif test == 'ttest':
118
+ # run ttest
119
+ if ave_reps:
120
+ p_value = ttest_rel(y, x, axis=1)[1]
37
121
 
38
- return ((getDelta(x,y) - ctrl_median) / growth_rate) / ctrl_std
122
+ else:
123
+ p_value = ttest_rel(y, x)[1]
39
124
 
125
+ return p_value
126
+ else:
127
+ raise ValueError(f'Test "{test}" not recognized')
40
128
 
41
- def runPhenoScore(adata, cond1, cond2, growth_rate=1, n_reps=2, test='ttest', layer='seq_depth_norm'):
42
- # prep fqcounter
43
- df_cond1 = adata[adata.obs.query(f'condition=="{cond1}"').index[:n_reps], ].to_df(layer).T
44
- df_cond2 = adata[adata.obs.query(f'condition=="{cond2}"').index[:n_reps], ].to_df(layer).T
45
129
 
46
- x = df_cond1.to_numpy()
47
- y = df_cond2.to_numpy()
130
+ def matrixTest(x, y, x_ctrl, y_ctrl, math, ave_reps, test = 'ttest', growth_rate = 1):
131
+ """Calculate phenotype score and p-values comparing `y` vs `x` matrices
132
+ """
133
+ if ave_reps:
134
+ ave = 'col'
135
+ else:
136
+ ave = 'all'
48
137
 
49
- x_ctrl = df_cond1[adata.var.targetType.eq('negCtrl')].to_numpy()
50
- y_ctrl = df_cond2[adata.var.targetType.eq('negCtrl')].to_numpy()
51
-
52
138
  # calculate growth score
53
- phenotype_score = getScore(x, y, x_ctrl, y_ctrl, growth_rate)
54
-
55
- adata.var[f'condition_{cond2}_vs_{cond1}_delta'] = phenotype_score
56
-
57
- # calculate p-values
58
- if test == 'MW':
59
- # run Mann-Whitney U rank test on replicates
60
- pass
61
- if test == 'ttest':
62
- # run ttest on replicates
63
- pvalues = ttest_rel(y, x, axis=1)[1]
64
- adata.var[f'condition_{cond2}_vs_{cond1}_pvalue'] = pvalues
65
-
66
- ## calculate FDR
67
- # Calculate the adjusted p-values using the Benjamini-Hochberg method
68
- # _, adj_pvalues, _, _ = multipletests(adata.var[f'condition_{cond1}_vs_{cond2}_pvalue'], alpha=0.05, method='fdr_bh')
69
- # adata.var[f'condition_{cond1}_vs_{cond2}_adj_pvalue'] = adj_pvalues
70
-
71
-
139
+ scores = getScore(
140
+ x = x, y = y, x_ctrl = x_ctrl, y_ctrl = y_ctrl,
141
+ growth_rate = growth_rate, math = math,
142
+ ave = ave
143
+ )
144
+
145
+ # compute p-value
146
+ p_values = matrixStat(x, y, test=test, ave_reps=ave_reps)
147
+
148
+ return scores, p_values
149
+
150
+
72
151
  def ann_score_df(df_in, up_hit='resistance_hit', down_hit='sensitivity_hit', ctrl_label='non-targeting', threshold=10):
152
+ """Annotate score dataframe with hit labels using given `threshold`
153
+ (i.e. `score/pseudo_sd * -np.log10(pvalue) >= threshold`)
154
+ """
73
155
  df = df_in.copy()
74
156
 
75
157
  df.columns = ['target', 'score', 'pvalue']
@@ -78,8 +160,7 @@ def ann_score_df(df_in, up_hit='resistance_hit', down_hit='sensitivity_hit', ctr
78
160
 
79
161
  pseudo_sd = df[df['target'].str.contains(ctrl_label)]['score'].tolist()
80
162
  pseudo_sd = np.std(pseudo_sd)
81
- # print (pseudo_sd)
82
-
163
+
83
164
  df['label'] = '.'
84
165
 
85
166
  df.loc[
@@ -1,9 +0,0 @@
1
- screenpro/__init__.py,sha256=heNcvrsJwuisUqdpi4kljd2pzC9om9eW-RR7SYGLdfs,62
2
- screenpro/__version__.py,sha256=m6kyaNpwBcP1XYcqrelX2oS3PJuOnElOcRdBa9pEb8c,22
3
- screenpro/load.py,sha256=M6d7jEWp_MIj2e6zK9X0DmthMTKHH3TIaWx3EQ1LP0U,2009
4
- screenpro/phenoScore.py,sha256=ruEXInaG0DRAdJk2nM7Jt6Wh36GEq7_6tbkFqswiQ5k,3418
5
- ScreenPro2-0.2.2.dist-info/LICENSE,sha256=IHBn522sDxLGxi5EfDS9CZdqnW11ZeDrUxqkRfIbJR4,1072
6
- ScreenPro2-0.2.2.dist-info/METADATA,sha256=D842Yk9uKPUM5Kg6wfTi5vd9vqbV7lGSS0sRpffFGOU,139
7
- ScreenPro2-0.2.2.dist-info/WHEEL,sha256=bb2Ot9scclHKMOLDEHY6B2sicWOgugjFKaJsT7vwMQo,110
8
- ScreenPro2-0.2.2.dist-info/top_level.txt,sha256=uOEhN69bjK8D-lUo9aFehqGZQiGp8ouTSdzTDvZ4aek,10
9
- ScreenPro2-0.2.2.dist-info/RECORD,,