Class: TrailGuide::Calculators::Bayesian

Inherits:
Calculator
  • Object
show all
Defined in:
lib/trail_guide/calculators/bayesian.rb

Instance Attribute Summary collapse

Attributes inherited from Calculator

#choice, #experiment, #goal, #probability

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Calculator

#base, #best, #variants, #variants_with_conversion, #worst

Constructor Details

#initialize(*args, beta: nil, **opts) ⇒ Bayesian

Returns a new instance of Bayesian.



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
# File 'lib/trail_guide/calculators/bayesian.rb', line 10

def initialize(*args, beta: nil, **opts)
  raise NoIntegrationLibrary if !defined?(::Integration)

  if beta.nil?
    # prefer rubystats if not specified
    if defined?(::Rubystats)
      beta = :rubystats
    elsif defined?(::Distribution)
      beta = :distribution
    else
      raise NoBetaDistributionLibrary
    end
  end

  case beta.to_sym
  when :distribution
    raise NoBetaDistributionLibrary, beta unless defined?(::Distribution)
    TrailGuide.logger.debug "Using Distribution::Beta to calculate beta distributions"
    TrailGuide.logger.debug "GSL detected, Distribution::Beta will use GSL for better performance" if defined?(::GSL)
  when :rubystats
    raise NoBetaDistributionLibrary, beta unless defined?(::Rubystats)
    TrailGuide.logger.debug "Using Rubystats::BetaDistribution to calculate beta distributions"
  else
    raise UnknownBetaDistributionLibrary, beta
  end

  super(*args, **opts)
  @beta = beta.to_sym
end

Instance Attribute Details

#betaObject (readonly)

Returns the value of attribute beta.



8
9
10
# File 'lib/trail_guide/calculators/bayesian.rb', line 8

def beta
  @beta
end

Class Method Details

.enabled?Boolean

Returns:

  • (Boolean)


4
5
6
# File 'lib/trail_guide/calculators/bayesian.rb', line 4

def self.enabled?
  !!(defined?(::Integration) && (defined?(::Rubystats) || defined?(::Distribution)))
end

Instance Method Details

#calculate!Object



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
# File 'lib/trail_guide/calculators/bayesian.rb', line 71

def calculate!
  variants_with_conversion.each do |variant|
    expvar = experiment.variants.find { |var| var.name == variant.name }
    vprob = variant_probability(variant)
    variant.probability = vprob
    variant.significance = TrailGuide::Calculators::SIGNIFICANT_PROBABILITIES.reverse.find { |pct| vprob >= pct } || 0

    #if worst && variant.measure > worst.measure
    #  variant.difference = (variant.measure - worst.measure) / worst.measure * 100
    #end
    if base
      if variant.measure > base.measure
        variant.difference = (variant.measure - base.measure) / base.measure * 100
      elsif base.measure > variant.measure
        variant.difference = -((base.measure - variant.measure) / base.measure * 100)
      else
        variant.difference = 0
      end
    end
  end

  @choice = best && best.probability >= probability ? best : nil

  self
end

#cdf(variant, z) ⇒ Object



50
51
52
53
54
55
56
57
58
# File 'lib/trail_guide/calculators/bayesian.rb', line 50

def cdf(variant, z)
  x = variant.subset
  n = variant.superset
  if beta == :distribution
    Distribution::Beta.cdf(z, x+1, n-x+1)
  else
    Rubystats::BetaDistribution.new(x+1, n-x+1).cdf(z)
  end
end

#pdf(variant, z) ⇒ Object



40
41
42
43
44
45
46
47
48
# File 'lib/trail_guide/calculators/bayesian.rb', line 40

def pdf(variant, z)
  x = variant.subset
  n = variant.superset
  if beta == :distribution
    Distribution::Beta.pdf(z, x+1, n-x+1)
  else
    Rubystats::BetaDistribution.new(x+1, n-x+1).pdf(z)
  end
end

#variant_probability(variant) ⇒ Object



60
61
62
63
64
65
66
67
68
69
# File 'lib/trail_guide/calculators/bayesian.rb', line 60

def variant_probability(variant)
  Integration.integrate(0, 1, tolerance: 1e-4) do |z|
    vpdf = pdf(variant, z)
    variants.each do |var|
      next if var == variant
      vpdf = vpdf * cdf(var, z)
    end
    vpdf
  end * 100.0
end