Reputation: 25348
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
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
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
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