Module: Enumerable

Included in:
FixedRange
Defined in:
lib/just_enumerable_stats.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *args, &block) ⇒ Object



327
328
329
330
331
332
333
# File 'lib/just_enumerable_stats.rb', line 327

def method_missing(sym, *args, &block)
  if self.categories.include?(sym)
    self._jes_render_category(sym)
  else
    super
  end
end

Instance Attribute Details

#_jes_range_class_argsObject (readonly)

The arguments needed to instantiate the custom-defined range class.



356
357
358
# File 'lib/just_enumerable_stats.rb', line 356

def _jes_range_class_args
  @_jes_range_class_args
end

#_jes_range_hashObject (readonly)

The hash of lambdas that are used to categorize the enumerable.



352
353
354
# File 'lib/just_enumerable_stats.rb', line 352

def _jes_range_hash
  @_jes_range_hash
end

Class Method Details

.safe_alias(sym1, sym2 = nil) ⇒ Object

Defines the new methods unobtrusively.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/just_enumerable_stats.rb', line 51

def self.safe_alias(sym1, sym2=nil)

  return false if not sym2 and not sym1.to_s.match(/^_jes_/)
  
  if sym2
    old_meth = sym2
    new_meth = sym1
  else
    old_meth = sym1
    new_meth = sym1.to_s.sub(/^_jes_/, '').to_sym
    return false if self.class.respond_to?(new_meth)
  end
  alias_method new_meth, old_meth
end

Instance Method Details

#_jes_add_category(hash, &block) ⇒ Object

Allows you to add one category at a time. You can actually add more than one category at a time, but it won’t disrupt any previously-set categories.



311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/just_enumerable_stats.rb', line 311

def _jes_add_category(hash, &block)
  _jes_init_range_hash
  if hash.is_a?(Hash)
    hash.each do |k, v|
      @_jes_range_hash[k] = v
      @_jes_categories << k
    end
    @_jes_category_values = nil
    hash
  # Allows the syntax a.add_category(:two_or_three) {|e| e == 2 or e == 3}
  elsif block
    _jes_add_category(hash => block)
  end
end

#_jes_all_categories(value) ⇒ Object



420
421
422
423
424
425
426
427
428
# File 'lib/just_enumerable_stats.rb', line 420

def _jes_all_categories(value)
  return [value] unless self.range_hash
  self._jes_range_hash.inject([]) do |list, e|
    cat = e.first
    block = e.last
    list << cat if block.call(value)
    list
  end
end

#_jes_average(&block) ⇒ Object

The arithmetic mean, uses a block or default block.



139
140
141
# File 'lib/just_enumerable_stats.rb', line 139

def _jes_average(&block)
  _jes_sum(&block)/size
end

#_jes_cartesian_product(other, &block) ⇒ Object

Finds the cartesian product, excluding duplicates items and self- referential pairs. Yields the block value if given.



668
669
670
671
672
673
674
675
# File 'lib/just_enumerable_stats.rb', line 668

def _jes_cartesian_product(other, &block)
  x,y = self.uniq.dup, other.uniq.dup
  pairs = x.inject([]) do |cp, i|
    cp | y.map{|b| i == b ? nil : [i,b]}.compact
  end
  return pairs unless block_given?
  pairs.map{|p| yield p.first, p.last}
end

#_jes_categoriesObject

Takes the range_class and returns its map. Example: require ‘mathn’ a = [1,2,3] a range_class = FixedRange, a.min, a.max, 1/4 a.categories

> [1, 5/4, 3/2, 7/4, 2, 9/4, 5/2, 11/4, 3]

For non-numeric values, returns a unique set, ordered if possible.



254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/just_enumerable_stats.rb', line 254

def _jes_categories
  if @_jes_categories
    @_jes_categories
  elsif self.any? {|e| e.is_a?(Float)}
    val = self.map {|e| e}
    val.uniq.sort rescue val
  elsif self._jes_is_numeric?
    val = self._jes_range_instance.map {|e| e}
    val.uniq.sort rescue val
  else
    self.uniq.sort rescue self.uniq
  end
