Numpy 处理大型Numpy数组
阅读更多:Numpy 教程
介绍
NumPy是Python科学计算库的基础。它支持大型多维数组和矩阵,以及其中包含的快速数学运算。当您的数据集非常大而无法完全加载到内存中时,NumPy非常有用,因为它支持内存映射文件和流式计算,这使您可以逐块处理数据而不会耗尽内存。本文中,我们将提供一些技术,显示如何处理大型Numpy数组。
1. 内存映射
内存映射是指将磁盘上的文件映射到进程的内存中。这样做可以减少I/O负载,并且在大型数据集上执行操作比传统I/O更快。Numpy数组支持内存映射,可以通过使用np.memmap函数创建。
例如,假设您有一个超大型的csv文件,其中包含有用的数值数据。您可以使用以下代码将其读取到内存中的numpy数组中:
import numpy as np
filename = "data.csv"
array = np.genfromtxt(filename, delimiter=",")
这可能需要几分钟到几小时的时间,具体取决于数据文件的大小和计算机的速度。相反,您可以使用numpy.memmap函数将数据文件映射到numpy内存映射数组中,如下所示:
import numpy as np
filename = "data.csv"
array = np.memmap(filename, dtype='float32', mode='r', shape=(10**6, 100))
这里,我们使用了np.memmap函数将数据文件映射到numpy数组中,其中dtype指定了数据类型,mode指定了映射的模式(’r’代表只读),shape指定了数组的维数和形状。
在内存映射的数组中,您可以像使用普通的numpy数组一样使用它,例如切片,索引,统计和缩减。
2. 分块计算
如果您无法使用内存映射文件,并且正在处理大于可用内存的数据集,请考虑将其拆分成块并将块逐个处理。这可以通过对numpy数组进行切片来实现。例如,如果您有一个2D数组,可以使用以下循环遍历每个子区域:
import numpy as np
def process_block(block):
# 处理numpy块
pass
# 加载大型数组
array = np.load("big_array.npy")
# 定义块大小
block_size = 1000
# 处理块
for i in range(0, array.shape[0], block_size):
for j in range(0, array.shape[1], block_size):
# 从大数组中提取子块
block = array[i:i+block_size, j:j+block_size]
# 处理子块
process_block(block)
在此示例中,我们加载一个大型numpy数组并将其拆分为大小为1000的子区域。然后,我们使用两层循环遍历每个子区域,并使用process_block函数处理它。每个子块都可以仅在内存中处理,这比在整个数组上进行计算要快得多。
3. 消除赋值
在处理大型numpy数组时,在循环中进行多次赋值可能会导致显着的性能损失。您可以使用原位操作来消除这些赋值操作。它们具有通过引用复制并在同一空间中进行修改的数组的内存效率。
例如,假设您有一个2D数组且您要在其中每个元素上执行一些函数:
import numpy as np
def expensive_func(x):
# 昂贵的函数
return x ** 2 + np.sin(x)
# 加载大型数组
array = np.load("big_array.npy")
# 使用原地操作遍历数组并更新其值
for i in range(array.shape[0]):
for j in range(array.shape[1]):
array[i, j] = expensive_func(array[i, j])
在这个例子中,我们使用了2个嵌套的循环来遍历数组中的每个元素,并使用expensive_func函数进行计算。但是,我们没有在每个循环迭代中进行赋值,而是通过在原地更新数组来实现内存效率。这可以显着提高计算速度。
4. 使用并行计算
在处理大型numpy数组时,使用并行计算可以显着提高计算速度。NumPy支持并行计算,可以通过多个核心/线程来并行计算操作。您可以使用多个线程或通过使用multiprocessing模块的多个进程来实现并行计算。例如,您可以使用以下代码在4个核心上并行计算:
import numpy as np
from concurrent.futures import ThreadPoolExecutor
# 创建4个数据块计算函数
def process_block(block):
# 处理numpy块
pass
# 加载大型数组
array = np.load("big_array.npy")
# 定义块大小
block_size = 1000
# 使用线程池计算块
with ThreadPoolExecutor(max_workers=4) as executor:
for i in range(0, array.shape[0], block_size):
for j in range(0, array.shape[1], block_size):
# 从大数组中提取子块
block = array[i:i+block_size, j:j+block_size]
# 提交块处理任务到线程池
executor.submit(process_block, block)
在这个示例中,我们使用了concurrent.futures.ThreadPoolExecutor来并行计算数据块。我们创建了一个process_block函数来处理数据块,然后使用两个嵌套的循环来遍历所有块并将它们提交到线程池中。
总结
在本文中,我们介绍了处理大型numpy数组的一些技术。我们看到了如何使用内存映射、分块计算、消除赋值和并行计算来处理大型数据集。这些技术将帮助您在处理大型数据集时提高计算速度并减少内存开销。
极客笔记