【问题标题】:c++ histogram bin sortingc++直方图bin排序
【发布时间】:2023-03-08 16:44:01
【问题描述】:

我正在编写一个函数来克隆 Excel 中数据分析插件的直方图功能。基本上,提供了样本数据的输入,然后还提供了 bin 范围。 bin 范围必须单调增加,在我的情况下,需要具体为 [0 20 40 60 80 100]。如果样本大于下限(左边缘)且小于或等于上限(右边缘),Excell 会计算样本是否落入 bin 范围。

我在下面编写了 bin 排序算法,它为 data0 提供了不正确的输出(非常接近),但为 data1 和 data2 提供了正确的输出。在这种情况下,正确意味着该算法的输出与 Excell 生成的表中的输出完全匹配,其中样本数与 bin 相邻。任何帮助表示赞赏!

#include <iostream>

int main(int argc, char **agv)
{
    const int SAMPLE_COUNT      = 21;
    const int BIN_COUNT         = 6;
    int binranges[BIN_COUNT]    = {0, 20, 40, 60, 80, 100};
    int bins[BIN_COUNT]         = {0, 0, 0, 0, 0, 0};

    int data0[SAMPLE_COUNT] =  {4,82,49,17,89,73,93,86,74,36,74,55,81,61,88,94,72,65,35,25,79};
    // for data0 excell's bins read:
    // 0    0
    // 20   2
    // 40   3
    // 60   2
    // 80   7
    // 100  7
    //
    // instead output of bins is: 203277

    int data1[SAMPLE_COUNT] = {88,83,0,0,95,86,0,94,92,77,94,73,93,90,50,95,93,83,0,95,91};
    //for data1 excell and this algorithm both yield:
    // 0    4
    // 20   0
    // 40   0
    // 60   1
    // 80   2
    // 100  14  (correct)

    int data2[SAMPLE_COUNT] = {58,48,75,68,85,78,74,83,83,75,67,58,75,58,84,68,57,88,55,79,72};
    //for data2 excell and this algorithm both yield:
    // 0    0
    // 20   0
    // 40   0
    // 60   6
    // 80   10
    // 100  5   (correct)

    for (unsigned int binNum = 1; binNum < BIN_COUNT; ++binNum)
    {
        const int leftEdge = binranges[binNum - 1];
        const int rightEdge = binranges[binNum];

        for (unsigned int sampleNum = 0; sampleNum < SAMPLE_COUNT; ++sampleNum)
        {
            const int sample = data0[sampleNum];

            if (binNum == 1)
            {
                if (sample >= leftEdge && sample <= rightEdge)
                    bins[binNum - 1]++;
            }
            else if (sample > leftEdge && sample <= rightEdge)
            {
                bins[binNum]++;
            }
        }
    }

    for (int i = 0; i < BIN_COUNT; ++i)
        std::cout << bins[i] << " " << std::flush;

    std::cout << std::endl << std::endl;

    return 0;
}

【问题讨论】:

  • 在给出我的答案之前,有些东西让我逃脱了:如果您将 0(甚至是负值)作为输入值之一,excel 中会发生什么?它不应该适合您定义的任何垃圾箱。
  • 没关系,我认为您的评论给了我答案,请参阅我的更新。

标签: c++ histogram bin


【解决方案1】:

假设边总是按递增顺序排列,那么您只需要:

     unsigned int bin;
    for (unsigned int sampleNum = 0; sampleNum < SAMPLE_COUNT; ++sampleNum)
    {
           const int sample = data0[sampleNum];
           bin = BIN_COUNT;
           for (unsigned int binNum = 0; binNum < BIN_COUNT; ++binNum)  {
                 const int rightEdge = binranges[binNum];
                 if (sample <= rightEdge) {
                    bin = binNum;
                    break;
                }
           }
           bins[bin]++;
      }

虽然,要使此代码正常工作,您需要为等于或低于第一条边 (0) 的值再添加一个 bin。

合理的是,如果你有 n 个分隔符,那么你就有 n+1 个间隔。

【讨论】:

  • 这个产生的输出是 [2, 3, 2, 7, 7, 0] 但是excell给出[0 2 3 2 7 7]。稍后绘制图表时,这种差异可能会很大。我最初的尝试也得到了相同的结果,但 Excell 的做法不同
  • 如果提供了另一个样本数据集,比如 {87,92,86,57,96,60,0,96,93,55,68,77,85,77,77,93, 69,74,32,86,43},Excel 产生 [1 0 1 4 6 9] 而这产生 [1 1 4 6 9 0]?
  • 这是 O(n^2) 内部循环找到正确的 bin。但是鉴于 bin 宽度是恒定的,您可以将 bin=val % BIN_WIDTH 夹在 (0, BIN_COUNT-1) 上,这将是 O(n)。
  • 请注意,它不是O(n*n),因为我不会在输入值上循环。更准确地说是O(n*m),m 是箱的数量,因为它是一个常数,所以归结为O(n)。但是您是正确的,您的解决方案可能更快,因为 bin 计算是通过算术完成的。
  • @didierc 是的,确实,我在发帖后不久就意识到这不是真正的O(n^2) 并回来纠正它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-09
  • 2013-04-03
  • 2016-10-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多