【问题标题】:Divide a stream into bins with equal counts将流划分为具有相同计数的 bin
【发布时间】:2017-04-30 15:26:30
【问题描述】:

理想情况下,我希望以下内容不会从硬盘读取数据太多次。数据很大,内存无法同时保存所有数据。

  1. 输入是来自硬盘的流x[t]。数字流包含N 元素。
  2. x 的直方图可能带有m 分箱。
  3. n 个 bin 由 bin 边缘 e01, ..., m 定义。例如,如果 ei =i+1,则 x[0] 属于第 ith 个 bin .
  4. 找到使 bin 包含几乎相等数量的流中元素的 bin 边缘。理想情况下,每个 bin 中的元素数量应在N/m 的某个阈值百分比内。这是因为如果我们将N 元素平均分布在 m 个 bin 中,每个 bin 应该包含大约 N/m 元素。

目前的解决方案:

import numpy as np


def test_data(size):
    x = np.random.normal(0, 0.5, size // 2)
    x = np.hstack([x, np.random.normal(4, 1, size // 2)])
    return x


def bin_edge_as_index(n_bin, fine_hist, fine_n_bin, data_size):
    cum_sum = np.cumsum(fine_hist)
    bin_id = np.empty((n_bin + 1), dtype=int)

    count_per_bin = data_size * 1.0 / n_bin

    for i in range(1, n_bin):
        bin_id[i] = np.argmax(cum_sum > count_per_bin * i)

    bin_id[0] = 0
    bin_id[n_bin] = fine_n_bin
    return bin_id


def get_bin_count(bin_edge, data):
    n_bin = bin_edge.shape[0] - 1
    result = np.zeros((n_bin), dtype=int)
    for i in range(n_bin):
        cmp0 = (bin_edge[i] <= data)
        cmp1 = (data < bin_edge[i + 1])
        result[i] = np.sum(cmp0 & cmp1)
    return result


# Test Setting
test_size = 10000
n_bin = 6
fine_n_bin = 2000  # use a big number and hope it works

# Test Data
x = test_data(test_size)

# Fine Histogram
fine_hist, fine_bin_edge = np.histogram(x, fine_n_bin)

# Index of the bins of the fine histogram that contains
# the required bin edges (e_1, e_2, ... e_n)
bin_id = bin_edge_as_index(
    n_bin, fine_hist, fine_n_bin, test_size)

# Find the bin edges
bin_edge = fine_bin_edge[bin_id]
print("bin_edges:")
print(bin_edge)

# Check
bin_count = get_bin_count(bin_edge, x)
print("bin_counts:")
print(bin_count)
print("ideal count per bin:")
print(test_size * 1.0 / n_bin)

程序输出:

bin_edges:
[-1.86507282 -0.22751473  0.2085489   1.30798591  3.57180559  4.40218207
  7.41287669]
bin_counts:
[1656 1675 1668 1663 1660 1677]
ideal count per bin:
1666.6666666666667

问题:

我无法指定阈值 s,并且预计 bin 计数与每个 bin 的理想计数最多相差 s%。

【问题讨论】:

  • 你愿意接受多少差异?例如,所有的 bin 大小是否需要彼此相差 1,或 5,或 10,或 5%,还是什么?您不能简单地对数据进行排序吗?
  • 我想我很快就会睡着了...如果您的意思是对所有数据进行排序,我无法对数据进行排序,因为我猜这意味着从硬盘读取数据多次。而且硬盘速度非常慢。大多数情况下,我不喜欢我不能指定阈值 s 并且知道 bin_counts 最多与每个 bin 的理想计数不同。我想这样做是因为这意味着我以后可以控制错误。这些 bin 边缘的误差会成倍增加。
  • this answer的三篇被引论文。
  • @Adrian Colomitchi:该链接非常有帮助。谢谢。

标签: python algorithm numpy stream numerical-methods


【解决方案1】:

如果您可以假设您的数据是随机的,具有定义的分布(即:按顺序获取任何重要百分比的数据都将“草绘”与整个数据的分布相同,只是精度较低),我想有很多选择:

  1. 在一些过采样的直方图中读取部分数据。基于此,按照您现在的方式选择 bin 边缘的近似值(如您的问题中所述),然后均匀地对这些 bin 进行过采样,然后将另一块数据读入新的 bin 等等在。如果您有足够的数据,以 0f 10% 的块处理它们将允许 10 次迭代以单次改进您的 bin 结构。

  2. 从多个 bin 开始并累积一些(不是全部)数据。查看它们,如果一个 bin_width*count 不成比例地高于邻居(也许这就是精度/误差可能发挥作用的地方),将那个 bin 分成两部分,并启发式地将旧 bin 计数分配到新创建的 bin 中(一个可能的启发式 - 与邻居的数量成正比)。最后,您应该有一个由可接受的错误控制的部门,从中可以对您的分布进行插值。

当然,以上只是方法的想法,不能保证它们的效果。

【讨论】:

    【解决方案2】:

    假设分布没有严重偏斜(例如 1.0000001 和 1.0000002 之间的 10000 个值和 9.0000001 和 9.0000002 之间的 10000 个其他值),您可以按照以下步骤进行。

    计算具有足够分辨率的直方图,例如K bins,它涵盖了整个范围(希望事先知道)。这将对数据进行一次传递。

    然后计算累积直方图,并在进行过程中识别m+1 分位数边缘(其中累积计数与N/m 的倍数交叉)。

    您将获得的准确度取决于原始直方图 bin 中的最大元素数。

    对于N 元素,使用K 箱的直方图并假设一些“非均匀性因子”(为合理分布,等于几个单位),最大误差将为f.N/K


    如果您愿意,可以通过考虑 m+1 辅助直方图来提高准确性,该直方图仅累积落在全局直方图分位数箱中的值。然后您可以将分位数细化为这些辅助直方图的分辨率。

    这将花费您额外的通过,但错误将减少到f.N/(K.K'),仅使用K 然后m.K' 直方图空间,而不是K.K'

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-14
      • 2015-12-10
      • 1970-01-01
      • 2017-09-07
      • 2011-12-16
      相关资源
      最近更新 更多