end

#_jes_category_map(reset = false) ⇒ Object



431
432
433
434
435
436
437
# File 'lib/just_enumerable_stats.rb', line 431

def _jes_category_map(reset=false)
  @_jes_category_map = nil if reset
  return @_jes_category_map if @_jes_category_map
  @_jes_category_map = self.inject([]) do |list, e|
    list << self._jes_first_category(e)
  end
end

#_jes_category_values(reset = false) ⇒ Object

Returns a Hash or Dictionary (if available) for each category with a value as the set of matching values as an array. Because this is supposed to be lean (just enumerables), but this is an expensive call, I’m going to cache it and offer a parameter to reset the cache. So, call category_values(true) if you need to reset the cache.



386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
# File 'lib/just_enumerable_stats.rb', line 386

def _jes_category_values(reset=false)
  @_jes_category_values = nil if reset
  return @_jes_category_values if @_jes_category_values
  container = defined?(Dictionary) ? Dictionary.new : Hash.new
  if self.range_hash
    @_jes_category_values = self._jes_categories.inject(container) do |cont, cat|
      cont[cat] = self.find_all &self._jes_range_hash[cat]
      cont
    end
  else
    @_jes_category_values = self._jes_categories.inject(container) do |cont, cat|
      cont[cat] = self.find_all {|e| e == cat}
      cont
    end
  end
end

#_jes_compliment(other) ⇒ Object

Everything on the left hand side except what’s shared on the right hand side. “The relative compliment of y in x”



655
656
657
# File 'lib/just_enumerable_stats.rb', line 655

def _jes_compliment(other)
  self - other
end

#_jes_correlation(other) ⇒ Object

Finds the correlation between two enumerables. Example: [1,2,3].cor [2,3,5] returns 0.981980506061966



717
718
719
720
721
722
723
724
725
726
727
728
729
730
# File 'lib/just_enumerable_stats.rb', line 717

def _jes_correlation(other)
  n = [self.size, other.size]._jes_min
  sum_of_products_of_pairs = self._jes_sigma_pairs(other) {|a, b| a * b}
  self_sum = self._jes_sum
  other_sum = other._jes_sum
  sum_of_squared_self_scores = self._jes_sum { |e| e * e }
  sum_of_squared_other_scores = other._jes_sum { |e| e * e }
  
  numerator = (n * sum_of_products_of_pairs) - (self_sum * other_sum)
  self_denominator = ((n * sum_of_squared_self_scores) - (self_sum ** 2))
  other_denominator = ((n * sum_of_squared_other_scores) - (other_sum ** 2))
  denominator = Math.sqrt(self_denominator * other_denominator)
  return numerator / denominator
end

#_jes_count_if(&block) ⇒ Object

Counts each element where the block evaluates to true Example: a = [1,2,3] a.count_if {|e| e % 2 == 0}



372
373
374
375
376
377
# File 'lib/just_enumerable_stats.rb', line 372

def _jes_count_if(&block)
  self.inject(0) do |s, e|
    s += 1 if block.call(e)
    s
  end
end

#_jes_covariance(other) ⇒ Object

Returns the covariance of two lists.



761
762
763
764
765
766
767
768
769
# File 'lib/just_enumerable_stats.rb', line 761

def _jes_covariance(other)
  self._jes_to_f!
  other._jes_to_f!
  n = [self.size, other.size]._jes_min
  self_average = self._jes_average
  other_average = other._jes_average
  total_expected = self._jes_sigma_pairs(other) {|a, b| (a - self_average) * (b - other_average)}
  total_expected / n
end

#_jes_cum_max(&block) ⇒ Object

Example:

1,2,3,0,5].cum_max # => [1,2,3,3,5


586
587
588
589
590
591
# File 'lib/just_enumerable_stats.rb', line 586

def _jes_cum_max(&block)
  _jes_morph_list(&block).inject([]) do |list, e|
    found = (list | [e])._jes_max
    list << (found ? found : e)
  end
end

#_jes_cum_min(&block) ⇒ Object

