Class: Network

Inherits:
Object
  • Object
show all
Defined in:
lib/NetAnalyzer/network.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(layers) ⇒ Network

BASIC METHODS



13
14
15
16
17
18
19
20
# File 'lib/NetAnalyzer/network.rb', line 13

def initialize(layers)
	@nodes = {} 
	@edges = {}
	@adjacency_matrices = {}
	@layers = layers
	@association_values = {}
	@control_connections = {}
end

Instance Attribute Details

#association_valuesObject

Returns the value of attribute association_values.



9
10
11
# File 'lib/NetAnalyzer/network.rb', line 9

def association_values
  @association_values
end

#control_connectionsObject

Returns the value of attribute control_connections.



9
10
11
# File 'lib/NetAnalyzer/network.rb', line 9

def control_connections
  @control_connections
end

Instance Method Details

#add_edge(nodeID1, nodeID2) ⇒ Object



26
27
28
29
# File 'lib/NetAnalyzer/network.rb', line 26

def add_edge(nodeID1, nodeID2)
	query_edge(nodeID1, nodeID2)
	query_edge(nodeID2, nodeID1)
end

#add_nested_record(hash, node1, node2, val) ⇒ Object



298
299
300
301
302
303
304
305
# File 'lib/NetAnalyzer/network.rb', line 298

def add_nested_record(hash, node1, node2, val)
	query_node1 = hash[node1]
	if query_node1.nil?
		hash[node1] = {node2 => val}
	else
		query_node1[node2] = val
	end
end

#add_node(nodeID, nodeType = 0) ⇒ Object



22
23
24
# File 'lib/NetAnalyzer/network.rb', line 22

def add_node(nodeID, nodeType = 0)
	@nodes[nodeID] = Node.new(nodeID, nodeType)
end

#add_record(hash, node1, node2) ⇒ Object



289
290
291
292
293
294
295
296
# File 'lib/NetAnalyzer/network.rb', line 289

def add_record(hash, node1, node2)
	query = hash[node1]
	if query.nil?
		hash[node1] = [node2]
	else
		query << node2
	end
end

#clean_autorelations_on_association_valuesObject



142
143
144
145
146
# File 'lib/NetAnalyzer/network.rb', line 142

def clean_autorelations_on_association_values
	@association_values.each do |meth, values|
		values.select!{|relation| @nodes[relation[0]].type != @nodes[relation[1]].type}
	end
end

#generate_adjacency_matrix(layerA, layerB) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/NetAnalyzer/network.rb', line 123

def generate_adjacency_matrix(layerA, layerB)
	layerAidNodes = @nodes.select{|id, node| node.type == layerA}.keys
	layerBidNodes = @nodes.select{|id, node| node.type == layerB}.keys
	adjacency_matrix = []
	layerAidNodes.each do |nodeA|
		layerBidNodes.each do |nodeB|
			if @edges[nodeB].include?(nodeA)
				adjacency_matrix << 1
			else
				adjacency_matrix << 0
			end
		end
	end
	matrix = NMatrix.new([layerAidNodes.length, layerBidNodes.length], adjacency_matrix)
	all_info_matrix = [matrix, layerAidNodes, layerBidNodes]
	@adjacency_matrices[[layerA, layerB]] = all_info_matrix
	return all_info_matrix
end

#get_all_intersectionsObject



71
72
73
74
75
76
77
# File 'lib/NetAnalyzer/network.rb', line 71

def get_all_intersections
	intersection_lengths = []
	get_all_pairs do |node1, node2|
		intersection_lengths << intersection(node1, node2).length
	end
	return intersection_lengths
end

#get_all_pairs(args = {}) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/NetAnalyzer/network.rb', line 79

def get_all_pairs(args = {})
	default = {:meth => :all, :layers => :all}
	args = default.merge(args)
	if args[:layers] == :all
		nodeIDs = @nodes.keys
	else
		nodeIDs = []
		args[:layers].each do |layer|
			nodeIDs.concat(@nodes.select{|id, node| node.type == layer}.keys)
		end
	end

	if args[:meth] == :all
		while !nodeIDs.empty?
			node1 = nodeIDs.shift
			nodeIDs.each do |node2|
				yield(node1, node2)
			end
		end
	#elsif args[:meth] == :conn
		
	end
end

#get_association_by_transference_resources(firstPairLayers, secondPairLayers, lambda_value1 = 0.5, lambda_value2 = 0.5) ⇒ Object

association methods adjacency matrix based


Alaimo 2014, doi: 10.3389/fbioe.2014.00071



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/NetAnalyzer/network.rb', line 175

