【问题标题】:How can I make 2D histograms based on large data with matplolib?如何使用 matplotlib 基于大数据制作 2D 直方图?
【发布时间】:2018-03-02 18:28:39
【问题描述】:

我想做一个大型数据集的二维直方图。如果我一次打开所有数据,我会收到 MemoryError 消息。因此,我将数据细分为可以单独加载的较小块。问题是我可以为每个块制作一个 2D 直方图,但不能一次为整个数据集制作一个 2D 直方图,因为我不能一次全部加载。

让我们看一个玩具示例。在这里想象 x 和 y 是来自我的一个块的数据。在此示例中,“块”由一百万个数据点组成:

import numpy as np
import matplotlib.pyplot as plt

x=np.random.normal(-1,1,1000000)
y=np.random.normal(-1,1,1000000)

#CLASSIC WAY TO MAKE A 2D HISTOGRAM
plt.hist2d(x,y,bins=100)
plt.savefig("histo1.png",dpi=800)
plt.close()

#ALTERNATIVE WAY TO MAKE A 2D HISTOGRAM
arr, xedges, yedges=np.histogram2d(x,y,bins=100)
frame=[xedges[0], xedges[-1], yedges[0], yedges[-1]]
plt.imshow(np.rot90(arr), interpolation="none", extent=frame)
plt.savefig("histo2.png",dpi=800)
plt.close()

所以在这里我展示了两种不同的方法来制作完全相同的图像:经典方法是使用 matplotlib.pyplot.hist2d() 直接从数据中绘制直方图,另一种方法是首先从数据中创建密度矩阵(使用 numpy.histogram2d())然后使用 matplotlib.pyplot.imshow() 绘制它。

所有这些都可以正常工作,并且两种方法都会产生完全相同的图像。但现在我想为整个数据集制作直方图。我不能用经典的方式来做,因为加载 x=x_data_chunk1+x_data_chunk2+... 和 y=y_data_chunk1+y_data_chunk2+... 由于 RAM 内存过载是不可能的。但理论上,替代方法应该有效;我可以加载第一个块并提取 x 和 y,然后使用 numpy.histogram2d() 对其进行密度矩阵,存储它,删除 x 和 y 的数据并对下一个块执行相同的操作。最后,我们将为每个块创建一个密度矩阵,而无需同时加载其中的任何两个。密度矩阵不是问题,因为它们只是计算每个单元格中数据点数量的网格(它们占用的数据显然比实际数据少得多)。最后,我们将所有密度矩阵添加到一个中,并使用 matplotlib.pyplot.imshow() 绘制最终排列。

理论上这应该可行。所以我首先尝试了一个玩具示例,它使用两个数据块 (x1,y1) 和 (x2,y2) 来查看如果可以同时加载数据(只是看看它是否和以前一样在两种方式下都是相同的图像,即使在真实情况下由于MemoryError,用经典方式是不可能的)。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

#CHUNK OF DATA 1
x1=np.random.normal(-1,1,1000000)
y1=np.random.normal(-1,1,1000000)

#CHUNK OF DATA 2
x2=np.random.normal(-1,1,1000000)
y2=np.random.normal(-1,1,1000000)

#CLASSIC WAY
x=x1+x2
y=y1+y2
plt.hist2d(x,y,bins=100)
plt.savefig("histo1.png",dpi=800)
plt.close()

#ALTERNATIVE WAY
arr1, xedges1, yedges1=np.histogram2d(x1,y1,bins=100)
arr2, xedges2, yedges2=np.histogram2d(x2,y2,bins=100)
arr=arr1+arr2
frame=[min([xedges1[0],xedges2[0]]), max([xedges1[-1],xedges2[-1]]), min([yedges1[0],yedges2[0]]), max([yedges1[-1],yedges2[-1]])]
plt.imshow(np.rot90(arr), interpolation="none", extent=frame)
plt.savefig("histo2.png",dpi=800)
plt.close()

这样做我得到两个完全不同的图像。为什么会这样? 标题是我试图在这里解决的一个更一般的问题,但我真的很想知道如何解决这种特殊情况。

这里真正的问题是 如何制作 2D 直方图,将不同数据块的密度矩阵相加,并获得与对整个数据集使用 matplotlib.pyplot.hist2d() 相同的结果?

这个问题的标题没有足够的空间,我无法想象它的更简洁的版本,所以最后我决定提出一个更一般的问题并解释我的特殊情况。不便之处请见谅。

【问题讨论】:

  • 为什么要添加x1x2 - 你不想连接它们吗?即x = np.concatenate([x1,x2])y 也一样。如果这解决了问题,请告诉我,我可以制定答案。

标签: python numpy matplotlib


【解决方案1】:

我猜有两个问题。

首先是代码中的一个简单错误。 x=x1+x2 添加两个数组,但是您真正想要的是将一个附加到另一个。虽然这只是为了玩具示例,但在实际情况下应该无关紧要,但它会导致您看到不同的图像。

第二:当然,您需要为所有直方图使用相同的 bin。因此,如果您事先知道要使用的垃圾箱,例如因为已知最小和最大数据,所以这很容易。

import numpy as np
import matplotlib.pyplot as plt


#CHUNK OF DATA 1
x1=np.random.normal(-1,1,1000000)
y1=np.random.normal(-1,1,1000000)

#CHUNK OF DATA 2
x2=np.random.normal(-1,1,1000000)
y2=np.random.normal(-1,1,1000000)

#CLASSIC WAY
x=np.concatenate((x1,x2))
y=np.concatenate((y1,y2))
plt.hist2d(x,y,bins=np.linspace(-3,3,101))
plt.savefig("histo1.png",dpi=200)

#ALTERNATIVE WAY
arr1, xedges1, yedges1=np.histogram2d(x1,y1,bins=np.linspace(-3,3,101))
arr2, xedges2, yedges2=np.histogram2d(x2,y2,bins=np.linspace(-3,3,101))
arr=arr1+arr2

plt.figure()
plt.pcolormesh(xedges1,yedges1,arr.T)
plt.savefig("histo2.png",dpi=200)
plt.show()

两个代码产生相同的数字。

如果您事先不知道垃圾箱或不能仅将它们设置为有用的数字,我担心您需要遵循两步程序:

  1. 逐块读入数据,找到最大值和最小值,更新整体最大值和最小值并存储起来以备后用。从内存中删除块。
  2. 再次逐块读取数据并按上述方式进行直方图,在每种情况下使用先前存储的最小值和最大值。

起点可能是这个问题:Numpy histogram of large arrays

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-26
    • 2019-03-05
    相关资源
    最近更新 更多