如何使用Apache Math 3.0在Java中生成直方图的区间?

12

我一直在寻找一种使用Apache Common Math 3.0生成特定数据集的区间(通过指定下限、上限和所需区间数)的方法。我查看了Frequency http://commons.apache.org/math/apidocs/org/apache/commons/math3/stat/Frequency.html,但它并不能给我想要的结果...我想要一个能够给出某个区间内值的频率的方法(例如:0到5之间有多少个值)。有什么建议或想法吗?


你是否受限于Apache?这听起来正是Guava的使用案例,SortedMultiset - Louis Wasserman
@Louis Wasserman 是的,我受限于使用 Apache math 3.0,因为它提供了其他拟合和插值功能。 - Sami
如果您正在使用更新版本的Java,您可以使用Java Streams API来完成此操作。请参见下面的答案 - ATutorMe
5个回答

17

以下是使用 Apache Commons Math 3 实现直方图的简单方法:

final int BIN_COUNT = 20;
double[] data = {1.2, 0.2, 0.333, 1.4, 1.5, 1.2, 1.3, 10.4, 1, 2.0}; 

long[] histogram = new long[BIN_COUNT];
org.apache.commons.math3.random.EmpiricalDistribution distribution = new org.apache.commons.math3.random.EmpiricalDistribution(BIN_COUNT);
distribution.load(data);
int k = 0;
for(org.apache.commons.math3.stat.descriptive.SummaryStatistics stats: distribution.getBinStats())
{
    histogram[k++] = stats.getN();
}

3
从EmpiricalDistribution#getUpperBounds也可以获得区间边界。 - Till Schäfer
Commons Math 提供了一个函数,根据你要分成的组的数量来推荐一个“好”的箱子数量吗? - L. Blanc
使用说明: binCount 默认设置为 1000。一个好的经验法则是将 bin 计数设置为输入文件长度除以 10 左右。 输入文件必须是包含每行一个有效数字条目的纯文本文件。参见 https://commons.apache.org/proper/commons-math/javadocs/api-3.6/org/apache/commons/math3/random/EmpiricalDistribution.html - greg

8
据我所知,Apache Commons 中目前没有好的直方图类。我最终自己编写了一个。如果你只需要从最小到最大线性分布的箱子,那么编写起来非常容易。
可能就像这样:
public static int[] calcHistogram(double[] data, double min, double max, int numBins) {
  final int[] result = new int[numBins];
  final double binSize = (max - min)/numBins;

  for (double d : data) {
    int bin = (int) ((d - min) / binSize);
    if (bin < 0) { /* this data is smaller than min */ }
    else if (bin >= numBins) { /* this data point is bigger than max */ }
    else {
      result[bin] += 1;
    }
  }
  return result;
}

编辑: 这里有一个例子。

double[] data = { 2, 4, 6, 7, 8, 9 };
int[] histogram = calcHistogram(data, 0, 10, 4);
// This is a histogram with 4 bins, 0-2.5, 2.5-5, 5-7.5, 7.5-10.
assert histogram[0] == 1; // one point (2) in range 0-2.5
assert histogram[1] == 1; // one point (4) in range 2.5-5.
// etc..

但是如何获取每个数据段的频率呢?我在Apache Math 3.0中没有找到任何可以实现该功能的类或方法。 - Sami
每个箱子的频率是多少?result[i]告诉你第i个箱子中有多少数据点。如果你想要频率(比例),只需执行result[i] / data.length... - Max
Max,我认为你的代码有一个小错误...请看我下面发布的更正。谢谢。 - user1172468
我怎样能够获取区间的数组?你能帮忙吗? - Shrey
频率数组 - Shrey

1

我认为你的代码有一个错误,请参见下面更正后的代码:

public static int[] calcHistogram(double[] data, double min, double max, int numBins) {
  final int[] result = new int[numBins];
  final double binSize = (max - min)/numBins;

  for (double d : data) {
    int bin = (int) ((d - min) / binSize); // changed this from numBins
    if (bin < 0) { /* this data is smaller than min */ }
    else if (bin >= numBins) { /* this data point is bigger than max */ }
    else {
      result[bin] += 1;
    }
  }
  return result;
}

9
这应该是对 Max 回答的编辑,而不是一个独立的答案。 - nessa.gp

0
这是一个基于Java流的实现相同功能的例子。
使用了一些有用的范围、过滤和计数函数。
public static Long[] calcHistogram(Double[] data, Double min, Double max, Integer numBins) {
  final var interval = (max - min) / numBins;

  return IntStream.range(0, numBins)
      .boxed()
      .map(n -> {
        var binStart = min + n * interval;
        var binEnd = min + (n + 1) * interval;
        return Arrays.stream(data).filter(d -> d >= binStart && d < binEnd).count();
      })
      .toArray(Long[]::new);
}

0
这是对@Altair7852答案的补充。
如果您想为y值(每个bin中的频率..也称为histogram[]在索引i处)生成x值bin interval,这里是完整的方法。
    private fun displayHistogram(binCount: Int, data: DoubleArray) {
        val histogram = DoubleArray(binCount)
        val distribution = org.apache.commons.math3.random.EmpiricalDistribution(binCount)
        distribution.load(data)

        var k = 0
        for (stats in distribution.binStats) {
            histogram[k++] = stats.n.toDouble()
        }

        val binSize = (data.max()!!.toDouble() - data.min()!!.toDouble()) / binCount

        for (i in 0 until histogram.size) {
            series2?.appendData(DataPoint(generateHistogramXValues(data.min()!!.toDouble(), histogram.size, binSize)[i], histogram[i]), false, histogram.count())
        }
    }

这是生成x值的方法

        val xValuesArray = DoubleArray(numberOfBIns)
        for (i in 0 until numberOfBIns) {
            if (i == 0){
                xValuesArray[i] = min
            }else{
                val previous = xValuesArray[i-1]
                xValuesArray[i] = previous+binSize
            }
        }
        return xValuesArray
    }

我正在使用 GraphView 绘图库在 Android 上进行此操作,但您可以在任何库上使用它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接