2009-11-16 4 views
0

J'ai écrit deux calculs simples avec Ruby qui correspondent à la façon dont Microsoft Excel calcule les quartiles supérieur et inférieur pour un ensemble donné de données - ce qui n'est pas la même que la méthode généralement acceptée (surprise).calculs percentile rubis pour faire correspondre les formules Excel (refactor besoin)

Ma question est - combien et comment ces méthodes peuvent-elles être refactorisées pour une DRYness maximale?

 
# 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

Comme Ian le souligne ci-dessous, cette première instruction if devrait être 'return trié [u.truncate-1] si (u-u.truncate) .zero?' – Dave

Répondre

2

Certains pourraient être en désaccord sur le refactoring, mais voici comment je débrouille:

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

Je vais commencer par un peu généralisant et de fournir une méthode pour gérer les deux cas.

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 

alors vous pouvez faire des méthodes pratiques de:

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

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

Note: la méthode excel_quartile correspond aux attentes pour quartile in { 1, 2, 3, 4}. Rien d'autre, je garantis l'échec.

Mise à jour:

La formule je n'est pas expressément donnée sur le site que je citais, mais il est l'abstraction pour la méthode Freund et PERLES de calculer la position de quartile.

nouvelle mise à jour:

Il y a une erreur dans votre code d'origine, bien que vous ne devriez jamais il: u - u.trunc est toujours dans l'intervalle [0.0, 1.0), donc la seule fois où il ressemblerait un entier est quand u - u.trunc = 0. Cependant, (u - u.trunc) est toujours une instance d'un Float lorsque u est un Float, donc votre code ne se produit jamais sur l'index mal calculé. Incidemment, si u - u.trunc était un entier, votre méthode retournerait le dernier élément du tableau.

Questions connexes