原博地址: http://chrisschell.de/2018/02/01/how-to-efficiently-deal-with-huge-Numpy-arrays.html
1. 更快faster: 使用预分配的arrays
假设您从数据库中检索了大量不同的值。您想以某种方式处理这些数据,然后将它们保存到numpy数组中。
不要
不要遍历每个数据并将其逐个添加到数组中,如下所示:
entries = range(1000000) # 1 billion entries
results = np.array((0,)) # empty array
for entry in entries:
processed_entry = entry + 5 # do something
results = np.append(results, [processed_entry])
这个例子在我的MacBook Air上大约需要11秒。我使用这样一个循环来填充多维数组,最终有超过10亿条数据。以这种方式构建该数组需要大约45分钟。这里的问题是,python需要一次又一次地为在内存中分配空间以此来对数组进行append操作,这非常耗时。
要
使用np.zeros方法预分配数组
entries = range(1000000) # 1 million entries
results = np.zeros((len(entries),)) # prefilled array
for idx, entry in enumerate(entries):
processed_entry = entry + 5 # do something
results[idx] = processed_entry
这可以在1秒内完成,因为数组已经以完整的大小存在内存中。
如果您事先不知道最终的数组大小,您甚至可以这样做np.resize来调整大小,这仍然比其他方法快得多。
2. 更大larger:使用h5py
有时,你的数组十分大,主存(RAM)不再适应
不要
不要向下面的方式来操作数据
results = np.ones((1000,1000,1000,5))
#do something...
results[100, 25, 1, 4] = 42
执行上述代码,你的RAM将没有空余,不要期望你的电脑还可以做别的,这段代码就占用了将近40GB的内存
要
显然这是要避免的。我们需要以某种方式将这些数据存储在我们的磁盘上,而不是RAM中。所以需要使用h5py模块:
import h5py
hdf5_store = h5py.File("./cache.hdf5", "a")
results = hdf5_store.create_dataset("results", (1000,1000,1000,5), compression="gzip")
#do something...
results[100, 25, 1, 4] = 42
这将创建一个包含数据的cache.hdf5文件。create_dataset给我们一个对象,我们可以像一个numpy数组一样对待(至少在大多数时候)。另外,我们得到一个包含这个数组的文件,我们可以从其它地方访问它:
hdf5_store = h5py.File("./cache.hdf5", "r")
print(hdf5_store["results"][100, 25, 1, 4]) # 42.0
3.更聪明smarter:不要经常访问数组
不要
这个情况应该是显而易见的,但代码中有时仍然会出现,如果在循环中需要访问数组中的某一值
some_array = np.ones((100, 200, 300))
for _ in range(10000000):
some_array[50, 12, 199] # get some value some_array
尽管numpy在通过索引访问大型数组时确实很快,但它仍然需要一些时间,在大循环中时间消耗变得非常大。
要
只需将数组访问移动到循环外部,您就可以获得显着的改进:
some_array = np.ones((100, 200, 300))
the_value_I_need = some_array[50, 12, 199] # access some_array
for _ in range(10000000):
the_value_I_need
它的运行速度在MacBook Air上其他版本的两倍。大多数时候,像这样的简单事情会减慢一切!