Расчеты Ruby Percentile для соответствия формулам Excel (требуется рефакторинг) - PullRequest
0 голосов
/ 16 ноября 2009

Я написал два простых вычисления для Ruby, которые соответствуют способу, которым Microsoft 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

Ответы [ 2 ]

4 голосов
/ 17 ноября 2009

Я начну с небольшого обобщения и предоставлю один метод для обработки обоих случаев.

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}. Всё остальное гарантирую провал.

Обновление:

Формула, которую я использовал, прямо не приводится на цитируемом мной веб-сайте, но это абстракция для метода Фрейнда и Перлеса для расчета квартильной позиции.

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

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

2 голосов
/ 17 ноября 2009

Некоторые могут не согласиться с рефакторингом, но вот как я бы с этим справился:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...