<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DZone Snippets: weighted code</title>
    <link>http://snippets.dzone.com/posts</link>
    <pubDate>Sat, 17 May 2008 09:35:56 GMT</pubDate>
    <description>DZone Snippets: weighted code</description>
    <item>
      <title>Weighted Mean</title>
      <link>http://snippets.dzone.com/posts/show/4613</link>
      <description>Weighted mean ( http://en.wikipedia.org/wiki/Mean#Weighted_arithmetic_mean )&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class Array&lt;br /&gt;  #sum (and mean) found on http://snippets.dzone.com/posts/show/2161&lt;br /&gt;  def sum&lt;br /&gt;    inject( nil ) { |sum,x| sum ? sum + x.to_f : x.to_f }&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;  def mean&lt;br /&gt;    sum.to_f / size&lt;br /&gt;  end&lt;br /&gt;  &lt;br /&gt;  #http://en.wikipedia.org/wiki/Mean#Weighted_arithmetic_mean&lt;br /&gt;  def weighted_mean(weights_array)&lt;br /&gt;    raise "Each element of the array must have an accompanying weight.  Array length = #{self.size} versus Weights length = #{weights_array.size}" if weights_array.size != self.size&lt;br /&gt;    w_sum = weights_array.sum&lt;br /&gt;    w_prod = 0&lt;br /&gt;    self.each_index {|i| w_prod += self[i] * weights_array[i].to_f}&lt;br /&gt;    w_prod.to_f / w_sum.to_f&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Example&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&gt;&gt; a = [1,2,3]&lt;br /&gt;=&gt; [1, 2, 3]&lt;br /&gt;&gt;&gt; w = [1,1,1]&lt;br /&gt;=&gt; [1, 1, 1]&lt;br /&gt;&gt;&gt; a.weighted_arithmetic_mean(w)&lt;br /&gt;=&gt; 2.0&lt;br /&gt;&gt;&gt; a.mean&lt;br /&gt;=&gt; 2.0&lt;br /&gt;&gt;&gt; w = [5,2,1]&lt;br /&gt;=&gt; [5, 2, 1]&lt;br /&gt;&gt;&gt; a.weighted_arithmetic_mean(w)&lt;br /&gt;=&gt; 1.5&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Wed, 03 Oct 2007 21:29:12 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/4613</guid>
      <author>wiseleyb (ben)</author>
    </item>
    <item>
      <title>Weighted Random array selection</title>
      <link>http://snippets.dzone.com/posts/show/4571</link>
      <description>Say you have an array of ['apples', 'oranges', 'bananas', 'kiwis']&lt;br /&gt;&lt;br /&gt;Selecting a random item is simple enough&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  arr = ['apples', 'oranges', 'bananas', 'kiwis']&lt;br /&gt;  arr[rand(arr.size)]&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;But say you want to have apples come up 50% of the time, oranges 25%, bananas 15% and kiwis 10% ... &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  class Array&lt;br /&gt;    &lt;br /&gt;    #sum (and mean) found on http://snippets.dzone.com/posts/show/2161&lt;br /&gt;    def sum&lt;br /&gt;      inject( nil ) { |sum,x| sum ? sum+x : x }&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;    def probability(spread = 2)&lt;br /&gt;      z = 1.0&lt;br /&gt;      collect {|x| z = z / spread}&lt;br /&gt;    end&lt;br /&gt;    def weighted_random_index(probability_array = probability(2) )&lt;br /&gt;      size.times do |x|&lt;br /&gt;        return x if rand &lt; probability_array[0..x].sum&lt;br /&gt;      end&lt;br /&gt;      return 0&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;    def get_weighted_random_item(probability_array = probability(2))&lt;br /&gt;      self[weighted_random_index(probability_array)]&lt;br /&gt;    end&lt;br /&gt;    &lt;br /&gt;    def get_weighted_random_indexes(num_items, p = probability(2))&lt;br /&gt;      res = []&lt;br /&gt;      escape = 1000&lt;br /&gt;      while res.size &lt; num_items and escape &gt; 0&lt;br /&gt;        escape -= 1&lt;br /&gt;        tmp = weighted_random_index(p) &lt;br /&gt;        res &lt;&lt; tmp unless res.include?(tmp)&lt;br /&gt;      end&lt;br /&gt;      return res.sort&lt;br /&gt;    end&lt;br /&gt;  &lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;arr = ['apples', 'oranges', 'bananas', 'kiwis']&lt;br /&gt;10.times do |i|&lt;br /&gt;  puts arr.get_weighted_random_item([0.5, 0.25, 0.15, 0.10])&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;oranges&lt;br /&gt;oranges&lt;br /&gt;apples&lt;br /&gt;apples&lt;br /&gt;bananas&lt;br /&gt;apples&lt;br /&gt;apples&lt;br /&gt;bananas&lt;br /&gt;oranges&lt;br /&gt;apples&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I'm sure there's some math term for this but I'm calling it 'spread' until I learn otherwise.  I put in a default probability array of p = p / 2 which gives you (for an array of 4)&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;arr.probability&lt;br /&gt;=&gt; [0.5, 0.25, 0.125, 0.0625]&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;On larger arrays the probabilities will get (for all practicle purposes) zero quickly&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;arr = [1,2,3,4,5,6,7,8,9]&lt;br /&gt;=&gt; [1, 2, 3, 4, 5, 6, 7, 8, 9]&lt;br /&gt;arr.probability&lt;br /&gt;=&gt; [0.5, 0.25, 0.125, 0.0625, 0.03125, 0.015625, 0.0078125, 0.00390625, 0.001953125]&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I put in a simple spread concept to spread out the probabilities a bit more... the higher the spread, the more even the probability distribution (this varies a lot with array size - but here's a simple example):&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;   arr = ['apples', 'oranges', 'bananas', 'guava']&lt;br /&gt;   iterations = 10000&lt;br /&gt;   4.times do |t|&lt;br /&gt;     p = arr.probability(t+2)&lt;br /&gt;     res = Array.new(arr.size).fill(0)&lt;br /&gt;     iterations.times do |x|&lt;br /&gt;       res[arr.weighted_random_index(p)] += 1&lt;br /&gt;     end&lt;br /&gt;     res2 = res.collect {|x| (x/iterations.to_f) * 100}&lt;br /&gt;     puts "For probability spread #{t+2}"&lt;br /&gt;     puts "Results #{res2.join(", ")} = #{res2.sum}"&lt;br /&gt;     puts ""&lt;br /&gt;   end&lt;br /&gt;&lt;br /&gt;   For probability spread 2&lt;br /&gt;   Results 49.71, 37.55, 11.35, 1.39 = 100.0&lt;br /&gt;&lt;br /&gt;   For probability spread 3&lt;br /&gt;   Results 43.44, 29.99, 17.79, 8.78 = 100.0&lt;br /&gt;&lt;br /&gt;   For probability spread 4&lt;br /&gt;   Results 48.3, 23.56, 16.73, 11.41 = 100.0&lt;br /&gt;&lt;br /&gt;   For probability spread 5&lt;br /&gt;   Results 54.22, 19.31, 14.65, 11.82 = 100.0&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Here is a longer example:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;    def weighted_random_index_example&lt;br /&gt;      arr = ['apples', 'oranges', 'bananas', 'guava']&lt;br /&gt;      puts "Sample array = [#{arr.join(",")}]"&lt;br /&gt;      p = [0.5,0.25, 0.15, 0.10]&lt;br /&gt;      puts "Probability that each will show up [#{p.join(', ')}]"&lt;br /&gt;      puts "1000 runs..."&lt;br /&gt;      res = Array.new(arr.size).fill(0)&lt;br /&gt;      1000.times do |t|&lt;br /&gt;        res[arr.weighted_random_index(p)] += 1&lt;br /&gt;      end&lt;br /&gt;      res2 = res.collect {|x| (x/1000.0) * 100}&lt;br /&gt;      puts "Results:"&lt;br /&gt;      4.times do |t|&lt;br /&gt;        puts "    #{arr[t]}: #{res2[t]}%"&lt;br /&gt;      end&lt;br /&gt;      &lt;br /&gt;      puts ""&lt;br /&gt;      puts "You can also use more spread out probability arrays"&lt;br /&gt;      p = arr.probability(3)&lt;br /&gt;      puts "Probability that each will show up with a spread of 3 [#{p.join(', ')}]"&lt;br /&gt;      puts "1000 runs..."&lt;br /&gt;      res = Array.new(arr.size).fill(0)&lt;br /&gt;      1000.times do |t|&lt;br /&gt;        res[arr.weighted_random_index(p)] += 1&lt;br /&gt;      end&lt;br /&gt;      res2 = res.collect {|x| (x/1000.0) * 100}&lt;br /&gt;      puts "Results:"&lt;br /&gt;      4.times do |t|&lt;br /&gt;        puts "    #{arr[t]}: #{res2[t]}%"&lt;br /&gt;      end&lt;br /&gt;      &lt;br /&gt;      puts ""&lt;br /&gt;      puts "You can also just get selected indexes"&lt;br /&gt;      puts "arr.get_weighted_random_indexes(3,p) = [#{arr.get_weighted_random_indexes(3,p).join(', ')}]"&lt;br /&gt;      &lt;br /&gt;      puts "The probability spread will depend on the number of items in your array - for an array of 4 it looks like this:"&lt;br /&gt;      8.times do |t|&lt;br /&gt;        puts "  probability(#{t+2}):  [#{arr.probability(t+2).collect {|x| sprintf('%0.5f',x)}.join(', ')}]"&lt;br /&gt;      end&lt;br /&gt;      return nil&lt;br /&gt;    end&lt;br /&gt;    weighted_random_index_example&lt;br /&gt;&lt;br /&gt;Outputs...&lt;br /&gt;Sample array = [apples,oranges,bananas,guava]&lt;br /&gt;Probability that each will show up [0.5, 0.25, 0.15, 0.1]&lt;br /&gt;1000 runs...&lt;br /&gt;Results:&lt;br /&gt;    apples: 49.1%&lt;br /&gt;    oranges: 38.3%&lt;br /&gt;    bananas: 11.3%&lt;br /&gt;    guava: 1.3%&lt;br /&gt;&lt;br /&gt;You can also use more spread out probability arrays&lt;br /&gt;Probability that each will show up with a spread of 3 [0.333333333333333, 0.111111111111111, 0.037037037037037, 0.0123456790123457]&lt;br /&gt;1000 runs...&lt;br /&gt;Results:&lt;br /&gt;    apples: 43.6%&lt;br /&gt;    oranges: 29.2%&lt;br /&gt;    bananas: 18.0%&lt;br /&gt;    guava: 9.2%&lt;br /&gt;&lt;br /&gt;You can also just get selected indexes&lt;br /&gt;arr.get_weighted_random_indexes(3,p) = [0, 1, 3]&lt;br /&gt;The probability spread will depend on the number of items in your array - for an array of 4 it looks like this:&lt;br /&gt;  probability(2):  [0.50000, 0.25000, 0.12500, 0.06250]&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;</description>
      <pubDate>Tue, 25 Sep 2007 21:55:19 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/4571</guid>
      <author>wiseleyb (ben)</author>
    </item>
    <item>
      <title>Weighted random choice</title>
      <link>http://snippets.dzone.com/posts/show/732</link>
      <description>From Kevin Parks's &lt;a href=http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117241&gt;recipe&lt;/a&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;import random&lt;br /&gt;&lt;br /&gt;def w_choice(lst):&lt;br /&gt;	n = random.uniform(0, 1)&lt;br /&gt;	for item, weight in lst:&lt;br /&gt;		if n &lt; weight:&lt;br /&gt;			break&lt;br /&gt;		n = n - weight&lt;br /&gt;	return item&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Usage, similar to random.choice but must specify probabilities.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&gt;&gt;&gt; x = w_choice( [('one',0.25), ('two',0.25), ('three',0.5)] )&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;</description>
      <pubDate>Sat, 17 Sep 2005 05:41:27 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/732</guid>
      <author>korakot (Korakot Chaovavanich)</author>
    </item>
  </channel>
</rss>
