dspin 1.3.3__tar.gz → 1.3.5__tar.gz
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.
- {dspin-1.3.3/dspin.egg-info → dspin-1.3.5}/PKG-INFO +14 -2
- {dspin-1.3.3 → dspin-1.3.5}/dspin/annotate.py +0 -1
- {dspin-1.3.3 → dspin-1.3.5}/dspin/compute.py +1 -1
- {dspin-1.3.3 → dspin-1.3.5}/dspin/dspin.py +72 -25
- {dspin-1.3.3 → dspin-1.3.5}/dspin/plot.py +7 -1
- {dspin-1.3.3 → dspin-1.3.5/dspin.egg-info}/PKG-INFO +14 -2
- {dspin-1.3.3 → dspin-1.3.5}/setup.py +1 -1
- {dspin-1.3.3 → dspin-1.3.5}/LICENSE +0 -0
- {dspin-1.3.3 → dspin-1.3.5}/README.md +0 -0
- {dspin-1.3.3 → dspin-1.3.5}/__pycache__/__init__.cpython-310.pyc +0 -0
- {dspin-1.3.3 → dspin-1.3.5}/__pycache__/__init__.cpython-37.pyc +0 -0
- {dspin-1.3.3 → dspin-1.3.5}/__pycache__/compute.cpython-310.pyc +0 -0
- {dspin-1.3.3 → dspin-1.3.5}/__pycache__/compute.cpython-37.pyc +0 -0
- {dspin-1.3.3 → dspin-1.3.5}/__pycache__/dspin_abstract.cpython-310.pyc +0 -0
- {dspin-1.3.3 → dspin-1.3.5}/__pycache__/plot.cpython-310.pyc +0 -0
- {dspin-1.3.3 → dspin-1.3.5}/__pycache__/plotting.cpython-37.pyc +0 -0
- {dspin-1.3.3 → dspin-1.3.5}/dspin/__init__.py +0 -0
- {dspin-1.3.3 → dspin-1.3.5}/dspin.egg-info/SOURCES.txt +0 -0
- {dspin-1.3.3 → dspin-1.3.5}/dspin.egg-info/dependency_links.txt +0 -0
- {dspin-1.3.3 → dspin-1.3.5}/dspin.egg-info/requires.txt +0 -0
- {dspin-1.3.3 → dspin-1.3.5}/dspin.egg-info/top_level.txt +0 -0
- {dspin-1.3.3 → dspin-1.3.5}/requirements.txt +0 -0
- {dspin-1.3.3 → dspin-1.3.5}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: dspin
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.5
|
|
4
4
|
Summary: Regulatory network models from single-cell perturbation profiling
|
|
5
5
|
Home-page: https://github.com/JialongJiang/DSPIN
|
|
6
6
|
Author: Jialong Jiang
|
|
@@ -25,6 +25,18 @@ Requires-Dist: scanpy
|
|
|
25
25
|
Requires-Dist: tqdm
|
|
26
26
|
Requires-Dist: igraph
|
|
27
27
|
Requires-Dist: leidenalg
|
|
28
|
+
Dynamic: author
|
|
29
|
+
Dynamic: author-email
|
|
30
|
+
Dynamic: classifier
|
|
31
|
+
Dynamic: description
|
|
32
|
+
Dynamic: description-content-type
|
|
33
|
+
Dynamic: home-page
|
|
34
|
+
Dynamic: keywords
|
|
35
|
+
Dynamic: license
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
Dynamic: requires-dist
|
|
38
|
+
Dynamic: requires-python
|
|
39
|
+
Dynamic: summary
|
|
28
40
|
|
|
29
41
|
# D-SPIN: Constructing regulatory network models from scRNA-seq perturbation profiling
|
|
30
42
|
|
|
@@ -108,7 +108,7 @@ def summary_components(all_components: np.array,
|
|
|
108
108
|
gene_weight = np.sum(all_components ** 2, axis=0) ** 0.5
|
|
109
109
|
gene_sele_filt = gene_weight > np.mean(gene_weight)
|
|
110
110
|
all_components_sub = all_components[:, gene_sele_filt]
|
|
111
|
-
kmeans_gene = KMeans(n_clusters=2 * num_spin, random_state=0, n_init=10).fit(all_components_sub.T)
|
|
111
|
+
kmeans_gene = KMeans(n_clusters=min(2 * num_spin, all_components_sub.shape[1]), random_state=0, n_init=10).fit(all_components_sub.T)
|
|
112
112
|
|
|
113
113
|
# Initialize an array to store the average component for each cluster.
|
|
114
114
|
components_kmeans = np.zeros((num_spin, num_gene))
|
|
@@ -207,6 +207,7 @@ class AbstractDSPIN(ABC):
|
|
|
207
207
|
self._samp_list = self._samp_list[example_list_ind]
|
|
208
208
|
raw_data = raw_data[example_list_ind]
|
|
209
209
|
self._raw_data = raw_data
|
|
210
|
+
print("Using a subset of {} samples for network inference.".format(len(self._samp_list)))
|
|
210
211
|
|
|
211
212
|
num_sample = len(raw_data)
|
|
212
213
|
params = {'num_epoch': 400,
|
|
@@ -497,6 +498,42 @@ class ProgramDSPIN(AbstractDSPIN):
|
|
|
497
498
|
def onmf_decomposition(self, value):
|
|
498
499
|
self._onmf_summary = value
|
|
499
500
|
|
|
501
|
+
def compute_onmf_expression(self,
|
|
502
|
+
sample_matrix: np.ndarray,
|
|
503
|
+
gene_group_ind: List[List[int]]):
|
|
504
|
+
"""
|
|
505
|
+
Compute the oNMF expression for a given sample matrix and gene components of each program.
|
|
506
|
+
|
|
507
|
+
Parameters
|
|
508
|
+
----------
|
|
509
|
+
sample_matrix : np.ndarray
|
|
510
|
+
The sample matrix containing gene expressions.
|
|
511
|
+
gene_group_ind : List[List[int]]
|
|
512
|
+
List of lists containing indices of genes for each program component.
|
|
513
|
+
|
|
514
|
+
Returns
|
|
515
|
+
-------
|
|
516
|
+
NMF
|
|
517
|
+
An NMF object containing the computed components.
|
|
518
|
+
"""
|
|
519
|
+
num_spin = self.num_spin
|
|
520
|
+
adata = self.adata
|
|
521
|
+
|
|
522
|
+
# Initialize and compute the summary matrix
|
|
523
|
+
components_summary = np.zeros((num_spin, adata.shape[1]))
|
|
524
|
+
for ii in range(num_spin):
|
|
525
|
+
sub_matrix = sample_matrix[:, gene_group_ind[ii]]
|
|
526
|
+
sub_onmf = NMF(n_components=1, init='random', random_state=0).fit(sub_matrix)
|
|
527
|
+
components_summary[ii, gene_group_ind[ii]] = sub_onmf.components_
|
|
528
|
+
|
|
529
|
+
# Normalize the summary components and finalize the onmf_summary object
|
|
530
|
+
components_summary = normalize(components_summary, axis=1, norm='l2')
|
|
531
|
+
onmf_summary = NMF(n_components=num_spin, init='random', random_state=0)
|
|
532
|
+
onmf_summary.components_ = components_summary
|
|
533
|
+
|
|
534
|
+
return onmf_summary
|
|
535
|
+
|
|
536
|
+
|
|
500
537
|
def summarize_onmf_result(self,
|
|
501
538
|
large_subsample_matrix: np.ndarray,
|
|
502
539
|
num_onmf_components: int,
|
|
@@ -517,10 +554,6 @@ class ProgramDSPIN(AbstractDSPIN):
|
|
|
517
554
|
NMF
|
|
518
555
|
An NMF object containing the summarized components.
|
|
519
556
|
"""
|
|
520
|
-
|
|
521
|
-
# Retrieve the number of spins and annotated data
|
|
522
|
-
num_spin = self.num_spin
|
|
523
|
-
adata = self.adata
|
|
524
557
|
prior_programs_mask = self.prior_programs_mask
|
|
525
558
|
seed_list = self.onmf_parameters['seed_list']
|
|
526
559
|
summary_method = self.onmf_parameters['summary_method']
|
|
@@ -533,7 +566,7 @@ class ProgramDSPIN(AbstractDSPIN):
|
|
|
533
566
|
cur_onmf = np.load(self.save_path + f'onmf/onmf_components_{num_onmf_components}_repeat_{cur_seed}.npy', allow_pickle=True).item()
|
|
534
567
|
rec_components[ii] = cur_onmf.components_
|
|
535
568
|
|
|
536
|
-
all_components = rec_components.reshape(-1, np.sum(prior_programs_mask))
|
|
569
|
+
all_components = rec_components.reshape(- 1, np.sum(prior_programs_mask))
|
|
537
570
|
|
|
538
571
|
gene_group_ind = summary_components(all_components, num_onmf_components, summary_method=summary_method, figure_folder=self.fig_folder)
|
|
539
572
|
|
|
@@ -542,17 +575,8 @@ class ProgramDSPIN(AbstractDSPIN):
|
|
|
542
575
|
gene_group_ind = [sub_mask_ind[gene_list] for gene_list in gene_group_ind]
|
|
543
576
|
gene_group_ind += self.prior_programs_ind
|
|
544
577
|
|
|
545
|
-
#
|
|
546
|
-
|
|
547
|
-
for ii in range(num_spin):
|
|
548
|
-
sub_matrix = large_subsample_matrix[:, gene_group_ind[ii]]
|
|
549
|
-
sub_onmf = NMF(n_components=1, init='random', random_state=0).fit(sub_matrix)
|
|
550
|
-
components_summary[ii, gene_group_ind[ii]] = sub_onmf.components_
|
|
551
|
-
|
|
552
|
-
# Normalize the summary components and finalize the onmf_summary object
|
|
553
|
-
components_summary = normalize(components_summary, axis=1, norm='l2')
|
|
554
|
-
onmf_summary = NMF(n_components=num_spin, init='random', random_state=0)
|
|
555
|
-
onmf_summary.components_ = components_summary
|
|
578
|
+
# Evaluate the expression level of each program and the weights for each gene in the program
|
|
579
|
+
onmf_summary = self.compute_onmf_expression(large_subsample_matrix, gene_group_ind)
|
|
556
580
|
|
|
557
581
|
return onmf_summary
|
|
558
582
|
|
|
@@ -585,9 +609,9 @@ class ProgramDSPIN(AbstractDSPIN):
|
|
|
585
609
|
Parameters for discretization of the oNMF representation. Default is an empty dictionary.
|
|
586
610
|
"""
|
|
587
611
|
|
|
588
|
-
if mode not in ['compute_summary', 'compute_only', 'summary_only']:
|
|
612
|
+
if mode not in ['compute_summary', 'compute_only', 'summary_only', 'precomputed']:
|
|
589
613
|
raise ValueError(
|
|
590
|
-
'Mode must be one of compute_summary, compute_only, or
|
|
614
|
+
'Mode must be one of compute_summary, compute_only, summary_only, or precomputed.')
|
|
591
615
|
|
|
592
616
|
adata = self.adata
|
|
593
617
|
num_spin = self.num_spin
|
|
@@ -607,6 +631,7 @@ class ProgramDSPIN(AbstractDSPIN):
|
|
|
607
631
|
|
|
608
632
|
if onmf_parameters['num_subsample_large'] is None:
|
|
609
633
|
onmf_parameters['num_subsample_large'] = min(onmf_parameters['num_subsample'] * 5, adata.shape[0])
|
|
634
|
+
# print(onmf_parameters['num_subsample_large'])
|
|
610
635
|
|
|
611
636
|
if onmf_parameters['balance_method'] not in ['equal', 'proportional', 'squareroot', None]:
|
|
612
637
|
raise ValueError('balance_method must be one of equal, proportional, squareroot, or None')
|
|
@@ -619,7 +644,13 @@ class ProgramDSPIN(AbstractDSPIN):
|
|
|
619
644
|
prior_program_ind = [[np.where(adata.var_names == gene)[0][0] for gene in gene_list] for gene_list in prior_programs]
|
|
620
645
|
preprogram_flat = [gene for program in prior_programs for gene in program]
|
|
621
646
|
if len(prior_programs) > num_spin:
|
|
622
|
-
raise ValueError('Number of
|
|
647
|
+
raise ValueError('Number of prior programs must be less than the number of programs')
|
|
648
|
+
elif len(prior_programs) == num_spin:
|
|
649
|
+
warnings.warn('Number of prior programs is equal to the number of programs. No oNMF is performed.')
|
|
650
|
+
mode = 'summary_only'
|
|
651
|
+
elif len(prior_programs) == 0:
|
|
652
|
+
warnings.warn('Empty prior programs')
|
|
653
|
+
|
|
623
654
|
# Generate mask to exclude genes in prior programs from the annotated data
|
|
624
655
|
prior_program_mask = ~ np.isin(adata.var_names, preprogram_flat)
|
|
625
656
|
onmf_parameters['num_onmf_components'] -= len(prior_programs)
|
|
@@ -650,20 +681,36 @@ class ProgramDSPIN(AbstractDSPIN):
|
|
|
650
681
|
|
|
651
682
|
compute_onmf_decomposition(sub_gene_matrix_normed, num_onmf_components, seed=cur_seed, params=onmf_parameters, save_path=self.save_path + f'onmf/onmf_components_{num_onmf_components}_repeat_{cur_seed}.npy')
|
|
652
683
|
|
|
653
|
-
if mode == 'compute_summary' or mode == 'summary_only':
|
|
684
|
+
if mode == 'compute_summary' or mode == 'summary_only' or mode == 'precomputed':
|
|
685
|
+
|
|
686
|
+
cluster_label_raw = adata.obs[cluster_key].values
|
|
687
|
+
cluster_label = pd.factorize(cluster_label_raw)[0]
|
|
654
688
|
|
|
655
689
|
# Perform subsampling and standard deviation clipping on the matrix
|
|
656
|
-
std_clipped, sub_large_gene_matrix_normed = subsample_normalize_gene_matrix(
|
|
690
|
+
std_clipped, sub_large_gene_matrix_normed = subsample_normalize_gene_matrix(adata.X, cluster_label, num_subsample=onmf_parameters['num_subsample_large'], seed=seed, params=onmf_parameters)
|
|
657
691
|
self.matrix_std = std_clipped
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
692
|
+
|
|
693
|
+
if mode != 'precomputed':
|
|
694
|
+
# Summarize the oNMF decompositions
|
|
695
|
+
if num_onmf_components > 0:
|
|
696
|
+
onmf_summary = self.summarize_onmf_result(sub_large_gene_matrix_normed, num_onmf_components, num_repeat)
|
|
697
|
+
else:
|
|
698
|
+
onmf_summary = self.compute_onmf_expression(sub_large_gene_matrix_normed, prior_program_ind)
|
|
699
|
+
|
|
700
|
+
onmf_save_path = self.save_path + f'onmf/onmf_summary_total_{num_spin}_onmf_{num_onmf_components}_prior_{len(prior_program_ind)}.npy'
|
|
701
|
+
np.save(onmf_save_path, onmf_summary)
|
|
702
|
+
print(f"Consensus oNMF results saved to {onmf_save_path}")
|
|
703
|
+
else:
|
|
704
|
+
assert 'precomputed_onmf_path' in params.keys(), "For precomputed mode, 'precomputed_onmf_path' must be provided in params."
|
|
705
|
+
onmf_summary = np.load(params['precomputed_onmf_path'], allow_pickle=True).item()
|
|
661
706
|
|
|
662
707
|
self._onmf_summary = onmf_summary
|
|
663
708
|
|
|
664
709
|
# Save the gene programs to a CSV file
|
|
665
710
|
file_path = onmf_to_csv(onmf_summary.components_, adata.var_names, self.save_path + f'gene_programs_total_{num_spin}_onmf_{num_onmf_components}_prior_{len(prior_program_ind)}.csv', thres=0.01)
|
|
666
|
-
print('Gene
|
|
711
|
+
print('Gene program information saved to {}'.format(file_path))
|
|
712
|
+
file_wpath = onmf_to_csv(onmf_summary.components_, adata.var_names, self.save_path + f'gene_programs_total_{num_spin}_onmf_{num_onmf_components}_prior_{len(prior_program_ind)}_weights.csv', thres=0.01, if_write_weights=True)
|
|
713
|
+
# print('Gene programs saved to {}'.format(file_path))
|
|
667
714
|
self.gene_program_csv = file_path
|
|
668
715
|
|
|
669
716
|
gene_matrix = self.adata.X
|
|
@@ -21,7 +21,7 @@ from scipy import optimize
|
|
|
21
21
|
from scipy.spatial.distance import pdist
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
def onmf_to_csv(features, gene_name, file_path, thres=0.01):
|
|
24
|
+
def onmf_to_csv(features, gene_name, file_path, thres=0.01, if_write_weights=False):
|
|
25
25
|
"""
|
|
26
26
|
Extract gene names in ONMF to CSV.
|
|
27
27
|
|
|
@@ -30,6 +30,7 @@ def onmf_to_csv(features, gene_name, file_path, thres=0.01):
|
|
|
30
30
|
gene_name (List[str]): Names of the genes corresponding to feature indices.
|
|
31
31
|
file_path (str): Path of the file where the CSV will be written.
|
|
32
32
|
thres (float): Threshold value for filtering features.
|
|
33
|
+
if_write_weights (bool): If True, writes weights to the CSV file.
|
|
33
34
|
|
|
34
35
|
Returns:
|
|
35
36
|
str: Path of the created CSV file.
|
|
@@ -51,6 +52,11 @@ def onmf_to_csv(features, gene_name, file_path, thres=0.01):
|
|
|
51
52
|
cur_line.insert(0, spin)
|
|
52
53
|
write.writerow(cur_line) # Write the current line to the CSV file
|
|
53
54
|
|
|
55
|
+
if if_write_weights:
|
|
56
|
+
cur_line = [features[spin, ind].round(6) for ind in gene_ind]
|
|
57
|
+
cur_line.insert(0, f'Weights_{spin}')
|
|
58
|
+
write.writerow(cur_line)
|
|
59
|
+
|
|
54
60
|
# Read the created CSV, transpose it and save it again
|
|
55
61
|
pd_csv = pd.read_csv(file_path, names=range(rec_max_gene + 1))
|
|
56
62
|
pd_csv = pd_csv.transpose()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: dspin
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.5
|
|
4
4
|
Summary: Regulatory network models from single-cell perturbation profiling
|
|
5
5
|
Home-page: https://github.com/JialongJiang/DSPIN
|
|
6
6
|
Author: Jialong Jiang
|
|
@@ -25,6 +25,18 @@ Requires-Dist: scanpy
|
|
|
25
25
|
Requires-Dist: tqdm
|
|
26
26
|
Requires-Dist: igraph
|
|
27
27
|
Requires-Dist: leidenalg
|
|
28
|
+
Dynamic: author
|
|
29
|
+
Dynamic: author-email
|
|
30
|
+
Dynamic: classifier
|
|
31
|
+
Dynamic: description
|
|
32
|
+
Dynamic: description-content-type
|
|
33
|
+
Dynamic: home-page
|
|
34
|
+
Dynamic: keywords
|
|
35
|
+
Dynamic: license
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
Dynamic: requires-dist
|
|
38
|
+
Dynamic: requires-python
|
|
39
|
+
Dynamic: summary
|
|
28
40
|
|
|
29
41
|
# D-SPIN: Constructing regulatory network models from scRNA-seq perturbation profiling
|
|
30
42
|
|
|
@@ -21,7 +21,7 @@ install_requires = [
|
|
|
21
21
|
# ]
|
|
22
22
|
|
|
23
23
|
# Managing your version (adjust accordingly)
|
|
24
|
-
version = "1.3.
|
|
24
|
+
version = "1.3.5" # You can manage versioning in a more sophisticated way if needed
|
|
25
25
|
|
|
26
26
|
# Long description (usually a README file)
|
|
27
27
|
readme = open("README_PyPI.md").read() # Adjust the file name if necessary
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|