Example:

1,2,3,0,5].cum_min # => [1,1,1,0,0


597
598
599
600
601
602
# File 'lib/just_enumerable_stats.rb', line 597

def _jes_cum_min(&block)
    _jes_morph_list(&block).inject([]) do |list, e|
    found = (list | [e]).min
    list << (found ? found : e)
  end
end

#_jes_cum_prod(sorted = false, &block) ⇒ Object

The cummulative product. Example:

1,2,3].cum_prod # => [1.0, 2.0, 6.0


558
559
560
561
562
563
564
565
566
567
568
# File 'lib/just_enumerable_stats.rb', line 558

def _jes_cum_prod(sorted=false, &block)
  prod = _jes_one
  obj = sorted ? self.sort : self
  if block_given?
    obj.map { |i| prod *= yield(i) }
  elsif _jes_default_block
    obj.map { |i| prod *= _jes_default_block[*i] }
  else
    obj.map { |i| prod *= i }
  end
end

#_jes_cum_sum(sorted = false, &block) ⇒ Object

The cummulative sum. Example:

1,2,3].cum_sum # => [1, 3, 6


542
543
544
545
546
547
548
549
550
551
552
# File 'lib/just_enumerable_stats.rb', line 542

def _jes_cum_sum(sorted=false, &block)
  sum = _jes_zero
  obj = sorted ? self.sort : self
  if block_given?
    obj.map { |i| sum += yield(i) }
  elsif _jes_default_block
    obj.map { |i| sum += _jes_default_block[*i] }
  else
    obj.map { |i| sum += i }
  end
end

#_jes_default_blockObject

The block called to filter the values in the object.



97
98
99
# File 'lib/just_enumerable_stats.rb', line 97

def _jes_default_block
  @_jes_default_stat_block 
end

#_jes_default_block=(block) ⇒ Object

Allows me to setup a block for a series of operations. Example: a = [1,2,3] a.sum # => 6.0 a.default_block = lambda{|e| 1 / e} a.sum # => 1.0



107
108
109
# File 'lib/just_enumerable_stats.rb', line 107

def _jes_default_block=(block)
  @_jes_default_stat_block = block
end

#_jes_dichotomize(split_value, first_label, second_label) ⇒ Object

Splits the values in two, <= the value and > the value.



360
361
362
363
364
365
# File 'lib/just_enumerable_stats.rb', line 360

def _jes_dichotomize(split_value, first_label, second_label)
  container = defined?(Dictionary) ? Dictionary.new : Hash.new
  container[first_label] = lambda{|e| e <= split_value}
  container[second_label] = lambda{|e| e > split_value}
  _jes_set_range(container)
end

#_jes_euclidian_distance(other) ⇒ Object

Returns the Euclidian distance between all points of a set of enumerables



689
690
691
# File 'lib/just_enumerable_stats.rb', line 689

def _jes_euclidian_distance(other)
  Math.sqrt(self._jes_sigma_pairs(other) {|a, b| (a - b) ** 2})
end

#_jes_exclusive_not(other) ⇒ Object

Everything but what’s shared



661
662
663
# File 'lib/just_enumerable_stats.rb', line 661

def _jes_exclusive_not(other)
  (self | other) - (self & other)
end

#_jes_first_category(value) ⇒ Object

Returns the first category of a value. Example: a = [1,2,3] a.first_category(2) # => 2 a.add_category(:small) {|e| e <= 1} a.add_category(:large) {|e| e > 1} a.first_category(2) # => :large



410
411
412
413
414
415
416
# File 'lib/just_enumerable_stats.rb', line 410

def _jes_first_category(value)
  return value unless self.range_hash
  self._jes_range_hash.each do |cat, block|
    return cat if block.call(value)
  end
  return nil
end

#_jes_frequencyObject

Returns a hash or dictionary (if installed) of the frequency of each category.



860
861
862
863
864
865
866
# File 'lib/just_enumerable_stats.rb', line 860

def _jes_frequency
  dict = defined?(Dictionary) ? Dictionary.new : Hash.new
  self._jes_category_values.each do |k, v|
    dict[k] = v.size / self.size
  end
  dict
