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.
- {ScreenPro2-0.2.2.dist-info → ScreenPro2-0.2.2.dev0.dist-info}/METADATA +1 -1
- ScreenPro2-0.2.2.dev0.dist-info/RECORD +9 -0
- screenpro/__init__.py +110 -1
- screenpro/__version__.py +1 -1
- screenpro/phenoScore.py +124 -43
- ScreenPro2-0.2.2.dist-info/RECORD +0 -9
- {ScreenPro2-0.2.2.dist-info → ScreenPro2-0.2.2.dev0.dist-info}/LICENSE +0 -0
- {ScreenPro2-0.2.2.dist-info → ScreenPro2-0.2.2.dev0.dist-info}/WHEEL +0 -0
- {ScreenPro2-0.2.2.dist-info → ScreenPro2-0.2.2.dev0.dist-info}/top_level.txt +0 -0
|
@@ -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
|
|
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
|
|
22
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
|
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
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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
|
-
|
|
47
|
-
y
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|