class WeightedSampler::Base
Public Class Methods
new(enum, seed: nil, skip_normalization: false)
click to toggle source
# File lib/weighted_sampler.rb, line 13 def initialize(enum, seed: nil, skip_normalization: false) @random = Random.new(seed) unless seed.nil? if enum.is_a?(Hash) @p_margins = normalized_margins(enum.values, skip_normalization) @keys = enum.keys elsif enum.is_a?(Array) @p_margins = normalized_margins(enum, skip_normalization) @keys = [*0...enum.size] end return unless @p_margins.nil? || @keys.nil? || @keys.empty? raise ArgumentError, 'input structure must be a non-empty Hash or Array' end
Public Instance Methods
sample()
click to toggle source
# File lib/weighted_sampler.rb, line 29 def sample pick = @random ? @random.rand : rand idx = @p_margins.find_index { |margin| pick < margin } idx ||= @p_margins.count - 1 # safe assignment if last margin was not good enough @keys[idx] end
Private Instance Methods
incremental_margins(array)
click to toggle source
convert probs like [0.1, 0.2, 0.3, 0.4] to incremental margins [0.1, 0.3, 0.6, 1.0]
# File lib/weighted_sampler.rb, line 55 def incremental_margins(array) start = 0.0 margins = array.map do |v| res = v + start start = res res end raise 'normalized probabilities total is not 1' if (start - 1.0).abs > ERROR_ALLOWANCE margins end
normalize_probabilities(array)
click to toggle source
# File lib/weighted_sampler.rb, line 47 def normalize_probabilities(array) sum = array.inject(&:+).to_f array.map { |el| el / sum } end
normalized_margins(array, skip_normalization)
click to toggle source
# File lib/weighted_sampler.rb, line 40 def normalized_margins(array, skip_normalization) raise ArgumentError, 'weights can be only positive' if array.any?(&:negative?) probabilities = skip_normalization ? array : normalize_probabilities(array) incremental_margins probabilities end