如何在SQL中创建对数直方图?

时间:2015-08-03 22:57:09

标签: sql histogram logarithm

我的表:

val
1
2
3
4
5
6
10
15

期望的结果:

bin | qty 
1   | 1
2   | 2
4   | 3
8   | 3

这意味着有包容性/排他性范围

  • 1-2之间的值,
  • 2-4之间的值,
  • 4-8之间的3个值,
  • 3-16之间的值。

1 个答案:

答案 0 :(得分:4)

在这种情况下,您的垃圾箱尺寸以对数字表示,为2。

如果您想使用其他纸盒尺寸,请在下面的脚本中替换2s。

select 
    pow(2, floor(ln(val) / ln(2))) as bin,
    count(bin) as qty
from 
    mytable
group by
    bin;

说明

首先,我们在基数2中记录您的值。log(val, 2)可能在某些RDBMS中有效,但如果没有,只需记住log(val, 2) = ln(val) / ln(2)的日志属性。

val | ln(val) / ln(2)
1   | 0
2   | 1
3   | 1.58496250072
4   | 2
5   | 2.32192809489

然后我们这样做:

val | floor(ln(val) / ln(2))
1   | 0
2   | 1
3   | 1
4   | 2
5   | 2

最后,我们使用2的幂来将这些被覆盖的值转换为对数bin值。

val | pow(2, floor(ln(val) / ln(2)))
1   | 1
2   | 2
3   | 2
4   | 4
5   | 4

其余的只是按对数箱分组并计数。

注意事项

没有战俘

如果您的RDBMS不支持pow(x, y),则可以使用exp(y * ln(x))。然后表达式变为:

    exp(floor(ln(val) / ln(2)) * ln(2))

log(0)未定义。在我测试的RDBMS中,它返回null。

如果你的表的值为0,你很可能想要将它们在0和1之间加之。为此,你可以用ifnull(...,0)包装整个表达式,如下所示:

    ifnull(pow(2, floor(ln(val) / ln(2))), 0)

否定

负数的对数是未定义的......但你可能想要将它们分类为[0到-1),[ - 1到-2],[ - 2到-4],[ - 4到-8 )等等。

如果您的数据库具有负值,则可以首先在值中使用abs,然后通过将结果乘以val/abs(val)来恢复原始信号,从而实现该分箱。然后你的表达成为:

pow(2, floor(ln(abs(val)) / ln(2))) * val/abs(val)

负数和零

如果您的数据库同时包含负值和零值,则应将ifnull包装在其他所有内容中。否则,val/abs(val)部分将使您除以零,重新引入空值。

ifnull(pow(2, floor(ln(abs(val)) / ln(2))) * val/abs(val), 0)