def get_association_by_transference_resources(firstPairLayers, secondPairLayers, lambda_value1 = 0.5, lambda_value2 = 0.5)
	matrix1 = @adjacency_matrices[firstPairLayers].first
	rowIds = @adjacency_matrices[firstPairLayers][1]
	matrix2 = @adjacency_matrices[secondPairLayers].first
	colIds =  @adjacency_matrices[secondPairLayers][2]
	m1rowNumber = matrix1.rows
	m1colNumber = matrix1.cols
	m2rowNumber = matrix2.rows
	m2colNumber = matrix2.cols
	#puts m1rowNumber, m1colNumber, m2rowNumber, m2colNumber
	matrix1Weight = graphWeights(m1colNumber, m1rowNumber, matrix1.transpose, lambda_value1)
	matrix2Weight = graphWeights(m2colNumber, m2rowNumber, matrix2.transpose, lambda_value2)
	matrixWeightProduct = matrix1Weight.dot(matrix2.dot(matrix2Weight))
	finalMatrix = matrix1.dot(matrixWeightProduct)
	relations = nmatrix2relations(finalMatrix, rowIds, colIds)
	@association_values[:transference] = relations
	return relations
end

#get_association_values(layers, base_layer, meth) ⇒ Object

ASSOCIATION METHODS



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/NetAnalyzer/network.rb', line 150

def get_association_values(layers, base_layer, meth)
	relations = [] #node A, node B, val
	if meth == :jaccard #all networks
		relations = get_jaccard_association(layers, base_layer)
	elsif meth == :simpson #all networks
		relations = get_simpson_association(layers, base_layer)
	elsif meth == :geometric #all networks
		relations = get_geometric_associations(layers, base_layer)
	elsif meth == :cosine #all networks
		relations = get_cosine_associations(layers, base_layer)
	elsif meth == :pcc #all networks
		relations = get_pcc_associations(layers, base_layer)
	elsif meth == :hypergeometric #all networks
		relations = get_hypergeometric_associations(layers, base_layer)
	elsif meth == :csi #all networks
		relations = get_csi_associations(layers, base_layer)
	elsif meth == :transference #tripartite networks
		relations = get_association_by_transference_resources(layers, base_layer)
	end
	return relations
end

#get_associations(layers, base_layer) ⇒ Object

association methods node pairs based


Bass 2013, doi:10.1038/nmeth.2728



197
198
199
200
201
202
203
204
205
206
207
# File 'lib/NetAnalyzer/network.rb', line 197

def get_associations(layers, base_layer) # BASE METHOD
	relations = []
	get_all_pairs(layers: layers) do |node1, node2|
		associatedIDs_node1 = @edges[node1].map{|id| @nodes[id]}.select{|node| node.type == base_layer}.map{|node| node.id}
		associatedIDs_node2 = @edges[node2].map{|id| @nodes[id]}.select{|node| node.type == base_layer}.map{|node| node.id}
		intersectedIDs = associatedIDs_node1 & associatedIDs_node2
		associationValue = yield(associatedIDs_node1, associatedIDs_node2, intersectedIDs, node1, node2)
		relations << [node1, node2, associationValue]  
	end
	return relations
end

#get_cosine_associations(layers, base_layer) ⇒ Object



238
239
240
241
242
243
244
245
# File 'lib/NetAnalyzer/network.rb', line 238

def get_cosine_associations(layers, base_layer)
	relations = get_associations(layers, base_layer) do |associatedIDs_node1, associatedIDs_node2, intersectedIDs, node1, node2|
		productLength = Math.sqrt(associatedIDs_node1.length * associatedIDs_node2.length)
		cosineValue = intersectedIDs.length/productLength
	end
	@association_values[:cosine] = relations
	return relations
end

#get_csi_associations(layers, base_layer) ⇒ Object



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/NetAnalyzer/network.rb', line 308

def get_csi_associations(layers, base_layer)
	pcc_relations = get_pcc_associations(layers, base_layer)
	clean_autorelations_on_association_values if layers.length > 1
	nx = get_nodes_layer(layers).length
	pcc_vals = {}
	node_rels = {}
	pcc_relations.each do |node1, node2, assoc_index|
		add_nested_record(pcc_vals, node1, node2, assoc_index.abs)
		add_nested_record(pcc_vals, node2, node1, assoc_index.abs)
		add_record(node_rels, node1, node2)
		add_record(node_rels, node2, node1)
	end
	relations = []
	pcc_relations.each do |node1, node2 ,assoc_index|
		pccAB = assoc_index - 0.05
		valid_nodes = 0
		node_rels[node1].each do |node|
			valid_nodes += 1 if pcc_vals[node1][node] >= pccAB
		end
		node_rels[node2].each do |node|
			valid_nodes += 1 if pcc_vals[node2][node] >= pccAB
		end
		csiValue = 1 - (valid_nodes-1).fdiv(nx) 
		# valid_nodes-1 is done due to the connection node1-node2 is counted twice (one for each loop)
		relations << [node1, node2, csiValue]
	end
	@association_values[:csi] = relations
	return relations