end

#_jes_frequency_for(key) ⇒ Object



869
870
871
# File 'lib/just_enumerable_stats.rb', line 869

def _jes_frequency_for(key)
  self._jes_frequency[key]
end

#_jes_intersect(other) ⇒ Object

What’s shared on the left and right hand sides “The intersection of x and y”



647
648
649
# File 'lib/just_enumerable_stats.rb', line 647

def _jes_intersect(other)
  self & other
end

#_jes_is_numeric?Boolean

Returns:

  • (Boolean)


269
270
271
# File 'lib/just_enumerable_stats.rb', line 269

def _jes_is_numeric?
  self.all? {|e| e.is_a?(Numeric)}
end

#_jes_max(&block) ⇒ Object

Returns the max, using an optional block.



67
68
69
70
71
72
# File 'lib/just_enumerable_stats.rb', line 67

def _jes_max(&block)
  self.inject do |best, e|
    val = _jes_block_sorter(best, e, &block)
    best = val > 0 ? best : e
  end
end

#_jes_max_index(&block) ⇒ Object

Returns the first index of the max value



76
77
78
# File 'lib/just_enumerable_stats.rb', line 76

def _jes_max_index(&block)
  self.index(_jes_max(&block))
end

#_jes_max_of_lists(*enums) ⇒ Object

Returns the max of two or more enumerables. >> [1,2,3].max_of_lists(, [0,2,9])

> [1, 5, 9]



747
748
749
# File 'lib/just_enumerable_stats.rb', line 747

def _jes_max_of_lists(*enums)
  _jes_yield_transpose(*enums) {|e| e._jes_max}
end

#_jes_median(ratio = 0.5, &block) ⇒ Object

The slow way is to iterate up to the middle point. A faster way is to use the index, when available. If a block is supplied, always iterate to the middle point.



171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/just_enumerable_stats.rb', line 171

def _jes_median(ratio=0.5, &block)
  return _jes_iterate_midway(ratio, &block) if block_given?
  begin
    mid1, mid2 = _jes_middle_two
    sorted = sort
    med1, med2 = sorted[mid1], sorted[mid2]
    return med1 if med1 == med2
    return med1 + ((med2 - med1) * ratio)
  rescue
    _jes_iterate_midway(ratio, &block)
  end
end

#_jes_min(&block) ⇒ Object

Min of any number of items



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

def _jes_min(&block)
  self.inject do |best, e|
    val = _jes_block_sorter(best, e, &block)
    best = val < 0 ? best : e
  end
end

#_jes_min_index(&block) ⇒ Object

Returns the first index of the min value



91
92
93
# File 'lib/just_enumerable_stats.rb', line 91

def _jes_min_index(&block)
  self.index(_jes_min(&block))
end

#_jes_min_of_lists(*enums) ⇒ Object

Returns the min of two or more enumerables. >> [1,2,3].min_of_lists(, [0,2,9])

> [0, 2, 3]



755
756
757
# File 'lib/just_enumerable_stats.rb', line 755

def _jes_min_of_lists(*enums)
  _jes_yield_transpose(*enums) {|e| e.min}
end

#_jes_new_sort(&block) ⇒ Object

I don’t pass the block to the sort, because a sort block needs to look something like: {|x,y| x <=> y}. To get around this, set the default block on the object.



462
463
464
465
466
467
468
469
470
# File 'lib/just_enumerable_stats.rb', line 462

def _jes_new_sort(&block)
  if block_given?
    map { |i| yield(i) }.sort.dup
  elsif _jes_default_block
    map { |i| _jes_default_block[*i] }.sort.dup
  else
    sort().dup
  end
end

#_jes_normalizeObject



821
822
823
824
825
# File 'lib/just_enumerable_stats.rb', line 821

def _jes_normalize
  min = self._jes_min
  diff = self._jes_max - min
  self.map {|e| (e - min) / diff }
end

#_jes_normalize!Object



828
829
830
831
832
# File 'lib/just_enumerable_stats.rb', line 828

