-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathpre_processing.py
More file actions
196 lines (175 loc) · 7.29 KB
/
Copy pathpre_processing.py
File metadata and controls
196 lines (175 loc) · 7.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# !/usr/bin/env python
import numpy as np
import pandas as pd
from sklearn.preprocessing import scale, minmax_scale
def read_csv(filename, take_log):
""" Read TPM data of a dataset saved in csv format
Format of the csv:
first row: sample labels
second row: cell labels
third row: cluster labels from Seurat
first column: gene symbols
Args:
filename: name of the csv file
take_log: whether do log-transformation on input data
Returns:
dataset: a dict with keys 'gene_exp', 'gene_sym', 'sample_labels', 'cell_labels', 'cluster_labels'
"""
dataset = {}
df = pd.read_csv(filename, header=None)
dat = df[df.columns[1:]].values
dataset['sample_labels'] = dat[0, :].astype(int)
dataset['cell_labels'] = dat[1, :].astype(int)
dataset['cluster_labels'] = dat[2, :].astype(int)
gene_sym = df[df.columns[0]].tolist()[3:]
gene_exp = dat[3:, :]
if take_log:
gene_exp = np.log2(gene_exp + 1)
dataset['gene_exp'] = gene_exp
dataset['gene_sym'] = gene_sym
return dataset
def read_cluster_similarity(filename, thr):
""" read cluster similarity matrix, convert into the format of pairs and weights
first line is cluster label, starting with 1
Args:
filename: filename of the cluster similarity matrix
thr: threshold for identifying corresponding clusters
Returns:
cluster_pairs: np matrix, num_pairs by 3 matrix
[cluster_idx_1, cluster_id_2, weight]
"""
df = pd.read_csv(filename, header=None)
cluster_matrix = df[df.columns[:]].values
cluster_matrix = cluster_matrix[1:, :]
# use blocks of zeros to determine which clusters belongs to which datasets
num_cls = cluster_matrix.shape[0]
dataset_idx = np.zeros(num_cls, dtype=int)
idx = 0
for i in range(num_cls - 1):
dataset_idx[i] = idx
if cluster_matrix[i, i + 1] != 0:
idx += 1
dataset_idx[num_cls - 1] = idx
num_datasets = idx + 1
# only retain pairs if cluster i in dataset a is most similar to cluster j in dataset b
local_max = np.zeros(cluster_matrix.shape, dtype=int)
for i in range(num_cls):
for j in range(num_datasets):
if dataset_idx[i] == j:
continue
tmp = cluster_matrix[i, :] * (dataset_idx == j)
local_max[i, np.argmax(tmp)] = 1
local_max = local_max + local_max.T
local_max[local_max > 0] = 1
cluster_matrix = cluster_matrix * local_max # only retain dataset local maximal pairs
cluster_matrix[cluster_matrix < thr] = 0
cluster_matrix[cluster_matrix > 0] = 1 # binarize
# construct cluster pairs
tmp_idx = np.nonzero(cluster_matrix)
valid_idx = tmp_idx[0] < tmp_idx[1] # remove duplicate pairs
cluster_pairs = np.zeros((sum(valid_idx), 3), dtype=float)
cluster_pairs[:, 0] = tmp_idx[0][valid_idx] + 1
cluster_pairs[:, 1] = tmp_idx[1][valid_idx] + 1
for i in range(cluster_pairs.shape[0]):
cluster_pairs[i, 2] = cluster_matrix[int(cluster_pairs[i, 0] - 1), int(cluster_pairs[i, 1] - 1)]
return cluster_pairs
def remove_duplicate_genes(gene_exp, gene_sym):
""" Remove duplicate gene symbols in a dataset
Chooses the one with highest mean value when there are duplicate genes
Args:
gene_exp: np matrix, num_genes by num_cells
gene_sym: length num_cells
Returns:
gene_exp
gene_sym
"""
dic = {} # create a dictionary of gene_sym to identify duplicate
for i in range(len(gene_sym)):
if not gene_sym[i] in dic:
dic[gene_sym[i]] = [i]
else:
dic[gene_sym[i]].append(i)
if (len(dic) == len(gene_sym)): # no duplicate
return gene_exp, gene_sym
remove_idx = [] # idx of gene symbols that will be removed
for sym, idx in dic.items():
if len(idx) > 1: # duplicate exists
# print('duplicate! ' + sym)
remain_idx = idx[np.argmax(np.mean(gene_exp[idx, :], axis=1))]
for i in idx:
if i != remain_idx:
remove_idx.append(i)
gene_exp = np.delete(gene_exp, remove_idx, 0)
for idx in sorted(remove_idx, reverse=True):
del gene_sym[idx]
# print("Remove duplicate genes, remaining genes: {}".format(len(gene_sym)))
return gene_exp, gene_sym
def intersection_idx(lists):
""" intersection of multiple lists. Returns intersection and corresponding indexes
Args:
lists: list of lists that need to intersect
Returns:
intersect_list: list of intersection result
"""
idx_dict_list = [] # create index dictionary
for l in lists:
idx_dict_list.append(dict((k, i) for i, k in enumerate(l)))
intersect_set = set(lists[0]) # create intersection result
for i in range(1, len(lists)):
intersect_set = set(lists[i]).intersection(intersect_set)
intersect_list = list(intersect_set)
# generate corresponding index of intersection
idx_list = []
for d in idx_dict_list:
idx_list.append([d[x] for x in intersect_list])
return intersect_list, idx_list
def intersect_dataset(dataset_list):
""" Only retain the intersection of genes among multiple datasets
Args:
dataset_list: list of datasets
Returns:
intersect_dataset_list: list of after intersection pf gene symbols
"""
dataset_labels = ['sample_labels', 'cell_labels', 'cluster_labels'] # labels in a dataset
intersect_dataset_list = []
gene_sym_lists = []
for i, dataset in enumerate(dataset_list):
gene_sym_lists.append(dataset['gene_sym'])
# intersection of gene symbols
gene_sym, idx_list = intersection_idx(gene_sym_lists)
# print("Intersection of genes: {}".format(len(gene_sym)))
# only retain the intersection of genes in each dataset
for dataset, idx in zip(dataset_list, idx_list):
dataset_tmp = {'gene_exp': dataset['gene_exp'][idx,:], 'gene_sym': gene_sym}
for l in dataset_labels:
if l in dataset:
dataset_tmp[l] = dataset[l]
intersect_dataset_list.append(dataset_tmp)
return intersect_dataset_list
def pre_processing(dataset_file_list, pre_process_paras):
""" pre-processing of multiple datasets
Args:
dataset_file_list: list of filenames of datasets
pre_process_paras: dict, parameters for pre-processing
Returns:
dataset_list: list of datasets
"""
# parameters
take_log = pre_process_paras['take_log']
standardization = pre_process_paras['standardization']
scaling = pre_process_paras['scaling']
dataset_list = []
for data_file in dataset_file_list:
dataset = read_csv(data_file, take_log)
if standardization:
scale(dataset['gene_exp'], axis=1, with_mean=True, with_std=True, copy=False)
if scaling: # scale to [0,1]
minmax_scale(dataset['gene_exp'], feature_range=(0, 1), axis=1, copy=False)
dataset_list.append(dataset)
dataset_list = intersect_dataset(dataset_list) # retain intersection of gene symbols
return dataset_list
if __name__ == '__main__':
dataset_file_list = ['data/muraro_seurat.csv', 'data/baron_human_seurat.csv']
pre_process_paras = {'take_log': True, 'standardization': True, 'scaling': True}
dataset_list = pre_processing(dataset_file_list, pre_process_paras)
print()