end

#get_edge_numberObject



52
53
54
55
# File 'lib/NetAnalyzer/network.rb', line 52

def get_edge_number
	node_connections = @edges.values.map{|connections| connections.length}.inject(0){|sum, n| sum + n}
	return node_connections/2
end

#get_geometric_associations(layers, base_layer) ⇒ Object



227
228
229
230
231
232
233
234
235
236
# File 'lib/NetAnalyzer/network.rb', line 227

def get_geometric_associations(layers, base_layer)
	#wang 2016 method
	relations = get_associations(layers, base_layer) do |associatedIDs_node1, associatedIDs_node2, intersectedIDs, node1, node2|	
		intersectedIDs = intersectedIDs.length**2
		productLength = Math.sqrt(associatedIDs_node1.length * associatedIDs_node2.length)
		geometricValue = intersectedIDs.to_f/productLength
	end
	@association_values[:geometric] = relations
	return relations
end

#get_hypergeometric_associations(layers, base_layer) ⇒ Object



262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/NetAnalyzer/network.rb', line 262

def get_hypergeometric_associations(layers, base_layer)
	ny = get_nodes_layer([base_layer]).length
	relations = get_associations(layers, base_layer) do |associatedIDs_node1, associatedIDs_node2, intersectedIDs, node1, node2|
		minLength = [associatedIDs_node1.length, associatedIDs_node2.length].min
		intersection_lengths = intersectedIDs.length
		sum = 0
		if intersection_lengths > 0
			nA = associatedIDs_node1.length
			nB = associatedIDs_node2.length
			#Using index from A layer proyected to B
			hyper_denom = binom(ny, nB)
			(intersection_lengths..minLength).each do |i|
				binom_product = binom(nA, i) * binom(ny - nA, nB - i)
				sum += binom_product.fdiv(hyper_denom)
			end
		end
		if sum == 0
			hypergeometricValue = 0
		else
			hypergeometricValue = -Math.log10(sum)
		end
		hypergeometricValue
	end
	@association_values[:hypergeometric] = relations
	return relations
end

#get_jaccard_association(layers, base_layer) ⇒ Object



209
210
211
212
213
214
215
216
# File 'lib/NetAnalyzer/network.rb', line 209

def get_jaccard_association(layers, base_layer)
	relations = get_associations(layers, base_layer) do |associatedIDs_node1, associatedIDs_node2, intersectedIDs, node1, node2|
		unionIDS = associatedIDs_node1 | associatedIDs_node2
		jaccValue = intersectedIDs.length.to_f/unionIDS.length		
	end
	@association_values[:jaccard] = relations
	return relations
end

#get_nodes_layer(layers) ⇒ Object



103
104
105
106
107
108
109
110
# File 'lib/NetAnalyzer/network.rb', line 103

def get_nodes_layer(layers)
	#for creating ny value in hypergeometric and pcc index
	nodes = []
	layers.each do |layer|
		nodes.concat(@nodes.select{|nodeId, node| node.type == layer}.values)
	end
	return nodes
end

#get_pcc_associations(layers, base_layer) ⇒ Object



247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/NetAnalyzer/network.rb', line 247

def get_pcc_associations(layers, base_layer)
	#for Ny calcule use get_nodes_layer
	ny = get_nodes_layer([base_layer]).length
	relations = get_associations(layers, base_layer) do |associatedIDs_node1, associatedIDs_node2, intersectedIDs, node1, node2|
		intersProd = intersectedIDs.length * ny
		nodesProd = associatedIDs_node1.length * associatedIDs_node2.length
		nodesSubs = intersProd - nodesProd
		nodesAInNetwork = ny - associatedIDs_node1.length
		nodesBInNetwork = ny - associatedIDs_node2.length
		pccValue = nodesSubs.to_f / Math.sqrt(nodesProd * nodesAInNetwork * nodesBInNetwork)
	end
	@association_values[:pcc] = relations
	return relations
end

#get_pred_rec(meth, cut_number = 100, top_number = 10000) ⇒ Object

Pandey 2007, Association Analysis-based Transformations for Protein Interaction Networks: A Function Prediction Case Study



381
382
383
384
385
386
387
388
389
390
# File 'lib/NetAnalyzer/network.rb', line 381