def _jes_normalize!
  min = self._jes_min
  diff = self._jes_max - min
  self.map! {|e| (e - min) / diff }
end

#_jes_order(&block) ⇒ Object

Given values like [10,5,5,1] Rank should produce something like [4,2,2,1] And order should produce something like [4,2,3,1] The trick is that rank skips as many as were duplicated, so there could not be a 3 in the rank from the example above.



498
499
500
501
502
503
504
505
506
507
# File 'lib/just_enumerable_stats.rb', line 498

def _jes_order(&block)
  hold = []
  _jes_rank(&block).each do |x|
    while hold.include?(x) do
      x += 1
    end
    hold << x
  end
  hold
end

#_jes_pearson_correlation(other) ⇒ Object

The covariance / product of standard deviations en.wikipedia.org/wiki/Correlation



774
775
776
777
778
779
# File 'lib/just_enumerable_stats.rb', line 774

def _jes_pearson_correlation(other)
  self._jes_to_f!
  other._jes_to_f!
  denominator = self._jes_standard_deviation * other._jes_standard_deviation
  self._jes_covariance(other) / denominator
end

#_jes_productObject

Multiplies the values: >> product(1,2,3)

> 6.0



609
610
611
# File 'lib/just_enumerable_stats.rb', line 609

def _jes_product
  self.inject(_jes_one) {|sum, a| sum *= a}
end

#_jes_quantile(&block) ⇒ Object

First quartile: nth_split_by_m(1, 4) Third quartile: nth_split_by_m(3, 4) Median: nth_split_by_m(1, 2) Doesn’t match R, and it’s silly to try to. def _jes_nth_split_by_m(n, m)

sorted  = new_sort
dividers = m - 1
if size % m == dividers # Divides evenly
  # Because we have a 0-based list, we get the floor
  i = ((size / m.to_f) * n).floor
  j = i
else
  # This reflects R's approach, which I don't think I agree with.
  i = (((size / m.to_f) * n) - 1)
  i = i > (size / m.to_f) ? i.floor : i.ceil
  j = i + 1
end
sorted[i] + ((n / m.to_f) * (sorted[j] - sorted[i]))

end



529
530
531
532
533
534
535
536
537
# File 'lib/just_enumerable_stats.rb', line 529

def _jes_quantile(&block)
  [
    _jes_min(&block), 
    _jes_first_half(&block)._jes_median(0.25, &block), 
    _jes_median(&block), 
    _jes_second_half(&block)._jes_median(0.75, &block), 
    _jes_max(&block)
  ]
end

#_jes_rand_in_range(*args) ⇒ Object

Returns a random integer in the range for any number of lists. This is a way to get a random vector that is tenable based on the sample data. For example, given two sets of numbers:

a = [1,2,3]; b = [8,8,8]

rand_in_pair_range will return a value >= 1 and <= 8 in the first place, >= 2 and <= 8 in the second place, and >= 3 and <= 8 in the last place. Works for integers. Rethink this for floats. May consider setting up FixedRange for floats. O(n*5)



705
706
707
708
709
710
711
# File 'lib/just_enumerable_stats.rb', line 705

def _jes_rand_in_range(*args)
  min = self._jes_min_of_lists(*args)
  max = self._jes_max_of_lists(*args)
  (0...size).inject([]) do |ary, i|
    ary << rand_between(min[i], max[i])
  end
end

#_jes_range(&block) ⇒ Object

Just an array of [min, max] to comply with R uses of the work. Use range_as_range if you want a real Range.



276
277
278
# File 'lib/just_enumerable_stats.rb', line 276

def _jes_range(&block)
  [_jes_min(&block), _jes_max(&block)]
end

#_jes_range_as_range(&block) ⇒ Object

Actually instantiates the range, instead of producing a min and max array.



448
449
450
451
452
453
454
# File 'lib/just_enumerable_stats.rb', line 448

def _jes_range_as_range(&block)
  if @_jes_range_class_args and not @_jes_range_class_args.empty?
    self._jes_range_class.new(*@_jes_range_class_args)
  else
    self._jes_range_class.new(_jes_min(&block), _jes_max(&block))
  end
