Ruby数组到直方图。如何按范围分组数字?

时间:2016-11-13 00:53:58

标签: ruby

我需要将数组值分组为ruby中的基于范围的直方图......

values = [ 139, 145, 149, 151, 152, 153, 163, 166, 169 ]

例如:

141 - 145 = 2
146 - 150 = 1
151 - 155 = 3

...

是否有一种简单的方法可以使用group_by

2 个答案:

答案 0 :(得分:3)

由于您正在处理每个范围的简单定义,因此是:

values.group_by do |v|
  (v-1) / 5
end.values
# => [[139], [145, 149], [151, 152, 153], [163], [166, 169]]

通常group_by也包含分组元素,但这可以忽略,因为在这种情况下它没用。

您可以使用Ranges将其转换为您正在寻找的形式:

values.group_by do |v|
  (v-1) / 5
end.map do |v, a|
  [ (v*5+1..v*5+5), a.length ]
end.to_h
# => {136..140=>1, 141..145=>1, 146..150=>1, 151..155=>3, 161..165=>1, 166..170=>2}

答案 1 :(得分:0)

要准备直方图,通常会指定第一个范围的最小值,范围大小和范围数。可能需要对数据进行一些预处理以确定这些值。例如,给定

values = [139, 145, 149, 151, 152, 153, 164, 166, 169]
group_size = 5

我们可以按如下方式计算第一组的最小值和组数:

smallest, largest = values.minmax
  #=> [139, 169] 
start = group_size*(smallest/group_size)
  #=> 135 
nbr_groups = ((largest-start+1)/group_size.to_f).ceil
  #=> 7 

我们现在可以构造一个可用于创建直方图的数组。

def group_values(values, start, nbr_groups, group_size)
  groups = Array.new(nbr_groups) do |i|
    f = start + i * group_size
    { nbr: 0, range: f..f+group_size-1 }
  end    
  values.each_with_object(groups) { |v,arr|
    arr[(v-start)/group_size][:nbr] += 1 }
end

让我们尝试一下(针对上面计算的startnbr_groups的值)。

freq = group_values(values, start, nbr_groups, group_size)
  #=> group_values(values, 135, 7, 5)
  #=> [{:nbr=>1, :range=>135..139},
  #    {:nbr=>0, :range=>140..144},
  #    {:nbr=>2, :range=>145..149},
  #    {:nbr=>3, :range=>150..154},
  #    {:nbr=>0, :range=>155..159},
  #    {:nbr=>1, :range=>160..164},
  #    {:nbr=>2, :range=>165..169}]

请注意

  • 为结果数组的每个元素提供:range的值,用于标记直方图的水平轴。
  • 我初始化了数组groups,以便不包含values元素(对于值140-144155-159)的组将包含在返回的数组中。如果我在飞行中构造了那个数组,它就不会包含这两个组的哈希值。
  • 建立直方图垂直轴的频率范围,我们可以计算以下内容。

freq.map { |h| h[:nbr] }.minmax
  #=> [0, 3]