2009-11-16 3 views
0

Я написал два простых расчета с Ruby, которые соответствуют тому, как Microsoft Excel вычисляет верхний и нижний квартили для заданного набора данных - это не то же самое, что общепринятый способ (удивление).Расчет Ruby Percentile в соответствии с формулами 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

Как показано ниже, первый оператор if должен быть 'return sorted [u.truncate-1], если (u-u.truncate) .zero?' – Dave

ответ

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}. Что-нибудь еще, я гарантирую отказ.

Обновление:

формулы я использовал это специально не указана на сайте я цитируемый, но это абстракция для метода Freund и Perles вычисления позиции квартили.

Дальнейшее обновление:

Существует ошибка в исходном коде, хотя вы никогда не должны столкнуться с ним: u - u.trunc всегда находится в интервале [0,0, 1,0), таким образом, единственный раз, когда он будет напоминать целое, когда u - u.trunc = 0. Тем не менее, (u - u.trunc) по-прежнему является экземпляром Float, когда u является плавающей точкой, поэтому ваш код никогда не происходит на просчитанном индексе. Кстати, если u - u.trunc были целыми числами, ваш метод вернул бы последний элемент массива.

Смежные вопросы