end

#_jes_range_classObject

When creating a range, what class will it be? Defaults to Range, but other classes are sometimes useful.



442
443
444
# File 'lib/just_enumerable_stats.rb', line 442

def _jes_range_class
  @_jes_range_class ||= Range
end

#_jes_rank(&block) ⇒ Object

Ranks the values



474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
# File 'lib/just_enumerable_stats.rb', line 474

def _jes_rank(&block)

  sorted = _jes_new_sort(&block)
  # rank = map { |i| sorted.index(i) + 1 }

  if block_given?
    map { |i| sorted.index(yield(i)) + 1 }
  elsif _jes_default_block
    map { |i| 
      sorted.index(_jes_default_block[*i]) + 1 }
  else
    map { |i| sorted.index(i) + 1 }
  end

end

#_jes_render_category(category) ⇒ Object

Returns a specific category’s values



336
337
338
# File 'lib/just_enumerable_stats.rb', line 336

def _jes_render_category(category)
  self.category_values[category]
end

#_jes_scale(val = nil, &block) ⇒ Object



793
794
795
796
797
798
799
# File 'lib/just_enumerable_stats.rb', line 793

def _jes_scale(val=nil, &block)
  if block
    self.map{|e| block.call(e)}
  else
    self.map{|e| e * val}
  end
end

#_jes_scale!(val = nil, &block) ⇒ Object



802
803
804
805
806
807
808
# File 'lib/just_enumerable_stats.rb', line 802

def _jes_scale!(val=nil, &block)
  if block
    self.map!{|e| block.call(e)}
  else
    self.map!{|e| e * val}
  end
end

#_jes_scale_between(*values) ⇒ Object

Raises:

  • (ArgumentError)


835
836
837
838
839
840
841
842
843
844
# File 'lib/just_enumerable_stats.rb', line 835

def _jes_scale_between(*values)
  raise ArgumentError, "Must provide two values" unless values.size == 2
  values.sort!
  min = values[0]
  max = values[1]
  orig_min = self._jes_min
  scalar = (max - min) / (self._jes_max - orig_min).to_f
  shift = min - (orig_min * scalar)
  self._jes_scale{|e| (e * scalar) + shift}
end

#_jes_scale_between!(*values) ⇒ Object

Raises:

  • (ArgumentError)


847
848
849
850
851
852
853
854
855
856
# File 'lib/just_enumerable_stats.rb', line 847

def _jes_scale_between!(*values)
  raise ArgumentError, "Must provide two values" unless values.size == 2
  values.sort!
  min = values[0]
  max = values[1]
  orig_min = self._jes_min
  scalar = (max - min) / (self._jes_max - orig_min).to_f
  shift = min - (orig_min * scalar)
  self._jes_scale!{|e| (e * scalar) + shift}
end

#_jes_scale_to_sigmoidObject



811
812
813
# File 'lib/just_enumerable_stats.rb', line 811

def _jes_scale_to_sigmoid
  self._jes_scale { |e| 1 / (1 + Math.exp( -1 * (e))) }
end

#_jes_scale_to_sigmoid!Object



816
817
818
# File 'lib/just_enumerable_stats.rb', line 816

def _jes_scale_to_sigmoid!
  self._jes_scale! { |e| 1 / (1 + Math.exp( -1 * (e))) }
end

#_jes_set_range(hash) ⇒ Object

Takes a hash of arrays for categories If Facets happens to be loaded on the computer, this keeps the order of the categories straight.



292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/just_enumerable_stats.rb', line 292

def _jes_set_range(hash)
  if defined?(Dictionary)
    @_jes_range_hash = Dictionary.new
    @_jes_range_hash.merge!(hash)
    @_jes_categories = @_jes_range_hash.keys.dup
  else
    @_jes_categories = hash.keys.dup
    @_jes_range_hash = hash
  end
  @_jes_category_values = nil
  @_jes_categories
end

