【问题标题】:Creating a Python Histogram without Pylab在没有 Pylab 的情况下创建 Python 直方图
【发布时间】:2014-03-04 08:51:18
【问题描述】:

我必须生成一个具有高斯分布的随机数列表(我能够做到这一点),然后将这些数字绘制在直方图中。我的问题是我应该在不使用 pylab (或任何其他包)中的内置直方图函数的情况下执行此操作,而我完全不知所措。我一直在网上寻找,我还没有找到任何可以解释我将如何解决这个问题的东西,你们中有人知道我能做什么吗?提前致谢。

【问题讨论】:

标签: python matplotlib histogram gaussian


【解决方案1】:

计算直方图的一种快速方法是一次遍历列表中的一个元素,找出它应该在哪个 bin 中,然后计算每个 bin 中的条目数。

hist_vals = np.zeros(nbins)
for d in data:
    bin_number = int(nbins * ((d - min_val) / (max_val - min_val)))
    hist_vals[bin_number] += 1

请注意,这具有 O(len(data)) 和一个小的前置因子。

一个更聪明的写法是向量化散列函数:

bin_number = (nbins * ((data - min_val) / (max_val - min_val))).astype(np.int)

并使用切片魔法进行求和:

hist_vals[bin_number] += 1  # numpy slicing magic

如果你关心速度,你可以使用 numpy 函数,它本质上是这样做的,但将循环放在 c 级别:

bin_nums = np.digitize(data, bins) - 1
hist_vals = np.bincount(bin_nums)

【讨论】:

  • 如果您的数据集很小,这可能会起作用。如果您处理的是大样本 (N>1e6),我提出的解决方案可以更好地扩展。
  • @Matteo 你真的在板凳上做了标记吗?这应该可以更好地扩展,但由于在 python 中而不是 c 中执行循环可能会更慢(c 中的错误算法可能比 python 中的正确算法更快)。
  • 我习惯于处理大量数据(N>1e8),我可以告诉你,如果我使用我建议的代码,我只需要等待几分钟(最多) 得到答案。您的方法虽然对于小型数据集或当 bin 数量很大时肯定是聪明且有用的,但可能需要长达几天的时间。
  • 我只是在 1e8 个数据点上运行它,纯 python 版本大约需要一分钟,np.bincount(np.digitize(np.random.rand(1e8), np.linspace(0, 1, 100, endpoint=True), right=True) - 1) 需要
  • @tcaswell:不知hist_vals = np.zeros(nbins)要不要改成hist_vals = np.zeros(nbins+1)
【解决方案2】:

这是一个基于 @tacaswell 的解决方案但不使用 numpy 的版本。

def histogram(data, nbins, min_val=None, max_val=None):
    hist_vals = [0]*(nbins+1)
    if min_val is None:
        min_val = min(data)
    if max_val is None:
        max_val = max(data)

    for d in data:
        bin_number = int(nbins * ((d - min_val) / (max_val - min_val)))
        hist_vals[bin_number] += 1
    bin_lower_bounds = [min_val + i*(max_val - min_val)/len(hist_vals) for i in range(len(hist_vals))]
    return hist_vals, bin_lower_bounds

【讨论】:

    【解决方案3】:

    假设您有一个代表随机数的numpy 数组

            rnd_numb=array([ 0.48942231,  0.48536864,  0.48614467, ...,  0.47264172,
        0.48309697,  0.48439782])
    

    要创建直方图,您只需对数据进行分箱。所以让我们创建一个定义分箱的数组

           bin_array=linspace(0,1,100)
    

    在这种情况下,我们将创建 100 个线性间隔的 bin,范围为 0 到 1

    现在,为了创建直方图,您可以简单地做

      my_histogram=[]
      for i in range(len(bin_array)-1):
         mask = (rnd_numb>=bin_array[i])&(rnd_numb<bin_array[i+1])
         my_histogram.append(len(rnd_numb[mask]))
    

    这将创建一个列表,其中包含每个 bin 中的计数。最后,如果你想可视化你的直方图,你可以这样做

     plot ((bin_array[1:]+bin_array[:-1])/2.,my_histrogram)
    

    您也可以试试stepbar

    【讨论】:

    • 这对我来说非常有效。感谢您的帮助!
    • 当您触摸数据数组的每个元素 很多 次 (> nbins * 2) 时,这将非常糟糕。您可以在一次遍历数据中计算直方图
    猜你喜欢
    • 1970-01-01
    • 2013-06-25
    • 2012-07-25
    • 2021-03-30
    • 1970-01-01
    • 1970-01-01
    • 2016-01-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多