Shpigford
Shpigford

Reputation: 25348

Calculate interquartile mean from Ruby array?

I have this array:

[288.563044, 329.835918, 578.622569, 712.359026, 866.614253, 890.066321, 1049.78037, 1070.29897, 2185.443662, 2492.245562, 4398.300227, 13953.264379]

How do I calculate the interquartile mean from this?

That Wikipedia link explains it best, but I basically need to remove the bottom and top 25% leaving only the middle 50%, of which I'll need to average the numbers.

But that's assuming the number of array items is divisible by 4. Here's how to calculate it when it's not divisible by four.

So how would I do that as well?

Upvotes: 4

Views: 1028

Answers (3)

bouchard
bouchard

Reputation: 850

An improvement on tokland's answer that augments the Array class and fixes an edge case (method as written blows up with array size of 4).

class Array
  def interquartile_mean
     a = sort
     l = size
     quart = (l.to_f / 4).floor
     t = a[quart..-(quart + 1)]
     t.inject{ |s, e| s + e }.to_f / t.size
  end
end

Upvotes: 1

tokland
tokland

Reputation: 67870

The simple case array_size mod 4 = 0:

xs = [5, 8, 4, 38, 8, 6, 9, 7, 7, 3, 1, 6]
q = xs.size / 4
ys = xs.sort[q...3*q]
mean = ys.inject(0, :+) / ys.size.to_f
#=> 6.5

The general case (array_size >= 4):

xs = [1, 3, 5, 7, 9, 11, 13, 15, 17]
q = xs.size / 4.0
ys = xs.sort[q.ceil-1..(3*q).floor]
factor = q - (ys.size/2.0 - 1)
mean = (ys[1...-1].inject(0, :+) + (ys[0] + ys[-1]) * factor) / (2*q)
#=> 9.0

However, if you don't try to code it yourself this won't help much...

Upvotes: 2

Jesse Pollak
Jesse Pollak

Reputation: 1600

This is a partial solution for an array with a number of elements that is a multiple of 4. I'll put the full one when I figure it out.

arr = [288.563044, 329.835918, 578.622569, 712.359026, 866.614253, 890.066321, 1049.78037,    1070.29897, 2185.443662, 2492.245562, 4398.300227, 13953.264379].sort!
length = arr.size
mean = arr.sort[(length/4)..-(length/4+1)].inject(:+)/(length/2)

I think this is a better solution.

def interquartile_mean(array)
   arr = array.sort
   length = arr.size
   quart = (length/4.0).floor
   fraction = 1-((length/4.0)-quart)
   new_arr = arr[quart..-(quart + 1)]
   (fraction*(new_arr[0]+new_arr[-1]) + new_arr[1..-2].inject(:+))/(length/2.0)
end

Upvotes: 4

Related Questions