将流划分为具有相同计数的区间

时间:2016-12-15 05:41:12

标签: python algorithm numpy stream numerical-methods

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

  1. 输入是来自硬盘的流x[t]。数字流包含N个元素。
  2. 可能会有xm个柱子的直方图。
  3. n个bin由bin边缘e 0 &lt; e 1 ,...,&lt; Ë<子>米。例如,如果e i =&lt; x [0]&lt; e i + 1 ,然后x [0]属于i th bin。
  4. 找到bin边缘,使bin保持流中的元素数量几乎相等。理想情况下,每个bin中的元素数量应该在N/m的某个阈值百分比内。这是因为如果我们在m个bin中均匀分布N个元素,则每个bin应该包含大约N/m个元素。
  5. 目前的解决方案:

    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%。

2 个答案:

答案 0 :(得分:1)

Iff 您可以假设您的数据是随机的定义的分布(即:按顺序获取任何非平凡的数据百分比将“草图”与整个数据相同的分布,只有更粗略的精度),我想有很多选择:

  1. 在一些过采样直方图中读取部分数据。在此基础上,选择bin边缘的近似你现在的方式(如你的问题中所解释的),然后统一对这些bin进行过采样,然后将另一块数据读入新的bin中,等等上。如果您有足够的数据,那么以10%10%的块处理它们将允许10次迭代,以便在一次通过中改善您的箱结构。

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

  3. 当然,以上只是方法的想法,不能保证它们的工作状态。

答案 1 :(得分:1)

假设分布不是非常歪斜(例如在1.0000001和1.0000002之间的10000个值以及在9.0000001和9.0000002之间的10000个其他值),您可以按照以下步骤进行操作。

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

然后计算累积直方图,当你去的时候,确定m+1分位数边缘(累积计数交叉为N/m的倍数)。

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

对于N个元素,使用K个二进制位的直方图并假设一些&#34;非均匀性因子&#34; (等于合理分布的几个单位),最大误差为f.N/K

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

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