Ruby百分比计算来匹配Excel公式(需要重构)
我已经用Ruby写了两个简单的计算,它们与Microsoft Excel计算给定数据集的上下四分位数的方式相匹配 – 这与普遍接受的方法(意外)不一样。
我的问题是 – 为了最大限度地干燥,这些方法可以被重构多less,怎样最好?
#与Microsoft Excel(Freund + Perles方法)相同的基础上返回上四分位值 def excel_upper_quartile(array) 返回nil,如果array.empty? sorted_array = array.sort u =(0.25 *(3 * sorted_array.length + 1)) 如果(uu.truncate).is_a?(Integer) return sorted_array [(uu.truncate)-1] 其他 sample = sorted_array [u.truncate.abs-1] sample1 = sorted_array [(u.truncate.abs)] return sample +((sample1-sample)*(uu.truncate)) 结束 结束 #在Microsoft Excel(Freund + Perles方法)的基础上返回一个较低的四分位值, def excel_lower_quartile(array) 返回nil,如果array.empty? sorted_array = array.sort u =(0.25 *(sorted_array.length + 3)) 如果(uu.truncate).is_a?(Integer) return sorted_array [(uu.truncate)-1] 其他 sample = sorted_array [u.truncate.abs-1] sample1 = sorted_array [(u.truncate.abs)] return sample +((sample1-sample)*(uu.truncate)) 结束 结束
我将首先概括一点,并提供一个方法来处理这两个实例。
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}
期望相匹配。 别的,我保证失败。
更新:
我所用的公式并没有在我引用的网站上明确给出,而是用于计算四分位数的弗氏和珀耳斯方法的抽象。
进一步更新:
在原始代码中有一个错误,尽pipe你不应该遇到这个错误: u - u.trunc
总是在[ u - u.trunc
区间内,因此唯一一个类似于整数的时候是u - u.trunc = 0
。 然而,当u
是一个Float时, (u - u.trunc)
仍然是一个Float的实例,所以你的代码不会发生在失算的索引上。 顺便说一句,如果u – u.trunc是一个整数,你的方法将返回数组的最后一个元素。
有些人可能不同意重构,但这是我如何处理它:
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 (uu.truncate).is_a?(Integer) return sorted_array[(uu.truncate)-1] else sample = sorted_array[u.truncate.abs-1] sample1 = sorted_array[(u.truncate.abs)] return sample+((sample1-sample)*(uu.truncate)) end end def excel_upper_quartile(array) excel_quartile(:upper, array) end def excel_lower_quartile(array) excel_quartile(:lower, array) end