Class: Eps::Evaluators::NaiveBayes
- Inherits:
-
Object
- Object
- Eps::Evaluators::NaiveBayes
- Defined in:
- lib/eps/evaluators/naive_bayes.rb
Constant Summary collapse
- SQRT_2PI =
Math.sqrt(2 * Math::PI)
Instance Attribute Summary collapse
-
#features ⇒ Object
readonly
Returns the value of attribute features.
-
#probabilities ⇒ Object
readonly
Returns the value of attribute probabilities.
Instance Method Summary collapse
-
#calculate_class_probabilities(x) ⇒ Object
use log to prevent underflow www.antoniomallia.it/lets-implement-a-gaussian-naive-bayes-classifier-in-python.html.
-
#calculate_probability(x, mean, stdev) ⇒ Object
TODO memoize for performance.
-
#initialize(probabilities:, features:, derived: nil, legacy: false) ⇒ NaiveBayes
constructor
A new instance of NaiveBayes.
- #predict(x, probabilities: false) ⇒ Object
Constructor Details
#initialize(probabilities:, features:, derived: nil, legacy: false) ⇒ NaiveBayes
Returns a new instance of NaiveBayes.
6 7 8 9 10 11 |
# File 'lib/eps/evaluators/naive_bayes.rb', line 6 def initialize(probabilities:, features:, derived: nil, legacy: false) @probabilities = probabilities @features = features @derived = derived @legacy = legacy end |
Instance Attribute Details
#features ⇒ Object (readonly)
Returns the value of attribute features.
4 5 6 |
# File 'lib/eps/evaluators/naive_bayes.rb', line 4 def features @features end |
#probabilities ⇒ Object (readonly)
Returns the value of attribute probabilities.
4 5 6 |
# File 'lib/eps/evaluators/naive_bayes.rb', line 4 def probabilities @probabilities end |
Instance Method Details
#calculate_class_probabilities(x) ⇒ Object
use log to prevent underflow www.antoniomallia.it/lets-implement-a-gaussian-naive-bayes-classifier-in-python.html
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 |
# File 'lib/eps/evaluators/naive_bayes.rb', line 27 def calculate_class_probabilities(x) probs = Eps::DataFrame.new # assign very small probability if probability is 0 tiny_p = @legacy ? 0.0001 : 0 total = probabilities[:prior].values.sum.to_f probabilities[:prior].each do |c, cv| prior = Math.log(cv / total) px = [prior] * x.size @features.each do |k, type| case type when "categorical" x.columns[k].each_with_index do |xi, i| # TODO clean this up vc = probabilities[:conditional][k][xi] || probabilities[:conditional][k][xi.to_s] # unknown value if not vc if vc denom = probabilities[:conditional][k].map { |k, v| v[c] }.sum.to_f p2 = vc[c].to_f / denom # TODO use proper smoothing instead p2 = tiny_p if p2 == 0 px[i] += Math.log(p2) end end when "derived" @derived[k].each do |k2, v2| vc = probabilities[:conditional][k2][c] x.columns[k].each_with_index do |xi, i| px[i] += Math.log(calculate_probability(xi == v2 ? 1 : 0, vc[:mean], vc[:stdev])) end end else vc = probabilities[:conditional][k][c] if vc[:stdev] != 0 && !vc[:stdev].nil? x.columns[k].each_with_index do |xi, i| px[i] += Math.log(calculate_probability(xi, vc[:mean], vc[:stdev])) end else x.columns[k].each_with_index do |xi, i| if xi != vc[:mean] # TODO use proper smoothing instead px[i] += Math.log(tiny_p) end end end end probs.columns[c] = px end end probs end |
#calculate_probability(x, mean, stdev) ⇒ Object
TODO memoize for performance
91 92 93 94 |
# File 'lib/eps/evaluators/naive_bayes.rb', line 91 def calculate_probability(x, mean, stdev) exponent = Math.exp(-((x - mean)**2) / (2 * (stdev**2))) (1 / (SQRT_2PI * stdev)) * exponent end |
#predict(x, probabilities: false) ⇒ Object
13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/eps/evaluators/naive_bayes.rb', line 13 def predict(x, probabilities: false) probs = calculate_class_probabilities(x) probs.map do |xp| if probabilities sum = xp.values.map { |v| Math.exp(v) }.sum.to_f xp.map { |k, v| [k, Math.exp(v) / sum] }.to_h else xp.sort_by { |k, v| [-v, k] }[0][0] end end end |