Python 将numpy数组拆分为不相等的块
在我的程序中,我用元素填充一个大的Python 将numpy数组拆分为不相等的块,python,arrays,numpy,memory-management,Python,Arrays,Numpy,Memory Management,在我的程序中,我用元素填充一个大的numpy数组,元素的数量我事先不知道。由于每次向numpy数组添加单个元素效率低下,因此我将其大小增加10000个块,并用零初始化。这就导致了这样一种情况,最后我得到了一个带有零尾的数组。我想要的是数组,它的长度正好是有意义元素的数量(因为后来我无法区分零值的零值和实际数据点)。但是,直接复制切片会使RAM消耗翻一番,这确实是不可取的,因为我的阵列非常大。我研究了numpy.split函数,但它们似乎只将数组分割成大小相等的块,这当然不适合我 我用以下代码说明
numpy
数组,元素的数量我事先不知道。由于每次向numpy
数组添加单个元素效率低下,因此我将其大小增加10000个块,并用零初始化。这就导致了这样一种情况,最后我得到了一个带有零尾的数组。我想要的是数组,它的长度正好是有意义元素的数量(因为后来我无法区分零值的零值和实际数据点)。但是,直接复制切片会使RAM消耗翻一番,这确实是不可取的,因为我的阵列非常大。我研究了numpy.split
函数,但它们似乎只将数组分割成大小相等的块,这当然不适合我
我用以下代码说明问题:
import numpy, os, random
def check_memory(mode_peak = True, mark = ''):
"""Function for measuring the memory consumption (Linux only)"""
pid = os.getpid()
with open('/proc/{}/status'.format(pid), 'r') as ifile:
for line in ifile:
if line.startswith('VmPeak' if mode_peak else 'VmSize'):
memory = line[: -1].split(':')[1].strip().split()[0]
memory = int(memory) / (1024 * 1024)
break
mode_str = 'Peak' if mode_peak else 'Current'
print('{}{} RAM consumption: {:.3f} GB'.format(mark, mode_str, memory))
def generate_element():
"""Test element generator"""
for i in range(12345678):
yield numpy.array(random.randrange(0, 1000), dtype = 'i4')
check_memory(mode_peak = False, mark = '#1 ')
a = numpy.zeros(10000, dtype = 'i4')
i = 0
for element in generate_element():
if i == len(a):
a = numpy.concatenate((a, numpy.zeros(10000, dtype = 'i4')))
a[i] = element
i += 1
check_memory(mode_peak = False, mark = '#2 ')
a = a[: i]
check_memory(mode_peak = False, mark = '#3 ')
check_memory(mode_peak = True, mark = '#4 ')
这将产生:
#1 Current RAM consumption: 0.070 GB
#2 Current RAM consumption: 0.118 GB
#3 Current RAM consumption: 0.118 GB
#4 Peak RAM consumption: 0.164 GB
有人能帮我找到一个不会严重影响运行时或RAM消耗的解决方案吗
编辑:
我试着用
a = numpy.delete(a, numpy.s_[i: ])
以及
a = numpy.split(a, (i, ))[0]
但是,它会导致相同的内存消耗翻倍不必将数组拆分为大小相等的块。如果使用index\u或_sections
参数,可以给出一个整数列表,它将使用该列表拆分数组。例如:
>>> x = np.arange(8.0)
>>> np.split(x, [3, 5, 6, 10])
[array([ 0., 1., 2.]), # x[:3]
array([ 3., 4.]), # x[3:5]
array([ 5.]), # x[5:6]
array([ 6., 7.]), # x[6:10]
array([], dtype=float64)] # x[10:]
不必将数组拆分为大小相等的块。如果使用index\u或_sections
参数,可以给出一个整数列表,它将使用该列表拆分数组。例如:
>>> x = np.arange(8.0)
>>> np.split(x, [3, 5, 6, 10])
[array([ 0., 1., 2.]), # x[:3]
array([ 3., 4.]), # x[3:5]
array([ 5.]), # x[5:6]
array([ 6., 7.]), # x[6:10]
array([], dtype=float64)] # x[10:]
我终于明白了。事实上,额外的内存不仅在修剪阶段被消耗,而且在连接过程中也被消耗。因此,在点
#2
处引入峰值内存检查输出:
#2 Peak RAM consumption: 0.164 GB
但是,有一种方法是resize()
方法,它可以在适当的位置更改数组的大小/形状:
check_memory(mode_peak = False, mark = '#1 ')
page_size = 10000
a = numpy.zeros(page_size, dtype = 'i4')
i = 0
for element in generate_element():
if (i != 0) and (i % page_size == 0):
a.resize(i + page_size)
a[i] = element
i += 1
a.resize(i)
check_memory(mode_peak = False, mark = '#2 ')
check_memory(mode_peak = True, mark = '#2 ')
这将导致输出:
#1 Current RAM consumption: 0.070 GB
#2 Current RAM consumption: 0.118 GB
#2 Peak RAM consumption: 0.118 GB
此外,由于没有更多的重新分配,性能也得到了显著提高。我终于找到了答案。事实上,额外的内存不仅在修剪阶段被消耗,而且在连接过程中也被消耗。因此,在点
#2
处引入峰值内存检查输出:
#2 Peak RAM consumption: 0.164 GB
但是,有一种方法是resize()
方法,它可以在适当的位置更改数组的大小/形状:
check_memory(mode_peak = False, mark = '#1 ')
page_size = 10000
a = numpy.zeros(page_size, dtype = 'i4')
i = 0
for element in generate_element():
if (i != 0) and (i % page_size == 0):
a.resize(i + page_size)
a[i] = element
i += 1
a.resize(i)
check_memory(mode_peak = False, mark = '#2 ')
check_memory(mode_peak = True, mark = '#2 ')
这将导致输出:
#1 Current RAM consumption: 0.070 GB
#2 Current RAM consumption: 0.118 GB
#2 Peak RAM consumption: 0.118 GB
此外,由于不再进行重新分配,性能也显著提高。我的错误是我没有正确理解
numpy.split
的语法。然而,这导致了与切片相同的内存消耗翻倍:a=numpy.split(a,(i,)[0]
我的错误是我没有正确理解numpy.split的语法。但是,这会导致与切片相同的内存消耗翻倍:a=numpy.split(a,(i,)[0]
相对于内存,速度可能对您不重要,但我不知道如何在我的系统(mac os x)上测试内存消耗。在任何情况下,对我来说,构建一个列表,然后在最后转换为数组的速度大约快2倍。对我来说,最快的(虽然我不知道它实际上是如何实现的)是np.fromiter
,但我假设您的生成器只是用于测试,而不是您实际使用的。另外,如果您产生的是标量而不是数组(作为元素
),当然会快得多,除非每个元素
在您的用例中实际上都有一些长度。@askewchan在我的例子中,数组
的生成是大程序中的一个步骤,只占总运行时间的一小部分,因此,速度不是关键。另一方面,这一步是内存瓶颈。当然,生成器要复杂得多,需要从网络接收数据。相对于内存,速度可能对您来说并不重要,但我不知道如何在我的系统(mac os x)上测试内存消耗。在任何情况下,对我来说,构建一个列表,然后在最后转换为数组的速度大约快2倍。对我来说,最快的(虽然我不知道它实际上是如何实现的)是np.fromiter
,但我假设您的生成器只是用于测试,而不是您实际使用的。另外,如果您产生的是标量而不是数组(作为元素
),当然会快得多,除非每个元素
在您的用例中实际上都有一些长度。@askewchan在我的例子中,数组
的生成是大程序中的一个步骤,只占总运行时间的一小部分,因此,速度不是关键。另一方面,这一步是内存瓶颈。当然,生成器要复杂得多,需要从网络接收数据。