Method: Rust::Descriptive.quantile

Defined in:
lib/rust/stats/descriptive.rb

.quantile(data, percentiles = [0.0, 0.25, 0.5, 0.75, 1.0]) ⇒ Object

Raises:

  • (TypeError)


48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/rust/stats/descriptive.rb', line 48

def quantile(data, percentiles = [0.0, 0.25, 0.5, 0.75, 1.0])
    raise TypeError, "Expecting Array of numerics" if !data.is_a?(Array) || !data.all? { |e| e.is_a?(Numeric) }
    raise TypeError, "Expecting Array of numerics" if !percentiles.is_a?(Array) || !percentiles.all? { |e| e.is_a?(Numeric) }
    raise "Percentiles outside the range: #{percentiles}" if percentiles.any? { |e| !e.between?(0, 1) }
    
    n = data.size
    quantiles = percentiles.size
    percentiles = percentiles.map { |x| x > 1.0 ? 1.0 : (x < 0.0 ? 0.0 : x) }
    
    rough_indices = percentiles.map { |x| 1 + [n - 1, 0].max * x - 1 }
    floor_indices = rough_indices.map { |i| i.floor }
    ceil_indices = rough_indices.map { |i| i.ceil }
    
    data = data.sort
    result = floor_indices.map { |i| data[i] }
    result_ceil = ceil_indices.map { |i| data[i] }
    
    indices_to_fix = (0...quantiles).select { |i| rough_indices[i] > floor_indices[i] && result_ceil[i] != result[i] }
    index_approximation_errors = indices_to_fix.map { |i| rough_indices[i] - floor_indices[i] }
    reduced_index_approximation_errors = index_approximation_errors.map { |i| (1 - i) }
    hi_indices = indices_to_fix.map { |i| ceil_indices[i] }
    data_hi_indices = hi_indices.map { |i| data[i] }
    
    j = 0
    indices_to_fix.each do |i|
        result[i] = reduced_index_approximation_errors[j] * result[i] + index_approximation_errors[j] * data_hi_indices[j]
        j += 1
    end
    
    return percentiles.zip(result).to_h
end