Class: EMAlgorithm::Mixture

Inherits:
Model
  • Object
show all
Defined in:
lib/em_algorithm/models/mixture.rb

Constant Summary

Constants inherited from Model

EMAlgorithm::Model::DIGIT

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Model

#pdf, #value_distribution, #value_distribution_to_gnuplot

Constructor Details

#initialize(options) ⇒ Mixture

Returns a new instance of Mixture.



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/em_algorithm/models/mixture.rb', line 5

def initialize(options)
  opts = {
    :models =>
    [
      Gaussian.new(0.0, 9.0), Gaussian.new(10.0, 9.0)
    ],
    :weights =>
    [
      0.5, 0.5
    ]
  }.merge(options)
  @models = opts[:models]
  @weights = opts[:weights]
  if !proper_weights?
    argument_error
  end
  @temp_weights = Array.new(@models.size)
  @temp_weight_per_datum = Array.new(@models.size).map { Array.new }
end

Instance Attribute Details

#modelsObject

Returns the value of attribute models.



3
4
5
# File 'lib/em_algorithm/models/mixture.rb', line 3

def models
  @models
end

#weightsObject

Returns the value of attribute weights.



3
4
5
# File 'lib/em_algorithm/models/mixture.rb', line 3

def weights
  @weights
end

Instance Method Details

#add(model = Gaussian.new(0.0, 9.0), weight = 0.0) ⇒ Object



29
30
31
32
33
34
35
# File 'lib/em_algorithm/models/mixture.rb', line 29

def add(model = Gaussian.new(0.0, 9.0), weight = 0.0)
  @models << model
  @weights << weight
  if !proper_weights?
    argument_error
  end
end

#argument_errorObject

Raises:

  • (ArgumentError)


25
26
27
# File 'lib/em_algorithm/models/mixture.rb', line 25

def argument_error
  raise ArgumentError, "The summation of @weights must be equal to 1.0."
end

#calculate_posterior_data_array(data_array) ⇒ Object



53
54
55
56
57
58
59
60
61
# File 'lib/em_algorithm/models/mixture.rb', line 53

def calculate_posterior_data_array(data_array)
  posterior_data_array = Array.new(data_array.size, 0.0)
  @models.each_with_index do |model, mi|
    data_array.each_with_index do |x, di|
      posterior_data_array[di] += @weights[mi] * model.pdf(x)
    end
  end
  posterior_data_array
end

#clear_temp_weight_per_datum!Object



49
50
51
# File 'lib/em_algorithm/models/mixture.rb', line 49

def clear_temp_weight_per_datum!
  @temp_weight_per_datum.each {|w| w.clear}
end

#debug_outputObject



113
114
115
116
117
118
119
120
# File 'lib/em_algorithm/models/mixture.rb', line 113

def debug_output
  <<-DEBUG_OUT
  @weights=#{@weights.inspect}
  @temp_weights=#{@temp_weights.inspect}
  @models
   #{@models.inspect}
  DEBUG_OUT
end

#probability_density_function(x) ⇒ Object



41
42
43
44
45
46
47
# File 'lib/em_algorithm/models/mixture.rb', line 41

def probability_density_function(x)
  pdf = 0.0
  @models.each_with_index do |model, mi|
    pdf += model.pdf(x) * @weights[mi]
  end
  pdf
end

#proper_weights?Boolean

Returns:

  • (Boolean)


37
38
39
# File 'lib/em_algorithm/models/mixture.rb', line 37

def proper_weights?
  @weights.inject(0) {|sum, v| sum + v} == 1.0
end

#to_gnuplot(type = :full) ⇒ Object

output types :full (default) :separate_only :mixture_only



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/em_algorithm/models/mixture.rb', line 91

def to_gnuplot(type = :full)
  # output each model (currently assume Gaussian)
  output = []
  @models.each_with_index do |model, mi|
    output << "#{@weights[mi].round(DIGIT)} * #{model.to_gnuplot_with_title(@weights[mi])}"
  end
  separate = output.join(", ")
  # output mixture model (currently assume Gaussian Mixture model)
  output = []
  @models.each_with_index do |model, mi|
    output << "#{@weights[mi].round(DIGIT)} * #{model.to_gnuplot}"
  end
  mixture = output.join(" + ")
  case type
  when :separate_only
    return separate
  when :mixture_only
    return mixture
  end
  "#{separate}, #{mixture}"
end

#update_parameters!(data_array) ⇒ Object



80
81
82
83
84
85
# File 'lib/em_algorithm/models/mixture.rb', line 80

def update_parameters!(data_array)
  @models.each_with_index do |model, mi|
    model.update_parameters!(data_array, @temp_weights[mi], @temp_weight_per_datum[mi])
  end
  update_weights!(data_array)
end

#update_temp_weights!(data_array, posterior_data_array) ⇒ Object



63
64
65
66
67
68
69
70
71
72
# File 'lib/em_algorithm/models/mixture.rb', line 63

def update_temp_weights!(data_array, posterior_data_array)
  @models.each_with_index do |model, mi|
    data_array.each_with_index do |x, di|
      temp_weight_per_datum = @weights[mi] * model.pdf(x) / posterior_data_array[di]
      temp_weight_per_datum = 0.0 if temp_weight_per_datum.nan?
      @temp_weight_per_datum[mi] <<  temp_weight_per_datum
    end
    @temp_weights[mi] = @temp_weight_per_datum[mi].inject(0.0) {|sum, w| sum + w}
  end
end

#update_weights!(data_array) ⇒ Object



74
75
76
77
78
# File 'lib/em_algorithm/models/mixture.rb', line 74

def update_weights!(data_array)
  (0..(@models.size-1)).each do |mi|
    @weights[mi] = @temp_weights[mi] / data_array.size
  end
end