summaryrefslogtreecommitdiff
path: root/application.rb
diff options
context:
space:
mode:
authorgebele <gebele@in-silico.ch>2017-10-31 16:39:38 +0000
committergebele <gebele@in-silico.ch>2017-10-31 16:39:38 +0000
commit9b4484f150978854bcd9fb8723e1df41d806be7a (patch)
tree1357a57d99f1729566119d47c8d571b93911e546 /application.rb
parent8452f160e524aab7f163067ffbf8e3fb42ae1b13 (diff)
serial batch prediction with task
Diffstat (limited to 'application.rb')
-rw-r--r--application.rb472
1 files changed, 276 insertions, 196 deletions
diff --git a/application.rb b/application.rb
index 380b48a..4f73ad6 100644
--- a/application.rb
+++ b/application.rb
@@ -1,6 +1,5 @@
include OpenTox
-
configure :production do
$logger = Logger.new(STDOUT)
enable :reloader
@@ -39,8 +38,151 @@ helpers do
end
doc.to_html.html_safe
end
-end
+ def to_csv(m,predictions,compounds)
+ model = (m != "Cramer" ? Model::Validation.find(m.to_s) : "Cramer")
+ csv = ""
+ if model == "Cramer"
+ compounds = compounds.collect{|c| c.smiles}
+
+ prediction = [Toxtree.predict(compounds, "Cramer rules"), Toxtree.predict(compounds, "Cramer rules with extensions")]
+ output = {}
+ output["model_name"] = "Oral toxicity (Cramer rules)"
+ output["model_type"] = false
+ output["model_unit"] = false
+ ["measurements", "converted_measurements", "prediction_value", "converted_value", "interval", "converted_interval", "probability", "db_hit", "warnings", "info", "toxtree", "sa_prediction", "sa_matches", "confidence"].each do |key|
+ output["#{key}"] = false
+ end
+ output["toxtree"] = true
+ output["cramer_rules"] = prediction.collect{|array| array.collect{|hash| hash["Cramer rules"]}}.flatten.compact
+ output["cramer_rules_extensions"] = prediction.collect{|array| array.collect{|hash| hash["Cramer rules, with extensions"]}}.flatten.compact
+
+ # header
+ csv = "ID,Endpoint,Unique SMILES,Cramer rules,Cramer rules with extensions\n"
+
+ compounds.each_with_index do |smiles, idx|
+ csv << "#{idx+1},#{output["model_name"]},#{smiles},"\
+ "#{output["cramer_rules"][idx] != "nil" ? output["cramer_rules"][idx] : "none" },"\
+ "#{output["cramer_rules_extensions"][idx] != "nil" ? output["cramer_rules_extensions"][idx] : "none"}\n"
+ end
+
+ else
+ output = {}
+ predictions.each_with_index do |prediction,idx|
+ compound = compounds[idx]
+ line = ""
+ output["model_name"] = "#{model.endpoint.gsub('_', ' ')} (#{model.species})"
+ output["model_type"] = model.model.class.to_s.match("Classification") ? type = "Classification" : type = "Regression"
+ output["model_unit"] = (type == "Regression") ? "(#{model.unit})" : ""
+ output["converted_model_unit"] = (type == "Regression") ? "#{model.unit =~ /\b(mmol\/L)\b/ ? "(mg/L)" : "(mg/kg_bw/day)"}" : ""
+ ["measurements", "converted_measurements", "prediction_value", "converted_value", "interval", "converted_interval", "probability", "db_hit", "warnings", "info", "toxtree", "sa_prediction", "sa_matches", "confidence"].each do |key|
+ output["#{key}"] = false
+ end
+
+ if prediction[:value]
+ inApp = (prediction[:warnings].join(" ") =~ /Cannot/ ? "no" : (prediction[:warnings].join(" ") =~ /may|Insufficient/ ? "maybe" : "yes"))
+ if prediction[:info] =~ /\b(identical)\b/i
+ prediction[:info] = "This compound was part of the training dataset. All information "\
+ "from this compound was removed from the training data before the "\
+ "prediction, to obtain unbiased results."
+ end
+ note = "\"#{prediction[:warnings].uniq.join(" ")}\""
+
+ output["prediction_value"] = (type == "Regression") ? "#{prediction[:value].delog10.signif(3)}" : "#{prediction[:value]}"
+ output["converted_value"] = "#{compound.mmol_to_mg(prediction[:value].delog10).signif(3)}" if type == "Regression"
+
+ output["db_hit"] = prediction[:info] if prediction[:info]
+
+ if prediction[:measurements].is_a?(Array)
+ output["measurements"] = (type == "Regression") ? prediction[:measurements].collect{|value| "#{value.delog10.signif(3)} (#{model.unit})"} : prediction[:measurements].collect{|value| "#{value}"}
+ output["converted_measurements"] = (type == "Regression") ? prediction[:measurements].collect{|value| "#{compound.mmol_to_mg(value.delog10).signif(3)} #{model.unit =~ /mmol\/L/ ? "(mg/L)" : "(mg/kg_bw/day)"}"} : false
+ else
+ output["measurements"] = (type == "Regression") ? "#{prediction[:measurements].delog10.signif(3)} (#{model.unit})}" : "#{prediction[:measurements]}"
+ output["converted_measurements"] = (type == "Regression") ? "#{compound.mmol_to_mg(prediction[:measurements].delog10).signif(3)} #{(model.unit =~ /\b(mmol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : false
+
+ end #db_hit
+
+ if type == "Regression"
+
+ if !prediction[:prediction_interval].nil?
+ interval = prediction[:prediction_interval]
+ output['interval'] = "#{interval[1].delog10.signif(3)} - #{interval[0].delog10.signif(3)}"
+ output['converted_interval'] = "#{compound.mmol_to_mg(interval[1].delog10).signif(3)} - #{compound.mmol_to_mg(interval[0].delog10).signif(3)}"
+ end #prediction interval
+
+ line += "#{idx+1},#{output['model_name']},#{compound.smiles},"\
+ "\"#{prediction[:info] ? prediction[:info] : "no"}\",\"#{prediction[:measurements].join("; ") if prediction[:info]}\","\
+ "#{output['prediction_value'] != false ? output['prediction_value'] : ""},"\
+ "#{output['converted_value'] != false ? output['converted_value'] : ""},"\
+ "#{output['interval'].split(" - ").first.strip unless output['interval'] == false},"\
+ "#{output['interval'].split(" - ").last.strip unless output['interval'] == false},"\
+ "#{output['converted_interval'].split(" - ").first.strip unless output['converted_interval'] == false},"\
+ "#{output['converted_interval'].split(" - ").last.strip unless output['converted_interval'] == false},"\
+ "#{inApp},#{note.nil? ? "" : note.chomp}\n"
+ else # Classification
+
+ # consensus mutagenicity
+ sa_prediction = KaziusAlerts.predict(compound.smiles)
+ lazar_mutagenicity = prediction
+ confidence = 0
+ lazar_mutagenicity_val = (lazar_mutagenicity[:value] == "non-mutagenic" ? false : true)
+ if sa_prediction[:prediction] == false && lazar_mutagenicity_val == false
+ confidence = 0.85
+ elsif sa_prediction[:prediction] == true && lazar_mutagenicity_val == true
+ confidence = 0.85 * ( 1 - sa_prediction[:error_product] )
+ elsif sa_prediction[:prediction] == false && lazar_mutagenicity_val == true
+ confidence = 0.11
+ elsif sa_prediction[:prediction] == true && lazar_mutagenicity_val == false
+ confidence = ( 1 - sa_prediction[:error_product] ) - 0.57
+ end
+ output['sa_prediction'] = sa_prediction
+ output['sa_matches'] = sa_prediction[:matches].collect{|a| a.first}.join("; ") unless sa_prediction[:matches].blank?
+ output['confidence'] = confidence.signif(3)
+ output['model_name'] = "Lazar #{model.endpoint.gsub('_', ' ').downcase} (#{model.species}):"
+ output['probability'] = prediction[:probabilities] ? prediction[:probabilities].collect{|k,v| "#{k}: #{v.signif(3)}"} : false
+
+ line += "#{idx+1},Consensus mutagenicity,#{compound.smiles},"\
+ "\"#{prediction[:info] ? prediction[:info] : "no"}\",\"#{prediction[:measurements].join("; ") if prediction[:info]}\","\
+ "#{sa_prediction[:prediction] == false ? "non-mutagenic" : "mutagenic"},"\
+ "#{output['confidence']},#{output['sa_matches'] != false ? "\"#{output['sa_matches']}\"" : "none"},"\
+ "#{output['prediction_value']},"\
+ "#{output['probability'][0] != false ? output['probability'][0].split(":").last : ""},"\
+ "#{output['probability'][1] != false ? output['probability'][1].split(":").last : ""},"\
+ "#{inApp},#{note.nil? ? "" : note}\n"
+
+ end
+
+ output["warnings"] = prediction[:warnings] if prediction[:warnings]
+
+ else #no prediction value
+ inApp = "no"
+ if prediction[:info] =~ /\b(identical)\b/i
+ prediction[:info] = "This compound was part of the training dataset. All information "\
+ "from this compound was removed from the training data before the "\
+ "prediction, to obtain unbiased results."
+ end
+ note = "\"#{prediction[:warnings].join(" ")}\""
+
+ output["warnings"] = prediction[:warnings]
+ output["info"] = prediction[:info] if prediction[:info]
+
+ if type == "Regression"
+ line += "#{idx+1},#{output['model_name']},#{compound.smiles},#{prediction[:info] ? prediction[:info] : "no"},"\
+ "#{prediction[:measurements] if prediction[:info]},,,,,,,"+ [inApp,note].join(",")+"\n"
+ else
+ line += "#{idx+1},Consensus mutagenicity,#{compound.smiles},#{prediction[:info] ? prediction[:info] : "no"},"\
+ "#{prediction[:measurements] if prediction[:info]},,,,,,,"+ [inApp,note].join(",")+"\n"
+ end
+
+ end
+ csv += line
+ end
+ csv
+ end
+ end
+
+end
+
get '/?' do
redirect to('/predict')
end
@@ -53,6 +195,42 @@ get '/predict/?' do
@models.count <= 0 ? (haml :info) : (haml :predict)
end
+get '/task/?' do
+ if params[:turi]
+ task = Task.find(params[:turi].to_s)
+ return JSON.pretty_generate(:percent => task.percent)
+ elsif params[:predictions]
+ pageSize = params[:pageSize].to_i - 1
+ pageNumber= params[:pageNumber].to_i - 1
+ compound = Compound.find @@compounds_ids[pageNumber]
+ image = compound.svg
+ smiles = compound.smiles
+ task = Task.find(params[:predictions].to_s)
+ unless task.predictions[params[:model]].nil?
+ array = []
+ html = "<table class=\"table table-bordered single-batch\"><tr>"
+ html += "<td>#{image}</br>#{smiles}</br></td>"
+ string = "<td><table class=\"table\">"
+ prediction = task.predictions[params[:model]][pageNumber.to_i]
+ sort = []
+ if prediction[:info]
+ sort << {"info" => prediction[:info]}
+ sort << {"measurements" => prediction[:measurements].join("</br>")}
+ prediction.delete("info")
+ prediction.delete("measurements")
+ end
+ task.predictions[params[:model]][pageNumber.to_i].each do |k,v|
+ string += "<tr><td>#{(k=="value" ? "prediction" : k).capitalize}:</td> "\
+ "<td>#{v.blank? ? "none" : (v.kind_of?(Array) ? v.join("\</br>") : v)}</td></tr>"
+ end
+ string += "</table></td>"
+ html += "#{string}</tr></table>"
+ array << [html]
+ end
+ return JSON.pretty_generate(:predictions => array)
+ end
+end
+
get '/predict/modeldetails/:model' do
model = Model::Validation.find params[:model]
crossvalidations = Validation::RepeatedCrossValidation.find(model.repeated_crossvalidation_id).crossvalidations
@@ -71,175 +249,13 @@ get '/predict/dataset/:name' do
csv
end
-get '/predict/:tmppath/:model/:filename?' do
+get '/predict/csv/:task/:model/:filename/?' do
response['Content-Type'] = "text/csv"
- path = File.join("tmp", params[:tmppath])
- `sort -gk1 #{path} -o #{path}`
-
- send_file path, :filename => "#{Time.now.strftime("%Y-%m-%d")}_lazar_batch_prediction_#{params[:model]}_#{params[:filename]}", :type => "text/csv", :disposition => "attachment"
-end
-
-get '/batch/:model/' do
-
- if params[:model] == "Cramer"
- dataset = Dataset.find params[:dataset]
- compounds = dataset.compounds.collect{|c| c.smiles}
-
- prediction = [Toxtree.predict(compounds, "Cramer rules"), Toxtree.predict(compounds, "Cramer rules with extensions")]
- output = {}
- output["model_name"] = "Oral toxicity (Cramer rules)"
- output["model_type"] = false
- output["model_unit"] = false
- ["measurements", "converted_measurements", "prediction_value", "converted_value", "interval", "converted_interval", "probability", "db_hit", "warnings", "info", "toxtree", "sa_prediction", "sa_matches", "confidence"].each do |key|
- output["#{key}"] = false
- end
- output["toxtree"] = true
- output["cramer_rules"] = prediction.collect{|array| array.collect{|hash| hash["Cramer rules"]}}.flatten.compact
- output["cramer_rules_extensions"] = prediction.collect{|array| array.collect{|hash| hash["Cramer rules, with extensions"]}}.flatten.compact
-
- # td paths to insert results in GUI
- compound_ids = dataset.compounds.collect{|c| c.id}
- output["tds"] = compound_ids.each_with_index.map{|cid,idx| "prediction_#{cid}_Cramer_#{idx}"}
-
- # write to file
- # header
- csv = "ID,Endpoint,Unique SMILES,Cramer rules,Cramer rules with extensions\n"
-
- compounds.each_with_index do |smiles, idx|
- csv << "#{idx+1},#{output["model_name"]},#{smiles},"\
- "#{output["cramer_rules"][idx] != "nil" ? output["cramer_rules"][idx] : "none" },"\
- "#{output["cramer_rules_extensions"][idx] != "nil" ? output["cramer_rules_extensions"][idx] : "none"}\n"
- end
- File.open(File.join("tmp", params[:tmppath]),"a+"){|file| file.write(csv)}
-
- # cleanup
- dataset.delete
-
- # return output
- response['Content-Type'] = "application/json"
- return JSON.pretty_generate output
-
- else
- idx = params[:idx].to_i
- compound = Compound.find params[:compound]
-
- model = Model::Validation.find params[:model]
- prediction = model.predict(compound)
- output = {}
- output["model_name"] = "#{model.endpoint.gsub('_', ' ')} (#{model.species})"
- output["model_type"] = model.model.class.to_s.match("Classification") ? type = "Classification" : type = "Regression"
- output["model_unit"] = (type == "Regression") ? "(#{model.unit})" : ""
- output["converted_model_unit"] = (type == "Regression") ? "#{model.unit =~ /\b(mmol\/L)\b/ ? "(mg/L)" : "(mg/kg_bw/day)"}" : ""
- ["measurements", "converted_measurements", "prediction_value", "converted_value", "interval", "converted_interval", "probability", "db_hit", "warnings", "info", "toxtree", "sa_prediction", "sa_matches", "confidence"].each do |key|
- output["#{key}"] = false
- end
-
- if prediction[:value]
- inApp = (prediction[:warnings].join(" ") =~ /Cannot/ ? "no" : (prediction[:warnings].join(" ") =~ /may|Insufficient/ ? "maybe" : "yes"))
- if prediction[:info] =~ /\b(identical)\b/i
- prediction[:info] = "This compound was part of the training dataset. All information "\
- "from this compound was removed from the training data before the "\
- "prediction, to obtain unbiased results."
- end
- note = "\"#{prediction[:warnings].uniq.join(" ")}\""
-
- output["prediction_value"] = (type == "Regression") ? "#{prediction[:value].delog10.signif(3)}" : "#{prediction[:value]}"
- output["converted_value"] = "#{compound.mmol_to_mg(prediction[:value].delog10).signif(3)}" if type == "Regression"
-
- output["db_hit"] = prediction[:info] if prediction[:info]
-
- if prediction[:measurements].is_a?(Array)
- output["measurements"] = (type == "Regression") ? prediction[:measurements].collect{|value| "#{value.delog10.signif(3)} (#{model.unit})"} : prediction[:measurements].collect{|value| "#{value}"}
- output["converted_measurements"] = (type == "Regression") ? prediction[:measurements].collect{|value| "#{compound.mmol_to_mg(value.delog10).signif(3)} #{model.unit =~ /mmol\/L/ ? "(mg/L)" : "(mg/kg_bw/day)"}"} : false
- else
- output["measurements"] = (type == "Regression") ? "#{prediction[:measurements].delog10.signif(3)} (#{model.unit})}" : "#{prediction[:measurements]}"
- output["converted_measurements"] = (type == "Regression") ? "#{compound.mmol_to_mg(prediction[:measurements].delog10).signif(3)} #{(model.unit =~ /\b(mmol\/L)\b/) ? "(mg/L)" : "(mg/kg_bw/day)"}" : false
-
- end #db_hit
-
- if type == "Regression"
-
- if !prediction[:prediction_interval].nil?
- interval = prediction[:prediction_interval]
- output['interval'] = "#{interval[1].delog10.signif(3)} - #{interval[0].delog10.signif(3)}"
- output['converted_interval'] = "#{compound.mmol_to_mg(interval[1].delog10).signif(3)} - #{compound.mmol_to_mg(interval[0].delog10).signif(3)}"
- end #prediction interval
-
- csv = "#{idx+1},#{output['model_name']},#{compound.smiles},"\
- "\"#{prediction[:info] ? prediction[:info] : "no"}\",\"#{prediction[:measurements].join("; ") if prediction[:info]}\","\
- "#{output['prediction_value'] != false ? output['prediction_value'] : ""},"\
- "#{output['converted_value'] != false ? output['converted_value'] : ""},"\
- "#{output['interval'].split(" - ").first.strip unless output['interval'] == false},"\
- "#{output['interval'].split(" - ").last.strip unless output['interval'] == false},"\
- "#{output['converted_interval'].split(" - ").first.strip unless output['converted_interval'] == false},"\
- "#{output['converted_interval'].split(" - ").last.strip unless output['converted_interval'] == false},"\
- "#{inApp},#{note.nil? ? "" : note.chomp}\n"
- else # Classification
-
- # consensus mutagenicity
-
- sa_prediction = KaziusAlerts.predict(compound.smiles)
- lazar_mutagenicity = prediction
- confidence = 0
- lazar_mutagenicity_val = (lazar_mutagenicity[:value] == "non-mutagenic" ? false : true)
- if sa_prediction[:prediction] == false && lazar_mutagenicity_val == false
- confidence = 0.85
- elsif sa_prediction[:prediction] == true && lazar_mutagenicity_val == true
- confidence = 0.85 * ( 1 - sa_prediction[:error_product] )
- elsif sa_prediction[:prediction] == false && lazar_mutagenicity_val == true
- confidence = 0.11
- elsif sa_prediction[:prediction] == true && lazar_mutagenicity_val == false
- confidence = ( 1 - sa_prediction[:error_product] ) - 0.57
- end
- output['sa_prediction'] = sa_prediction
- output['sa_matches'] = sa_prediction[:matches].collect{|a| a.first}.join("; ") unless sa_prediction[:matches].blank?
- output['confidence'] = confidence.signif(3)
- output['model_name'] = "Lazar #{model.endpoint.gsub('_', ' ').downcase} (#{model.species}):"
- output['probability'] = prediction[:probabilities] ? prediction[:probabilities].collect{|k,v| "#{k}: #{v.signif(3)}"} : false
-
- csv = "#{idx+1},Consensus mutagenicity,#{compound.smiles},"\
- "\"#{prediction[:info] ? prediction[:info] : "no"}\",\"#{prediction[:measurements].join("; ") if prediction[:info]}\","\
- "#{sa_prediction[:prediction] == false ? "non-mutagenic" : "mutagenic"},"\
- "#{output['confidence']},#{output['sa_matches'] != false ? "\"#{output['sa_matches']}\"" : "none"},"\
- "#{output['prediction_value']},"\
- "#{output['probability'][0] != false ? output['probability'][0].split(":").last : ""},"\
- "#{output['probability'][1] != false ? output['probability'][1].split(":").last : ""},"\
- "#{inApp},#{note.nil? ? "" : note}\n"
-
- end
-
- output["warnings"] = prediction[:warnings] if prediction[:warnings]
-
- else #no prediction value
- inApp = "no"
- if prediction[:info] =~ /\b(identical)\b/i
- prediction[:info] = "This compound was part of the training dataset. All information "\
- "from this compound was removed from the training data before the "\
- "prediction, to obtain unbiased results."
- end
- note = "\"#{prediction[:warnings].join(" ")}\""
-
- output["warnings"] = prediction[:warnings]
- output["info"] = prediction[:info] if prediction[:info]
-
- if type == "Regression"
- csv = "#{idx+1},#{output['model_name']},#{compound.smiles},#{prediction[:info] ? prediction[:info] : "no"},"\
- "#{prediction[:measurements] if prediction[:info]},,,,,,,"+ [inApp,note].join(",")+"\n"
- else
- csv = "#{idx+1},Consensus mutagenicity,#{compound.smiles},#{prediction[:info] ? prediction[:info] : "no"},"\
- "#{prediction[:measurements] if prediction[:info]},,,,,,,"+ [inApp,note].join(",")+"\n"
- end
-
- end #prediction value
-
- # write to file
- File.open(File.join("tmp", params[:tmppath]),"a"){|file| file.write(csv)}
-
- # return output
- response['Content-Type'] = "application/json"
- return JSON.pretty_generate output
-
- end# if Cramer
+ task = Task.find params[:task].to_s
+ tempfile = Tempfile.new
+ tempfile.write(task.csv)
+ tempfile.rewind
+ send_file tempfile, :filename => "#{Time.now.strftime("%Y-%m-%d")}_lazar_batch_prediction_#{params[:model]}_#{params[:filename]}", :type => "text/csv", :disposition => "attachment"
end
post '/predict/?' do
@@ -273,33 +289,98 @@ post '/predict/?' do
end
@models = params[:selection].keys
- @tmppaths = {}
- @models.each do |model|
- m = Model::Validation.find model
- type = (m.regression? ? "Regression" : "Classification") unless model == "Cramer"
- # add header for regression
- if type == "Regression"
- unit = (type == "Regression") ? "(#{m.unit})" : ""
- converted_unit = (type == "Regression") ? "#{m.unit =~ /\b(mmol\/L)\b/ ? "(mg/L)" : "(mg/kg_bw/day)"}" : ""
- header = "ID,Endpoint,Unique SMILES,inTrainingSet,Measurements,Prediction #{unit},Prediction #{converted_unit},"\
- "Prediction Interval Low #{unit},Prediction Interval High #{unit},"\
- "Prediction Interval Low #{converted_unit},Prediction Interval High #{converted_unit},"\
- "inApplicabilityDomain,Note\n"
- end
- # add header for classification
- if type == "Classification"
- av = m.prediction_feature.accept_values
- header = "ID,Endpoint,Unique SMILES,inTrainingSet,Measurements,Consensus Prediction,Consensus Confidence,"\
- "Structural alerts for mutagenicity,Lazar Prediction,"\
- "Lazar predProbability #{av[0]},Lazar predProbability #{av[1]},inApplicabilityDomain,Note\n"
- end
- path = File.join("tmp", "#{Time.now.strftime("%Y-%m-%d")}_#{SecureRandom.urlsafe_base64(5)}")
- File.open(path, "w"){|f| f.write(header) if header}
- @tmppaths[model] = path.split("/").last
- end
+ # for single predictions in batch
+ @@compounds_ids = @compounds.collect{|c| c.id.to_s}
+ @tasks = []
+ @models.each{|m| t = Task.new; t.save; @tasks << t}
+ @predictions = {}
+ task = Task.run do
+ @models.each_with_index do |model,idx|
+ t = @tasks[idx]
+ unless model == "Cramer"
+ m = Model::Validation.find model
+ type = (m.regression? ? "Regression" : "Classification")
+ # add header for regression
+ if type == "Regression"
+ unit = (type == "Regression") ? "(#{m.unit})" : ""
+ converted_unit = (type == "Regression") ? "#{m.unit =~ /\b(mmol\/L)\b/ ? "(mg/L)" : "(mg/kg_bw/day)"}" : ""
+ header = "ID,Endpoint,Unique SMILES,inTrainingSet,Measurements,Prediction #{unit},Prediction #{converted_unit},"\
+ "Prediction Interval Low #{unit},Prediction Interval High #{unit},"\
+ "Prediction Interval Low #{converted_unit},Prediction Interval High #{converted_unit},"\
+ "inApplicabilityDomain,Note\n"
+ end
+ # add header for classification
+ if type == "Classification"
+ av = m.prediction_feature.accept_values
+ header = "ID,Endpoint,Unique SMILES,inTrainingSet,Measurements,Consensus Prediction,Consensus Confidence,"\
+ "Structural alerts for mutagenicity,Lazar Prediction,"\
+ "Lazar predProbability #{av[0]},Lazar predProbability #{av[1]},inApplicabilityDomain,Note\n"
+ end
+ # predict compounds
+ p = 100.0/@compounds.size
+ counter = 1
+ predictions = []
+ @compounds.each do |compound|
+ prediction = m.predict(compound)
+ if type == "Classification"# consensus mutagenicity
+ sa_prediction = KaziusAlerts.predict(compound.smiles)
+ lazar_mutagenicity = prediction
+ confidence = 0
+ lazar_mutagenicity_val = (lazar_mutagenicity[:value] == "non-mutagenic" ? false : true)
+ if sa_prediction[:prediction] == false && lazar_mutagenicity_val == false
+ confidence = 0.85
+ elsif sa_prediction[:prediction] == true && lazar_mutagenicity_val == true
+ confidence = 0.85 * ( 1 - sa_prediction[:error_product] )
+ elsif sa_prediction[:prediction] == false && lazar_mutagenicity_val == true
+ confidence = 0.11
+ elsif sa_prediction[:prediction] == true && lazar_mutagenicity_val == false
+ confidence = ( 1 - sa_prediction[:error_product] ) - 0.57
+ end
+ prediction["Consensus prediction"] = sa_prediction[:prediction] == false ? "non-mutagenic" : "mutagenic"
+ prediction["Consensus confidence"] = confidence.signif(3)
+ prediction["Structural alerts for mutagenicity"] = sa_prediction[:matches] ? sa_prediction[:matches].collect{|a| a.first}.join("; ") : "none"
+ end
+ predictions << prediction.delete_if{|k,v| k =~ /neighbors|prediction_feature_id/i}
+ t.update_percent((counter*p).ceil)
+ counter += 1
+ end
+ # write csv
+ t[:csv] = header + to_csv(model,predictions,@compounds)
+ # write predictions
+ @predictions["#{model}"] = predictions
+ else # Cramer model
+ #t[:csv] = to_csv(model,nil,@compounds)
+ compounds = @compounds.collect{|c| c.smiles}
+ prediction = [Toxtree.predict(compounds, "Cramer rules"), Toxtree.predict(compounds, "Cramer rules with extensions")]
+ output = {}
+ output["model_name"] = "Oral toxicity (Cramer rules)"
+ output["cramer_rules"] = prediction.collect{|array| array.collect{|hash| hash["Cramer rules"]}}.flatten.compact
+ output["cramer_rules_extensions"] = prediction.collect{|array| array.collect{|hash| hash["Cramer rules, with extensions"]}}.flatten.compact
+ # header
+ csv = "ID,Endpoint,Unique SMILES,Cramer rules,Cramer rules with extensions\n"
+ # content
+ compounds.each_with_index do |smiles, idx|
+ csv << "#{idx+1},#{output["model_name"]},#{smiles},"\
+ "#{output["cramer_rules"][idx] != "nil" ? output["cramer_rules"][idx] : "none" },"\
+ "#{output["cramer_rules_extensions"][idx] != "nil" ? output["cramer_rules_extensions"][idx] : "none"}\n"
+ end
+ # write csv
+ t[:csv] = csv
+ # write predictions
+ @predictions["#{model}"] = predictions
+ t.update_percent(100)
+ end
+ # save task
+ # append predictions as last action otherwise they won't save
+ # mongoid works with shallow copy via #dup
+ t[:predictions] = @predictions
+ t.save
+ end#models
+
+ end#main task
File.delete File.join("tmp", params[:fileselect][:filename])
- return haml :batch
+ return haml :task
end
# single compound prediction
@@ -350,4 +431,3 @@ get '/style.css' do
headers 'Content-Type' => 'text/css; charset=utf-8'
scss :style
end
-