opentox-ruby 3.0.1 → 3.1.0
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.
- data/ChangeLog +8 -0
- data/Rakefile +2 -3
- data/VERSION +1 -1
- data/lib/algorithm.rb +227 -675
- data/lib/authorization.rb +10 -8
- data/lib/compound.rb +47 -11
- data/lib/dataset.rb +50 -2
- data/lib/environment.rb +6 -1
- data/lib/model.rb +37 -72
- data/lib/opentox-ruby.rb +1 -1
- data/lib/parser.rb +115 -57
- data/lib/r-util.rb +354 -0
- data/lib/rest_client_wrapper.rb +1 -1
- data/lib/serializer.rb +47 -30
- data/lib/stratification.R +201 -0
- data/lib/task.rb +5 -1
- data/lib/transform.rb +520 -0
- data/lib/utils.rb +372 -0
- data/lib/validation.rb +52 -6
- metadata +413 -428
data/lib/utils.rb
ADDED
@@ -0,0 +1,372 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
|
4
|
+
module OpenTox
|
5
|
+
|
6
|
+
module Algorithm
|
7
|
+
|
8
|
+
include OpenTox
|
9
|
+
|
10
|
+
# Calculate physico-chemical descriptors.
|
11
|
+
# @param[Hash] Required keys: :dataset_uri, :pc_type
|
12
|
+
# @return[String] dataset uri
|
13
|
+
|
14
|
+
def self.pc_descriptors(params)
|
15
|
+
|
16
|
+
begin
|
17
|
+
ds = OpenTox::Dataset.find(params[:dataset_uri])
|
18
|
+
compounds = ds.compounds.collect
|
19
|
+
ambit_result_uri, smiles_to_inchi = get_pc_descriptors( { :compounds => compounds, :pc_type => params[:pc_type] } )
|
20
|
+
#ambit_result_uri = ["http://apps.ideaconsult.net:8080/ambit2/dataset/987103?" ,"feature_uris[]=http%3A%2F%2Fapps.ideaconsult.net%3A8080%2Fambit2%2Ffeature%2F4276789&", "feature_uris[]=http%3A%2F%2Fapps.ideaconsult.net%3A8080%2Fambit2%2Fmodel%2F16%2Fpredicted"] # for testing
|
21
|
+
LOGGER.debug "Ambit result uri for #{params.inspect}: '#{ambit_result_uri.to_yaml}'"
|
22
|
+
load_ds_csv(ambit_result_uri, smiles_to_inchi)
|
23
|
+
rescue Exception => e
|
24
|
+
LOGGER.debug "#{e.class}: #{e.message}"
|
25
|
+
LOGGER.debug "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
# Calculates PC descriptors via Ambit -- DO NOT OVERLOAD Ambit.
|
31
|
+
# @param[Hash] Required keys: :compounds, :pc_type
|
32
|
+
# @return[Array] Ambit result uri, piecewise (1st: base, 2nd: SMILES, 3rd+: features
|
33
|
+
def self.get_pc_descriptors(params)
|
34
|
+
|
35
|
+
begin
|
36
|
+
|
37
|
+
ambit_ds_service_uri = "http://apps.ideaconsult.net:8080/ambit2/dataset/"
|
38
|
+
ambit_mopac_model_uri = "http://apps.ideaconsult.net:8080/ambit2/model/69632"
|
39
|
+
descs = YAML::load_file( File.join(ENV['HOME'], ".opentox", "config", "ambit_descriptors.yaml") )
|
40
|
+
descs_uris = []
|
41
|
+
params[:pc_type] = "electronic,cpsa" if params[:pc_type].nil? # rescue missing pc_type
|
42
|
+
types = params[:pc_type].split(",")
|
43
|
+
descs.each { |uri, cat_name|
|
44
|
+
if types.include? cat_name[:category]
|
45
|
+
descs_uris << uri
|
46
|
+
end
|
47
|
+
}
|
48
|
+
if descs_uris.size == 0
|
49
|
+
raise "Error! Empty set of descriptors. Did you supply one of [geometrical, topological, electronic, constitutional, hybrid, cpsa] ?"
|
50
|
+
end
|
51
|
+
#LOGGER.debug "Ambit descriptor URIs: #{descs_uris.join(", ")}"
|
52
|
+
|
53
|
+
begin
|
54
|
+
# Create SMI
|
55
|
+
smiles_array = []; smiles_to_inchi = {}
|
56
|
+
params[:compounds].each do |n|
|
57
|
+
cmpd = OpenTox::Compound.new(n)
|
58
|
+
smiles_string = cmpd.to_smiles
|
59
|
+
smiles_to_inchi[smiles_string] = URI.encode_www_form_component(cmpd.to_inchi)
|
60
|
+
smiles_array << smiles_string
|
61
|
+
end
|
62
|
+
smi_file = Tempfile.open(['pc_ambit', '.csv'])
|
63
|
+
pc_descriptors = nil
|
64
|
+
|
65
|
+
# Create Ambit dataset
|
66
|
+
smi_file.puts( "SMILES\n" )
|
67
|
+
smi_file.puts( smiles_array.join("\n") )
|
68
|
+
smi_file.flush
|
69
|
+
ambit_ds_uri = OpenTox::RestClientWrapper.post(ambit_ds_service_uri, {:file => File.new(smi_file.path)}, {:content_type => "multipart/form-data", :accept => "text/uri-list"} )
|
70
|
+
rescue Exception => e
|
71
|
+
LOGGER.debug "#{e.class}: #{e.message}"
|
72
|
+
LOGGER.debug "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
|
73
|
+
ensure
|
74
|
+
smi_file.close! if smi_file
|
75
|
+
end
|
76
|
+
ambit_smiles_uri = OpenTox::RestClientWrapper.get(ambit_ds_uri + "/features", {:accept=> "text/uri-list"} ).chomp
|
77
|
+
|
78
|
+
# Calculate 3D for CPSA
|
79
|
+
if types.include? "cpsa"
|
80
|
+
ambit_ds_mopac_uri = OpenTox::RestClientWrapper.post(ambit_mopac_model_uri, {:dataset_uri => ambit_ds_uri}, {:accept => "text/uri-list"} )
|
81
|
+
LOGGER.debug "MOPAC dataset: #{ambit_ds_mopac_uri }"
|
82
|
+
end
|
83
|
+
|
84
|
+
# Get Ambit results
|
85
|
+
ambit_result_uri = [] # 1st pos: base uri, then features
|
86
|
+
ambit_result_uri << ambit_ds_uri + "?"
|
87
|
+
ambit_result_uri << ("feature_uris[]=" + URI.encode_www_form_component(ambit_smiles_uri) + "&")
|
88
|
+
descs_uris.each_with_index do |uri, i|
|
89
|
+
algorithm = Algorithm::Generic.new(uri)
|
90
|
+
result_uri = algorithm.run({:dataset_uri => ambit_ds_uri})
|
91
|
+
ambit_result_uri << result_uri.split("?")[1] + "&"
|
92
|
+
LOGGER.debug "Ambit (#{descs_uris.size}): #{i+1}"
|
93
|
+
end
|
94
|
+
#LOGGER.debug "Ambit result: #{ambit_result_uri.join('')}"
|
95
|
+
[ ambit_result_uri, smiles_to_inchi ]
|
96
|
+
|
97
|
+
rescue Exception => e
|
98
|
+
LOGGER.debug "#{e.class}: #{e.message}"
|
99
|
+
LOGGER.debug "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
# Load dataset via CSV
|
105
|
+
# @param[Array] Ambit result uri, piecewise (1st: base, 2nd: SMILES, 3rd+: features
|
106
|
+
# @return[String] dataset uri
|
107
|
+
def self.load_ds_csv(ambit_result_uri, smiles_to_inchi, subjectid=nil)
|
108
|
+
|
109
|
+
master=nil
|
110
|
+
(1...ambit_result_uri.size).collect { |idx|
|
111
|
+
curr_uri = ambit_result_uri[0] + ambit_result_uri[idx]
|
112
|
+
LOGGER.debug "Requesting #{curr_uri}"
|
113
|
+
csv_data = CSV.parse( OpenTox::RestClientWrapper.get(curr_uri, {:accept => "text/csv", :subjectid => subjectid}) )
|
114
|
+
if csv_data[0] && csv_data[0].size>1
|
115
|
+
if master.nil? # This is the smiles entry
|
116
|
+
(1...csv_data.size).each{ |idx| csv_data[idx][1] = smiles_to_inchi[csv_data[idx][1]] }
|
117
|
+
master = csv_data
|
118
|
+
next
|
119
|
+
else
|
120
|
+
index_uri = csv_data[0].index("SMILES")
|
121
|
+
csv_data.map {|i| i.delete_at(index_uri)} if index_uri #Removes additional SMILES information
|
122
|
+
|
123
|
+
nr_cols = (csv_data[0].size)-1
|
124
|
+
LOGGER.debug "Merging #{nr_cols} new columns"
|
125
|
+
master.each {|row| nr_cols.times { row.push(nil) } } # Adds empty columns to all rows
|
126
|
+
csv_data.each do |row|
|
127
|
+
temp = master.assoc(row[0]) # Finds the appropriate line in master
|
128
|
+
((-1*nr_cols)..-1).collect.each { |idx|
|
129
|
+
temp[idx] = row[nr_cols+idx+1] if temp # Updates columns if line is found
|
130
|
+
}
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
}
|
135
|
+
|
136
|
+
index_uri = master[0].index("Compound")
|
137
|
+
master.map {|i| i.delete_at(index_uri)}
|
138
|
+
master[0].each {|cell| cell.chomp!(" ")}
|
139
|
+
master[0][0] = "Compound" #"SMILES"
|
140
|
+
index_smi = master[0].index("SMILES")
|
141
|
+
master.map {|i| i.delete_at(index_smi)} if index_smi
|
142
|
+
#master[0][0] = "SMILES"
|
143
|
+
|
144
|
+
#LOGGER.debug "-------- AM: Writing to dumpfile"
|
145
|
+
#File.open("/tmp/test.csv", 'w') {|f| f.write( master.collect {|r| r.join(",")}.join("\n") ) }
|
146
|
+
|
147
|
+
parser = OpenTox::Parser::Spreadsheets.new
|
148
|
+
ds = OpenTox::Dataset.new(nil,subjectid)
|
149
|
+
ds.save(subjectid)
|
150
|
+
parser.dataset = ds
|
151
|
+
ds = parser.load_csv(master.collect{|r| r.join(",")}.join("\n"))
|
152
|
+
ds.save(subjectid)
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
# Gauss kernel
|
157
|
+
# @return [Float]
|
158
|
+
def self.gauss(x, sigma = 0.3)
|
159
|
+
d = 1.0 - x.to_f
|
160
|
+
Math.exp(-(d*d)/(2*sigma*sigma))
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
# For symbolic features
|
165
|
+
# @param [Array] Array to test, must indicate non-occurrence with 0.
|
166
|
+
# @return [Boolean] Whether the feature is singular or non-occurring or present everywhere.
|
167
|
+
def self.isnull_or_singular?(array)
|
168
|
+
nr_zeroes = array.count(0)
|
169
|
+
return (nr_zeroes == array.size) || # remove non-occurring feature
|
170
|
+
(nr_zeroes == array.size-1) || # remove singular feature
|
171
|
+
(nr_zeroes == 0) # also remove feature present everywhere
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
# Numeric value test
|
176
|
+
# @param[Object] value
|
177
|
+
# @return [Boolean] Whether value is a number
|
178
|
+
def self.numeric?(value)
|
179
|
+
true if Float(value) rescue false
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
# For symbolic features
|
184
|
+
# @param [Array] Array to test, must indicate non-occurrence with 0.
|
185
|
+
# @return [Boolean] Whether the feature has variance zero.
|
186
|
+
def self.zero_variance?(array)
|
187
|
+
return array.uniq.size == 1
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
# Sum of an array for Arrays.
|
192
|
+
# @param [Array] Array with values
|
193
|
+
# @return [Integer] Sum of size of values
|
194
|
+
def self.sum_size(array)
|
195
|
+
sum=0
|
196
|
+
array.each { |e| sum += e.size }
|
197
|
+
return sum
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
# Minimum Frequency
|
202
|
+
# @param [Integer] per-mil value
|
203
|
+
# return [Integer] min-frequency
|
204
|
+
def self.min_frequency(training_dataset,per_mil)
|
205
|
+
minfreq = per_mil * training_dataset.compounds.size.to_f / 1000.0 # AM sugg. 8-10 per mil for BBRC, 50 per mil for LAST
|
206
|
+
minfreq = 2 unless minfreq > 2
|
207
|
+
Integer (minfreq)
|
208
|
+
end
|
209
|
+
|
210
|
+
|
211
|
+
# Effect calculation for classification
|
212
|
+
# @param [Array] Array of occurrences per class in the form of Enumerables.
|
213
|
+
# @param [Array] Array of database instance counts per class.
|
214
|
+
def self.effect(occurrences, db_instances)
|
215
|
+
max=0
|
216
|
+
max_value=0
|
217
|
+
nr_o = self.sum_size(occurrences)
|
218
|
+
nr_db = db_instances.to_scale.sum
|
219
|
+
|
220
|
+
occurrences.each_with_index { |o,i| # fminer outputs occurrences sorted reverse by activity.
|
221
|
+
actual = o.size.to_f/nr_o
|
222
|
+
expected = db_instances[i].to_f/nr_db
|
223
|
+
if actual > expected
|
224
|
+
if ((actual - expected) / actual) > max_value
|
225
|
+
max_value = (actual - expected) / actual # 'Schleppzeiger'
|
226
|
+
max = i
|
227
|
+
end
|
228
|
+
end
|
229
|
+
}
|
230
|
+
max
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
# neighbors
|
235
|
+
|
236
|
+
module Neighbors
|
237
|
+
|
238
|
+
# Get confidence.
|
239
|
+
# @param[Hash] Required keys: :sims, :acts
|
240
|
+
# @return[Float] Confidence
|
241
|
+
def self.get_confidence(params)
|
242
|
+
conf = params[:sims].inject{|sum,x| sum + x }
|
243
|
+
confidence = conf/params[:sims].size
|
244
|
+
LOGGER.debug "Confidence is: '" + confidence.to_s + "'."
|
245
|
+
return confidence
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
249
|
+
|
250
|
+
|
251
|
+
# Similarity calculations
|
252
|
+
module Similarity
|
253
|
+
|
254
|
+
# Tanimoto similarity
|
255
|
+
# @param [Hash, Array] fingerprints of first compound
|
256
|
+
# @param [Hash, Array] fingerprints of second compound
|
257
|
+
# @return [Float] (Weighted) tanimoto similarity
|
258
|
+
def self.tanimoto(fingerprints_a,fingerprints_b,weights=nil,params=nil)
|
259
|
+
|
260
|
+
common_p_sum = 0.0
|
261
|
+
all_p_sum = 0.0
|
262
|
+
|
263
|
+
# fingerprints are hashes
|
264
|
+
if fingerprints_a.class == Hash && fingerprints_b.class == Hash
|
265
|
+
common_features = fingerprints_a.keys & fingerprints_b.keys
|
266
|
+
all_features = (fingerprints_a.keys + fingerprints_b.keys).uniq
|
267
|
+
if common_features.size > 0
|
268
|
+
common_features.each{ |f| common_p_sum += [ fingerprints_a[f], fingerprints_b[f] ].min }
|
269
|
+
all_features.each{ |f| all_p_sum += [ fingerprints_a[f],fingerprints_b[f] ].compact.max } # compact, since one fp may be empty at that pos
|
270
|
+
end
|
271
|
+
|
272
|
+
# fingerprints are arrays
|
273
|
+
elsif fingerprints_a.class == Array && fingerprints_b.class == Array
|
274
|
+
size = [ fingerprints_a.size, fingerprints_b.size ].min
|
275
|
+
LOGGER.warn "fingerprints don't have equal size" if fingerprints_a.size != fingerprints_b.size
|
276
|
+
(0...size).each { |idx|
|
277
|
+
common_p_sum += [ fingerprints_a[idx], fingerprints_b[idx] ].min
|
278
|
+
all_p_sum += [ fingerprints_a[idx], fingerprints_b[idx] ].max
|
279
|
+
}
|
280
|
+
end
|
281
|
+
|
282
|
+
(all_p_sum > 0.0) ? (common_p_sum/all_p_sum) : 0.0
|
283
|
+
|
284
|
+
end
|
285
|
+
|
286
|
+
|
287
|
+
# Cosine similarity
|
288
|
+
# @param [Hash] properties_a key-value properties of first compound
|
289
|
+
# @param [Hash] properties_b key-value properties of second compound
|
290
|
+
# @return [Float] cosine of angle enclosed between vectors induced by keys present in both a and b
|
291
|
+
def self.cosine(fingerprints_a,fingerprints_b,weights=nil)
|
292
|
+
|
293
|
+
# fingerprints are hashes
|
294
|
+
if fingerprints_a.class == Hash && fingerprints_b.class == Hash
|
295
|
+
a = []; b = []
|
296
|
+
common_features = fingerprints_a.keys & fingerprints_b.keys
|
297
|
+
if common_features.size > 1
|
298
|
+
common_features.each do |p|
|
299
|
+
a << fingerprints_a[p]
|
300
|
+
b << fingerprints_b[p]
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
# fingerprints are arrays
|
305
|
+
elsif fingerprints_a.class == Array && fingerprints_b.class == Array
|
306
|
+
a = fingerprints_a
|
307
|
+
b = fingerprints_b
|
308
|
+
end
|
309
|
+
|
310
|
+
(a.size > 0 && b.size > 0) ? self.cosine_num(a.to_gv, b.to_gv) : 0.0
|
311
|
+
|
312
|
+
end
|
313
|
+
|
314
|
+
|
315
|
+
# Cosine similarity
|
316
|
+
# @param [GSL::Vector] a
|
317
|
+
# @param [GSL::Vector] b
|
318
|
+
# @return [Float] cosine of angle enclosed between a and b
|
319
|
+
def self.cosine_num(a, b)
|
320
|
+
if a.size>12 && b.size>12
|
321
|
+
a = a[0..11]
|
322
|
+
b = b[0..11]
|
323
|
+
end
|
324
|
+
a.dot(b) / (a.norm * b.norm)
|
325
|
+
end
|
326
|
+
|
327
|
+
|
328
|
+
# Outlier detection based on Mahalanobis distances
|
329
|
+
# Multivariate detection on X, univariate detection on y
|
330
|
+
# Uses an existing Rinruby instance, if possible
|
331
|
+
# @param[Hash] Keys query_matrix, data_matrix, acts are required; r, p_outlier optional
|
332
|
+
# @return[Array] indices identifying outliers (may occur several times, this is intended)
|
333
|
+
def self.outliers(params)
|
334
|
+
outlier_array = []
|
335
|
+
data_matrix = params[:data_matrix]
|
336
|
+
query_matrix = params[:query_matrix]
|
337
|
+
acts = params[:acts]
|
338
|
+
begin
|
339
|
+
LOGGER.debug "Outliers (p=#{params[:p_outlier] || 0.9999})..."
|
340
|
+
r = ( params[:r] || RinRuby.new(false,false) )
|
341
|
+
r.eval "suppressPackageStartupMessages(library(\"robustbase\"))"
|
342
|
+
r.eval "outlier_threshold = #{params[:p_outlier] || 0.999}"
|
343
|
+
nr_cases, nr_features = data_matrix.to_a.size, data_matrix.to_a[0].size
|
344
|
+
r.odx = data_matrix.to_a.flatten
|
345
|
+
r.q = query_matrix.to_a.flatten
|
346
|
+
r.y = acts.to_a.flatten
|
347
|
+
r.eval "odx = matrix(odx, #{nr_cases}, #{nr_features}, byrow=T)"
|
348
|
+
r.eval 'odx = rbind(q,odx)' # query is nr 0 (1) in ruby (R)
|
349
|
+
r.eval 'mah = covMcd(odx)$mah' # run MCD alg
|
350
|
+
r.eval "mah = pchisq(mah,#{nr_features})"
|
351
|
+
r.eval 'outlier_array = which(mah>outlier_threshold)' # multivariate outliers using robust mahalanobis
|
352
|
+
outlier_array = r.outlier_array.to_a.collect{|v| v-2 } # translate to ruby index (-1 for q, -1 due to ruby)
|
353
|
+
r.eval 'fqu = matrix(summary(y))[2]'
|
354
|
+
r.eval 'tqu = matrix(summary(y))[5]'
|
355
|
+
r.eval 'outlier_array = which(y>(tqu+1.5*IQR(y)))' # univariate outliers due to Tukey (http://goo.gl/mwzNH)
|
356
|
+
outlier_array += r.outlier_array.to_a.collect{|v| v-1 } # translate to ruby index (-1 due to ruby)
|
357
|
+
r.eval 'outlier_array = which(y<(fqu-1.5*IQR(y)))'
|
358
|
+
outlier_array += r.outlier_array.to_a.collect{|v| v-1 }
|
359
|
+
rescue Exception => e
|
360
|
+
LOGGER.debug "#{e.class}: #{e.message}"
|
361
|
+
#LOGGER.debug "Backtrace:\n\t#{e.backtrace.join("\n\t")}"
|
362
|
+
end
|
363
|
+
outlier_array
|
364
|
+
end
|
365
|
+
|
366
|
+
end
|
367
|
+
|
368
|
+
|
369
|
+
end
|
370
|
+
|
371
|
+
end
|
372
|
+
|
data/lib/validation.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "yaml"
|
1
2
|
module OpenTox
|
2
3
|
class Validation
|
3
4
|
include OpenTox
|
@@ -66,7 +67,7 @@ module OpenTox
|
|
66
67
|
# @return [String] report uri
|
67
68
|
def find_or_create_report( subjectid=nil, waiting_task=nil )
|
68
69
|
@report = ValidationReport.find_for_validation(@uri, subjectid) unless @report
|
69
|
-
@report = ValidationReport.create(@uri, subjectid, waiting_task) unless @report
|
70
|
+
@report = ValidationReport.create(@uri, {}, subjectid, waiting_task) unless @report
|
70
71
|
@report.uri
|
71
72
|
end
|
72
73
|
|
@@ -107,6 +108,31 @@ module OpenTox
|
|
107
108
|
end
|
108
109
|
table
|
109
110
|
end
|
111
|
+
|
112
|
+
# returns probability-distribution for a given prediction
|
113
|
+
# it takes all predictions into account that have a confidence value that is >= confidence and that have the same predicted value
|
114
|
+
# (minimum 12 predictions with the hightest confidence are selected (even if the confidence is lower than the given param)
|
115
|
+
#
|
116
|
+
# @param [Float] confidence value (between 0 and 1)
|
117
|
+
# @param [String] predicted value
|
118
|
+
# @param [String,optional] subjectid
|
119
|
+
# @return [Hash] see example
|
120
|
+
#
|
121
|
+
# Example 1:
|
122
|
+
# validation.probabilities(0.3,"active")
|
123
|
+
# -> {:min_confidence=>0.32, :num_predictions=>20, :probs=>{"active"=>0.7, "moderate"=>0.25 "inactive"=>0.05}}
|
124
|
+
# there have been 20 "active" predictions with confidence >= 0.3, 70 percent of them beeing correct
|
125
|
+
#
|
126
|
+
# Example 2:
|
127
|
+
# validation.probabilities(0.8,"active")
|
128
|
+
# -> {:min_confidence=>0.45, :num_predictions=>12, :probs=>{"active"=>0.9, "moderate"=>0.1 "inactive"=>0}}
|
129
|
+
# the given confidence value was to high (i.e. <12 predictions with confidence value >= 0.8)
|
130
|
+
# the top 12 "active" predictions have a min_confidence of 0.45, 90 percent of them beeing correct
|
131
|
+
#
|
132
|
+
def probabilities( confidence, prediction, subjectid=nil )
|
133
|
+
YAML.load(OpenTox::RestClientWrapper.get(@uri+"/probabilities?prediction="+prediction.to_s+"&confidence="+confidence.to_s,
|
134
|
+
{:subjectid => subjectid, :accept => "application/x-yaml"}))
|
135
|
+
end
|
110
136
|
end
|
111
137
|
|
112
138
|
class Crossvalidation
|
@@ -168,6 +194,13 @@ module OpenTox
|
|
168
194
|
def statistics( subjectid=nil )
|
169
195
|
Validation.from_cv_statistics( @uri, subjectid )
|
170
196
|
end
|
197
|
+
|
198
|
+
# documentation see OpenTox::Validation.probabilities
|
199
|
+
def probabilities( confidence, prediction, subjectid=nil )
|
200
|
+
YAML.load(OpenTox::RestClientWrapper.get(@uri+"/statistics/probabilities?prediction="+prediction.to_s+"&confidence="+confidence.to_s,
|
201
|
+
{:subjectid => subjectid, :accept => "application/x-yaml"}))
|
202
|
+
end
|
203
|
+
|
171
204
|
end
|
172
205
|
|
173
206
|
class ValidationReport
|
@@ -196,12 +229,18 @@ module OpenTox
|
|
196
229
|
|
197
230
|
# creates a validation report via validation
|
198
231
|
# @param [String] validation uri
|
232
|
+
# @param [Hash] params addiditonal possible
|
233
|
+
# (min_confidence, params={}, min_num_predictions, max_num_predictions)
|
199
234
|
# @param [String,optional] subjectid
|
200
235
|
# @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
|
201
236
|
# @return [OpenTox::ValidationReport]
|
202
|
-
def self.create( validation_uri, subjectid=nil, waiting_task=nil )
|
237
|
+
def self.create( validation_uri, params={}, subjectid=nil, waiting_task=nil )
|
238
|
+
params = {} if params==nil
|
239
|
+
raise OpenTox::BadRequestError.new "params is no hash" unless params.is_a?(Hash)
|
240
|
+
params[:validation_uris] = validation_uri
|
241
|
+
params[:subjectid] = subjectid
|
203
242
|
uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/validation"),
|
204
|
-
|
243
|
+
params, {}, waiting_task )
|
205
244
|
ValidationReport.new(uri)
|
206
245
|
end
|
207
246
|
|
@@ -268,15 +307,17 @@ module OpenTox
|
|
268
307
|
uris.size==0 ? nil : AlgorithmComparisonReport.new(uris[-1])
|
269
308
|
end
|
270
309
|
|
271
|
-
# creates a
|
310
|
+
# creates a algorithm comparison report via crossvalidation uris
|
272
311
|
# @param [Hash] crossvalidation uri_hash, see example
|
312
|
+
# @param [Hash] params addiditonal possible
|
313
|
+
# (ttest_significance, ttest_attributes, min_confidence, min_num_predictions, max_num_predictions)
|
273
314
|
# @param [String,optional] subjectid
|
274
315
|
# @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly
|
275
316
|
# @return [OpenTox::AlgorithmComparisonReport]
|
276
317
|
# example for hash:
|
277
318
|
# { :lazar-bbrc => [ http://host/validation/crossvalidation/x1, http://host/validation/crossvalidation/x2 ],
|
278
319
|
# :lazar-last => [ http://host/validation/crossvalidation/xy, http://host/validation/crossvalidation/xy ] }
|
279
|
-
def self.create( crossvalidation_uri_hash, subjectid=nil, waiting_task=nil )
|
320
|
+
def self.create( crossvalidation_uri_hash, params={}, subjectid=nil, waiting_task=nil )
|
280
321
|
identifier = []
|
281
322
|
validation_uris = []
|
282
323
|
crossvalidation_uri_hash.each do |id, uris|
|
@@ -285,8 +326,13 @@ module OpenTox
|
|
285
326
|
validation_uris << uri
|
286
327
|
end
|
287
328
|
end
|
329
|
+
params = {} if params==nil
|
330
|
+
raise OpenTox::BadRequestError.new "params is no hash" unless params.is_a?(Hash)
|
331
|
+
params[:validation_uris] = validation_uris.join(",")
|
332
|
+
params[:identifier] = identifier.join(",")
|
333
|
+
params[:subjectid] = subjectid
|
288
334
|
uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/algorithm_comparison"),
|
289
|
-
|
335
|
+
params, {}, waiting_task )
|
290
336
|
AlgorithmComparisonReport.new(uri)
|
291
337
|
end
|
292
338
|
end
|