2009-11-16 25 views
0

我已经用Ruby编写了两个简单的计算,它们与Microsoft Excel计算给定数据集的上下四分位数的方式相匹配 - 这不同于普遍接受的方法(意外)。红宝石百分比计算匹配Excel公式(需要重构)

我的问题是 - 为了获得最大的干燥度,这些方法可以重构多少以及如何最好?

 
# Return an upper quartile value on the same basis as Microsoft Excel (Freund+Perles method) 
    def excel_upper_quartile(array) 
     return nil if array.empty? 
     sorted_array = array.sort 
     u = (0.25*(3*sorted_array.length+1)) 
     if (u-u.truncate).is_a?(Integer) 
     return sorted_array[(u-u.truncate)-1] 
     else 
     sample = sorted_array[u.truncate.abs-1] 
     sample1 = sorted_array[(u.truncate.abs)] 
     return sample+((sample1-sample)*(u-u.truncate)) 
     end 
    end 


    # Return a lower quartile value on the same basis as Microsoft Excel (Freund+Perles method) 
    def excel_lower_quartile(array) 
     return nil if array.empty? 
     sorted_array = array.sort 
     u = (0.25*(sorted_array.length+3)) 
     if (u-u.truncate).is_a?(Integer) 
     return sorted_array[(u-u.truncate)-1] 
     else 
     sample = sorted_array[u.truncate.abs-1] 
     sample1 = sorted_array[(u.truncate.abs)] 
     return sample+((sample1-sample)*(u-u.truncate)) 
     end 
    end 
+0

正如Ian指出的那样,如果(u-u.truncate).zero?'那么第一个if语句应该是'return sorted [u.truncate-1] – Dave 2011-07-13 08:40:32

回答

2

也许有人会不同意的重构,但这里是我会怎么处理这件事:

def excel_quartile(extreme,array)  
    return nil if array.empty? 
    sorted_array = array.sort 
    u = case extreme 
    when :upper then 3 * sorted_array.length + 1 
    when :lower then sorted_array.length + 3 
    else raise "ArgumentError" 
    end 
    u *= 0.25 
    if (u-u.truncate).is_a?(Integer) 
    return sorted_array[(u-u.truncate)-1] 
    else 
    sample = sorted_array[u.truncate.abs-1] 
    sample1 = sorted_array[(u.truncate.abs)] 
    return sample+((sample1-sample)*(u-u.truncate)) 
    end 
end 

def excel_upper_quartile(array) 
    excel_quartile(:upper, array) 
end 

def excel_lower_quartile(array) 
    excel_quartile(:lower, array) 
end 
4

我会通过概括一点开始,并提供一个方法来处理这两种情况。

def excel_quartile(array, quartile) 
    # Returns nil if array is empty and covers the case of array.length == 1 
    return array.first if array.length <= 1 
    sorted = array.sort 
    # The 4th quartile is always the last element in the sorted list. 
    return sorted.last if quartile == 4 
    # Source: http://mathworld.wolfram.com/Quartile.html 
    quartile_position = 0.25 * (quartile*sorted.length + 4 - quartile) 
    quartile_int = quartile_position.to_i 
    lower = sorted[quartile_int - 1] 
    upper = sorted[quartile_int] 
    lower + (upper - lower) * (quartile_position - quartile_int) 
end 

然后你就可以方便的方法:

def excel_lower_quartile(array) 
    excel_quartile(array, 1) 
end 

def excel_upper_quartile(array) 
    excel_quartile(array, 3) 
end 

注:excel_quartile方法相匹配quartile in { 1, 2, 3, 4}预期。别的,我保证失败。

更新:

我使用的公式不是明确地在网站我引用给出的,但它是用于计算四分位位置的弗氏和PERLES方法的抽象。

进一步更新:

有一个在你原来代码中的错误,但你永远不应该遇到它:u - u.trunc始终是区间[0.0,1.0)内,因此,只有时间会像一个整数时u - u.trunc = 0。但(u - u.trunc)仍然是Float的一个实例,只要u是一个Float,所以你的代码不会发生在失算的索引上。顺便说一句,如果u - u.trunc是一个整数,你的方法会返回数组的最后一个元素。