【发布时间】:2014-09-21 18:23:08
【问题描述】:
在 MySQL 数据库中,有一个带有单个数字 value 列的表。我想将这些值的分布绘制为具有以下要求的条形图/直方图:
- 图表中最多应有 N 个柱(区间)
- 每个条形的宽度(x 轴范围)应一致,每个条形的高度应反映此区间中值的数量。
- 条形的端点应以整数出现。我知道这是一个相当模糊的要求,但希望以下示例能够说明我的意思
- 间隔应该是连续的,例如下一个间隔应该从前一个结束的地方开始
- 理想情况下,应该可以通过单个查询检索数据
- 间隔计数(y 轴值)为 0 是可以的
- 如果第一个区间的下限小于最小值
value和/或最后一个区间的上限大于最大值value,则可以
示例
如果 N = 3 并且表包含以下数据
+------------+
| value |
+------------+
| -49.2 |
| -28.2 |
| 13.3 |
| 23.3 |
| 51.4 |
| 77.9 |
+------------+
检查时很容易看出间隔{-50..0, 0..50, 50..100} 满足此数据集和 N 值的要求。
但是,我正在努力想出一个适用于任何 N 值和任何数据集的通用解决方案。到目前为止,这是我尝试过的:
计算间隔宽度
通过以下查询获取最大和最小value
SELECT min(value), max(value), count(*) FROM my_table
然后将结果传递给这个(Groovy/Java)方法来计算每个区间的宽度
// intervalCount is what I've referred to as "N"
static Integer getRoundedIntervalSize(Double min, Double max, Integer intervalCount) {
Number intervalSize = Math.ceil((max - min) / intervalCount)
Integer roundingScale = Math.log10(intervalSize) - 1
Number roundNearest = 10 ** roundingScale
// round up the interval size to the nearest roundNearest
Number intervalDelta = roundNearest - (intervalSize % roundNearest)
intervalSize + intervalDelta
}
获取频率分布
然后我使用以下查询(将getRoundedIntervalSize 返回的值替换为:groupSize)来获取每个区间中的值的数量
SELECT floor(value / :groupSize) * :groupSize as groupLowerLimit,
count(*) as groupCount
FROM my_table
GROUP BY groupLowerLimit
ORDER BY groupLowerLimit ASC
这将返回每个区间的下限和每个区间中的值的数量,这就是我构建频率分布所需的全部内容。
不足之处
虽然这种方法在数据集分布相对均匀时效果很好,但如果不是这种情况,它会导致间隔具有不同的宽度或不连续。此外,当数据集的范围较小(例如,1 到 4 之间的所有值)且 N 较大(例如 30)时,生成的区间数往往远小于 N。
有没有更好的方法来解决这个问题,满足上述要求?
【问题讨论】:
-
+1 提出了这个非常罕见的事情:Stack Overflow 上的一个好问题。我希望我能回答它:(
-
@MikeW 我希望你也可以 :) 我开始怀疑这是否更像是一个统计/数学问题而不是编程问题
标签: java sql groovy language-agnostic histogram