如何使用matplotlib基于大数据制作2D直方图?

问题描述 投票:0回答:1

我想做一个大型数据集的二维直方图。如果我一次打开所有数据,我会收到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()时相同的结果?

这个问题的标题中没有空间,我不能想象一个更简洁的版本,所以最后我决定提出一个更普遍的问题并解释我的具体案例。对不起如果这样不方便。

python numpy matplotlib
1个回答
1
投票

我想有两个问题。

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

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

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()

两个代码都生成相同的数字。

enter image description here

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.