JavaScript中的简单直方图算法

6tr1vspr  于 2023-04-28  发布在  Java
关注(0)|答案(4)|浏览(143)

我正在创建一个直方图算法。我在下面提供的解决方案here
我想简单地计算每个值出现的次数。
然而,我不能完全得到正确的算法。我的代码是:

var values = [2, 4, 6, 3, 3];

var val_max = 6;
var val_min = 2;

var num_bins = parseInt(val_max - val_min + 1);
console.log('num_bins is ', num_bins);

var bin_width = (val_max-val_min)/num_bins;
console.log('bin_width is ', bin_width);

var to_plot = [];

for (var i = 0; i < num_bins; i++) {
  to_plot.push(0);
}

for (var x = 0; x < values.length; x++) {

    var bin_idx = parseInt((values[x] - val_min) / bin_width); 

    to_plot[bin_idx] = to_plot[bin_idx] + 1; 
}

console.log('to_plot is ', to_plot);

如果查看控制台日志,您将看到:

to_plot is  [1, 2, 1, 0, 0, NaN]

我希望最后一个索引为“1”。但问题是,对于接近最大值的值,bin_idx超出范围。我该如何调整它,以获得以下结果?

to_plot is  [1, 2, 1, 0, 1]

jsfiddle是here

ghhkc1vu

ghhkc1vu1#

我会这么做

const data = [2, 4, 6, 3, 3];

print(histogram(data, 1)); // [1, 2, 1, 0, 1]
print(histogram(data, 2)); // [3, 1, 1]
print(histogram(data, 3)); // [4, 1]
print(histogram(data, 4)); // [4, 1]
print(histogram(data, 5)); // [5]

function histogram(data, size) {
    let min = Infinity;
    let max = -Infinity;

    for (const item of data) {
        if (item < min) min = item;
        else if (item > max) max = item;
    }

    const bins = Math.ceil((max - min + 1) / size);

    const histogram = new Array(bins).fill(0);

    for (const item of data) {
        histogram[Math.floor((item - min) / size)]++;
    }

    return histogram;
}

function print(x) {
    console.log(JSON.stringify(x));
}

这也适用于非整数值。

agyaoht7

agyaoht72#

我觉得你的bin_width是错的。尝试以下计算:

var bin_width = (val_max - val_min) / (num_bins - 1);

这就形成了bin_width == 1,它可以让你的其余代码工作。

2hh7jdfx

2hh7jdfx3#

由于bin的数量等于val_minval_max之间的整数的数量,因此bin_width是1,而不是0。8目前正在计算中。你基本上是在计算整数。使用此循环生成直方图:

for (var x = 0; x < values.length; x++) {
    to_plot[values[x] - val_min] ++;
}
uajslkp6

uajslkp64#

对于那些对直方图输出感兴趣而不是对实现感兴趣的人,d3-array库提供了一个bin()方法,用于构建直方图。
下面是在bin()之上的一个用Typescript编写的精简 Package 器,它添加了一些特性并提供了类似于Python's numpy.histogram的输出。

/**
 * Computes histogram of an array of numbers.
 *
 * @remarks
 * Requires library d3-array.
 *
 * @param arr - The input array of numbers.
 * @param nBins - Optional number of bins desired. Auto if not passed.
 * @param domain - Optional minimum and maximum bin edge values.
 * @param clamp - Whether to clamp values in arr to the domain.
 *    Only relevant if domain is passed. If clamp is false (default),
 *    data outside the domain will be lost. If clamp is true, the data will
 *    be kept in the first or last bin.
 * @returns An object with keys hist, containing the count of values in
 *    each bin, and binEdges, containing the edges of each bin.
 */
export const computeHistogram = (
  arr: number[],
  nBins?: number,
  domain?: [number, number],
  clamp: boolean = false
) => {
  if (domain && clamp) {
    const [domainMin, domainMax] = domain;
    arr.forEach((val, i, arr) => {
      arr[i] = Math.min(Math.max(val, domainMin), domainMax);
    });
  }
  let bins = d3Array.bin();
  if (domain) bins = bins.domain(domain);
  if (nBins) bins = bins.thresholds(nBins);
  const d3Hist = bins(arr);
  const hist: number[] = d3Hist.map((item) => item.length);
  const binEdges = d3Hist.map((item) => item.x0);
  if (d3Hist.length) binEdges.push(d3Hist.at(-1)!.x1);

  return { hist, binEdges };
};

相关问题