def get_pred_rec(meth, cut_number = 100, top_number = 10000)
	performance = [] #cut, pred, rec
	preds, limits = load_prediction(@association_values[meth])
	cuts = get_cuts(limits, cut_number)
	cuts.each do |cut|
		prec, rec = pred_rec(preds, cut, top_number)
		performance << [cut, prec, rec]
	end
	return performance
end

#get_simpson_association(layers, base_layer) ⇒ Object



218
219
220
221
222
223
224
225
# File 'lib/NetAnalyzer/network.rb', line 218

def get_simpson_association(layers, base_layer)
	relations = get_associations(layers, base_layer) do |associatedIDs_node1, associatedIDs_node2, intersectedIDs, node1, node2|
		minLength = [associatedIDs_node1.length, associatedIDs_node2.length].min
		simpsonValue = intersectedIDs.length.to_f/minLength
	end
	@association_values[:simpson] = relations
	return relations
end

#intersection(node1, node2) ⇒ Object



112
113
114
115
116
117
118
119
120
121
# File 'lib/NetAnalyzer/network.rb', line 112

def intersection(node1, node2)
	shared_nodes = []
	associatedIDs_node1 = @edges[node1]
	associatedIDs_node2 = @edges[node2]
	intersectedIDs = associatedIDs_node1 & associatedIDs_node2
	intersectedIDs.each do |id|
		shared_nodes << @nodes[id]
	end
	return shared_nodes
end

#load_control(ref_array) ⇒ Object

PERFORMANCE METHODS



341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
# File 'lib/NetAnalyzer/network.rb', line 341

def load_control(ref_array)
	control = {}
	ref_array.each do |node1, node2|
		if node2 != '-'
			query = control[node1]
			if query.nil?
				control[node1] = [node2]
			else
				query << node2
			end
		end
	end
	@control_connections = control
	return control
end

#load_network_by_pairs(file, layers, split_character = "\t") ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
# File 'lib/NetAnalyzer/network.rb', line 40

def load_network_by_pairs(file, layers, split_character="\t")
	File.open(file).each("\n") do |line|
		line.chomp!
		pair = line.split(split_character)
		node1 = pair[0]
		node2 = pair[1]
		add_node(node1, set_layer(layers, node1))
		add_node(node2, set_layer(layers, node2))
		add_edge(node1, node2)	
	end
end

#load_prediction(pairs_array) ⇒ Object



357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
# File 'lib/NetAnalyzer/network.rb', line 357

def load_prediction(pairs_array)
	pred = {}
	min = nil
	max = nil
	pairs_array.each do |key, label, score|
		query = pred[key]
		if !min.nil? && !max.nil?
			min = score if score < min
			max = score if score > max
		else
			min = score; max = score
		end
		if query.nil?
			pred[key] = [[label], [score]]
		else
			query.first << label
			query.last << score
		end
	end
	return pred, [min, max]
end

#plot(output_filename, layout = "dot") ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/NetAnalyzer/network.rb', line 57

def plot(output_filename, layout="dot")		
	roboWrite = File.open(output_filename, 'w')
	roboWrite.puts "digraph g {"
	@edges.each do |nodeID, associatedIDs|
		associatedIDs.each do |associatedID|
			roboWrite.puts "\"#{nodeID}\"->\"#{associatedID}\";"
		end
	end
	roboWrite.puts "}"
	roboWrite.close
	cmd = "#{layout} -Tpng #{output_filename} -o #{output_filename}.png"
	system(cmd)
end

#pred_rec(preds, cut, top) ⇒ Object



392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
# File 'lib/NetAnalyzer/network.rb', line 392

def pred_rec(preds, cut, top)
	predicted_labels = 0 #m
	true_labels = 0 #n
	common_labels = 0 # k
	@control_connections.each do |key, c_labels|
		true_labels += c_labels.length #n
		pred_info = preds[key]
		if !pred_info.nil?
			labels, scores = pred_info
			reliable_labels = get_reliable_labels(labels, scores, cut, top)
			predicted_labels += reliable_labels.length #m
			common_labels += (c_labels & reliable_labels).length #k
		end
	end
	#puts "cut: #{cut} trueL: #{true_labels} predL: #{predicted_labels} commL: #{common_labels}"
	prec = common_labels.to_f/predicted_labels
	rec = common_labels.to_f/true_labels
	prec = 0.0 if prec.nan?
	rec = 0.0 if rec.nan?
	return prec, rec
end

#query_edge(nodeA, nodeB) ⇒ Object



31
32
33
34
35
36
37
38
# File 'lib/NetAnalyzer/network.rb', line 31

def query_edge(nodeA, nodeB)
	query = @edges[nodeA]
	if query.nil?
		@edges[nodeA] = [nodeB]
	else
		query << nodeB
	end
end