如何在 SQL 中制作对数直方图?

How do I make a logarithmic histogram in SQL?

我的table:

val
1
2
3
4
5
6
10
15

想要的结果:

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

这意味着有 inclusive/exclusive 个范围,

在这种情况下,您的 bin 大小(以对数表示)为 2。

如果您想使用其他 bin 大小,请替换下面脚本中的 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 中,它 returns null.

如果您的 table 的值为 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)