我需要将数组值分组为ruby中的基于范围的直方图......
values = [ 139, 145, 149, 151, 152, 153, 163, 166, 169 ]
例如:
141 - 145 = 2
146 - 150 = 1
151 - 155 = 3
...
是否有一种简单的方法可以使用group_by
?
答案 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
让我们尝试一下(针对上面计算的start
和nbr_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-144
和155-159
)的组将包含在返回的数组中。如果我在飞行中构造了那个数组,它就不会包含这两个组的哈希值。
freq.map { |h| h[:nbr] }.minmax
#=> [0, 3]