合并具有不同范围的直方图

时间:2017-11-02 22:33:44

标签: python numpy merge histogram

将两个numpy直方图与不同的bin范围和bin编号合并是否是快速的方法?

例如:

x = [1,2,2,3]
y = [4,5,5,6]

a = np.histogram(x, bins=10)  
#  a[0] = [1, 0, 0, 0, 0, 2, 0, 0, 0, 1]
#  a[1] = [ 1. ,  1.2,  1.4,  1.6,  1.8,  2. ,  2.2,  2.4,  2.6,  2.8,  3. ]

b = np.histogram(y, bins=5)
#  b[0] = [1, 0, 2, 0, 1]
#  b[1] = [ 4. ,  4.4,  4.8,  5.2,  5.6,  6. ]

现在我希望有这样的功能:

def merge(a, b):
    # some actions here #
    return merged_a_b_values, merged_a_b_bins

实际上我没有xyab只是已知的。 但merge(a, b)的结果必须等于np.histogram(x+y, bins=10)

m = merge(a, b)
#  m[0] = [1, 0, 2, 0, 1, 0, 1, 0, 2, 1]
#  m[1] = [ 1. ,  1.5,  2. ,  2.5,  3. ,  3.5,  4. ,  4.5,  5. ,  5.5,  6. ] 

2 个答案:

答案 0 :(得分:2)

我实际上已经在dangom的答案中添加了评论,但我缺乏所需的声誉。 你的榜样让我有些困惑。如果我没记错的话,您正在绘制直方图箱的直方图。应该是这样吧?

plt.figure()
plt.plot(a[1][:-1], a[0], marker='.', label='a')
plt.plot(b[1][:-1], b[0], marker='.', label='b')
plt.plot(c[1][:-1], c[0], marker='.', label='c')
plt.legend()
plt.show()

也请注意您建议的组合直方图。您当然是对的,因为您根本不知道,没有独特的解决方案,样本将在您用于组合的更精细网格中的位置。当两个直方图的仓宽明显不同时,建议的合并功能可能会导致稀疏且看起来很虚构的直方图。

我尝试通过插值法组合直方图(假设计数仓中的样本均匀分布在原始仓中,这当然只是一个假设)。 但是,这至少在从我通常遇到的分布中采样的数据中得出了更自然的结果。

import numpy as np
def merge_hist(a, b):

    edgesa = a[1]
    edgesb = b[1]
    da = edgesa[1]-edgesa[0]
    db = edgesb[1]-edgesb[0]
    dint = np.min([da, db])

    min = np.min(np.hstack([edgesa, edgesb]))
    max = np.max(np.hstack([edgesa, edgesb]))
    edgesc = np.arange(min, max, dint)

    def interpolate_hist(edgesint, edges, hist):
        cumhist = np.hstack([0, np.cumsum(hist)])
        cumhistint = np.interp(edgesint, edges, cumhist)
        histint = np.diff(cumhistint)
        return histint

    histaint = interpolate_hist(edgesc, edgesa, a[0])
    histbint = interpolate_hist(edgesc, edgesb, b[0])

    c = histaint + histbint
    return c, edgesc

两个高斯分布的示例:

import numpy as np
a = 5 + 1*np.random.randn(100)
b = 10 + 2*np.random.randn(100)
hista, edgesa = np.histogram(a, bins=10)
histb, edgesb = np.histogram(b, bins=5)

histc, edgesc = merge_hist([hista, edgesa], [histb, edgesb])

plt.figure()
width = edgesa[1]-edgesa[0]
plt.bar(edgesa[:-1], hista, width=width)
width = edgesb[1]-edgesb[0]
plt.bar(edgesb[:-1], histb, width=width)
plt.figure()
width = edgesc[1]-edgesc[0]
plt.bar(edgesc[:-1], histc, width=width)

plt.show()

但是我不是统计学家,所以请告诉我建议的方法是否可行。

答案 1 :(得分:1)

合并两个不同的直方图的问题没有独特的解决方案。我在此提出一个简单快速的解决方案,基于两个设计假设来处理分箱序列固有的信息丢失:

  1. 恢复的值由它们所属的bin的开头表示。

  2. 合并应保持最高的bin分辨率,以避免进一步丢失信息,并完全包含子直方图的间隔。

  3. 以下是代码:

      import numpy as np
    
      def merge(a, b):
    
          def extract_vals(hist):
              # Recover values based on assumption 1.
              values = [[y]*x for x, y in zip(hist[0], hist[1])]
              # Return flattened list.
              return [z for s in values for z in s]
    
          def extract_bin_resolution(hist):
              return hist[1][1] - hist[1][0]
    
          def generate_num_bins(minval, maxval, bin_resolution):
              # Generate number of bins necessary to satisfy assumption 2
              return int(np.ceil((maxval - minval) / bin_resolution))
    
          vals = extract_vals(a) + extract_vals(b)
          bin_resolution = min(map(extract_bin_resolution, [a, b]))
          num_bins = generate_num_bins(min(vals), max(vals), bin_resolution)
    
          return np.histogram(vals, bins=num_bins)
    

    以下是示例代码:

    import matplotlib.pyplot as plt
    
    x = [1,2,2,3]
    y = [4,5,5,6]
    
    a = np.histogram(x, bins=10)  
    #  a[0] = [1, 0, 0, 0, 0, 2, 0, 0, 0, 1]
    #  a[1] = [ 1. ,  1.2,  1.4,  1.6,  1.8,  2. ,  2.2,  2.4,  2.6,  2.8,  3. ]
    
    b = np.histogram(y, bins=5)
    #  b[0] = [1, 0, 2, 0, 1]
    #  b[1] = [ 4. ,  4.4,  4.8,  5.2,  5.6,  6. ]
    
    # Merge and plot results
    c = merge(a, b)
    
    c_num_bins = c[1].size - 1
    
    plt.hist(a[0], bins=5, label='a')
    plt.hist(b[0], bins=10, label='b')
    plt.hist(c[0], bins=c_num_bins, label='c')
    plt.legend()
    
    plt.show()