#_jes_set_range_class(klass, *args) ⇒ Object

Useful for setting a real range class (FixedRange).



282
283
284
285
286
# File 'lib/just_enumerable_stats.rb', line 282

def _jes_set_range_class(klass, *args)
  @_jes_range_class = klass
  @_jes_range_class_args = args
  self._jes_range_class
end

#_jes_sigma_pairs(other, z = _jes_zero, &block) ⇒ Object

Sigma of pairs. Returns a single float, or whatever object is sent in. Example: [1,2,3].sigma_pairs(, 0) {|x, y| x + y} returns 21 instead of 21.0.



683
684
685
# File 'lib/just_enumerable_stats.rb', line 683

def _jes_sigma_pairs(other, z=_jes_zero, &block)
  self._jes_to_pairs(other,&block).inject(z) {|sum, i| sum += i}
end

#_jes_standard_deviation(&block) ⇒ Object

The standard deviation. Uses a block or default block.



162
163
164
# File 'lib/just_enumerable_stats.rb', line 162

def _jes_standard_deviation(&block)
  Math::sqrt(_jes_variance(&block))
end

#_jes_sumObject

Adds up the list. Uses a block or default block if present.



125
126
127
128
129
130
131
132
133
134
135
# File 'lib/just_enumerable_stats.rb', line 125

def _jes_sum
  sum = _jes_zero
  if block_given?
    each{|i| sum += yield(i)}
  elsif _jes_default_block
    each{|i| sum += _jes_default_block[*i]}
  else
    each{|i| sum += i}
  end
  sum
end

#_jes_tanimoto_pairs(other) ⇒ Object

Finds the tanimoto coefficient: the intersection set size / union set size. This is used to find the distance between two vectors. >> [1,2,3].cor()

> 0.981980506061966

>> [1,2,3].tanimoto_pairs()

> 0.5



628
629
630
# File 'lib/just_enumerable_stats.rb', line 628

def _jes_tanimoto_pairs(other)
  _jes_intersect(other).size / _jes_union(other).size.to_f
end

#_jes_to_f!Object

Some calculations have to have at least floating point numbers. This generates a cached version of the operation–only runs once per object.



784
785
786
787
# File 'lib/just_enumerable_stats.rb', line 784

def _jes_to_f!
  return true if @_jes_to_f
  @_jes_to_f = self.map! {|e| e.to_f}
end

#_jes_to_pairs(other, &block) ⇒ Object

There are going to be a lot more of these kinds of things, so pay attention.



616
617
618
619
# File 'lib/just_enumerable_stats.rb', line 616

def _jes_to_pairs(other, &block)
  n = [self.size, other.size]._jes_min
  (0...n).map {|i| block.call(self[i], other[i]) }
end

#_jes_union(other) ⇒ Object

All of the left and right hand sides, excluding duplicates. “The union of x and y”



640
641
642
# File 'lib/just_enumerable_stats.rb', line 640

def _jes_union(other)
  self | other
end

#_jes_variance(&block) ⇒ Object

The variance, uses a block or default block.



147
148
149
150
151
152
153
154
155
156
157
# File 'lib/just_enumerable_stats.rb', line 147

def _jes_variance(&block)
  m = _jes_average(&block)
  sum_of_differences = if block_given?
    _jes_sum{ |i| j=yield(i); (m - j) ** 2 }
  elsif _jes_default_block
    _jes_sum{ |i| j=_jes_default_block[*i]; (m - j) ** 2 }
  else
    _jes_sum{ |i| (m - i) ** 2 }
  end
  sum_of_differences / (size - 1)
end

#_jes_yield_transpose(*enums, &block) ⇒ Object

Transposes arrays of arrays and yields a block on the value. The regular Array#transpose ignores blocks



736
737
738
739
740
741
# File 'lib/just_enumerable_stats.rb', line 736

def _jes_yield_transpose(*enums, &block)
  enums.unshift(self)
  n = enums.map{ |x| x.size}.min
  block ||= lambda{|e| e}
  (0...n).map { |i| block.call enums.map{ |x| x[i] } }
end