Class: Diverge

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

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(p, q) ⇒ Diverge

Returns a new instance of Diverge.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/diverge.rb', line 22

def initialize(p, q)
  @p, @q = p, q

  unless p.length == q.length
    debugger { "The two discrete distributions must have the same number of elements" }
  end

  unless (p_sum = p.inject(&:+)) == 1
    debugger { "Warning: the first argument does not sum to 1, the sum is #{p_sum.inspect}" }
  end

  unless (q_sum = q.inject(&:+)) == 1
    debugger { "Warning: the second argument does not sum to 1, the sum is #{q_sum.inspect}" }
  end
end

Class Attribute Details

.debugObject

Returns the value of attribute debug.



3
4
5
# File 'lib/diverge.rb', line 3

def debug
  @debug
end

.method_namesObject

Returns the value of attribute method_names.



3
4
5
# File 'lib/diverge.rb', line 3

def method_names
  @method_names
end

Instance Attribute Details

#pObject (readonly)

Returns the value of attribute p.



20
21
22
# File 'lib/diverge.rb', line 20

def p
  @p
end

#qObject (readonly)

Returns the value of attribute q.



20
21
22
# File 'lib/diverge.rb', line 20

def q
  @q
end

Class Method Details

.method_added(name) ⇒ Object



5
6
7
# File 'lib/diverge.rb', line 5

def method_added(name)
  (@method_names ||= []) << name
end

.method_missing(name, *args, &block) ⇒ Object



9
10
11
12
13
14
15
# File 'lib/diverge.rb', line 9

def method_missing(name, *args, &block)
  if (Diverge.public_instance_methods & Diverge.method_names).include?(name)
    new(*args[0..1]).send(name, *args[2..-1])
  else
    super
  end
end

Instance Method Details

#correlationObject Also known as: corr



72
73
74
75
76
77
78
# File 'lib/diverge.rb', line 72

def correlation
  square = ->(x) { x ** 2 }
  top    = size * p.zip(q).map { |x, y| x * y }.inject(&:+) - p.inject(&:+) * q.inject(&:+)
  bottom = Math.sqrt((size * p.map(&square).inject(&:+) - p.inject(&:+) ** 2) * (size * q.map(&square).inject(&:+) - q.inject(&:+) ** 2))

  bottom.zero? ? 0 : top / bottom
end

#debugObject



102
103
104
# File 'lib/diverge.rb', line 102

def debug
  self.class.debug
end

#debug=(value) ⇒ Object



106
107
108
# File 'lib/diverge.rb', line 106

def debug=(value)
  self.class.debug = value
end

#j_divergenceObject Also known as: j



60
61
62
# File 'lib/diverge.rb', line 60

def j_divergence
  0.5 * (kl + kl(:reverse))
end

#jensen_shannonObject Also known as: js



50
51
52
53
54
55
56
# File 'lib/diverge.rb', line 50

def jensen_shannon
  m = p.zip(q).map { |p_i, q_i| 0.5 * (p_i + q_i) }

  silently do
    0.5 * (Diverge.new(p, m).kl + Diverge.new(q, m).kl)
  end
end

#kullback_leibler(reverse = false) ⇒ Object Also known as: kl



38
39
40
41
42
43
44
45
46
# File 'lib/diverge.rb', line 38

def kullback_leibler(reverse = false)
  (reverse ? q.zip(p) : p.zip(q)).inject(0.0) do |sum, (i, j)|
    if i > 0 && j.zero?
      raise ArgumentError.new("Kullback-Leibler is not defined when P(i) > 0 and Q(i) = 0")
    end

    sum + (i.zero? ? 0 : i * Math.log(i / j))
  end
end

#mean_square_errorObject Also known as: mse



90
91
92
# File 'lib/diverge.rb', line 90

def mean_square_error
  p.zip(q).inject(0.0) { |sum, (i, j)| sum + (i - j) ** 2 } / size
end

#root_mean_square_deviationObject Also known as: rmsd



96
97
98
# File 'lib/diverge.rb', line 96

def root_mean_square_deviation
  Math.sqrt(p.zip(q).inject(0.0) { |sum, (i, j)| sum + (i - j) ** 2 } / size)
end

#silently(&block) ⇒ Object



110
111
112
113
114
# File 'lib/diverge.rb', line 110

def silently(&block)
  debug_value = debug
  self.debug  = false
  (yield block).tap { self.debug = debug_value }
end

#spearman_correlationObject Also known as: s_corr



82
83
84
85
86
# File 'lib/diverge.rb', line 82

def spearman_correlation
  sum_d_squared = list_ranks(p).zip(list_ranks(q)).inject(0.0) { |sum, (p_data, q_data)| sum + (p_data.rank_order - q_data.rank_order) ** 2 }

  1 - ((6 * sum_d_squared) / (size * (size ** 2 - 1)))
end

#total_variation_distanceObject Also known as: tvd



66
67
68
# File 'lib/diverge.rb', line 66

def total_variation_distance
  0.5 * p.zip(q).inject(0.0) { |sum, (i, j)| sum + (i - j).abs }
end