将numpy数组拆分为不相等的块

时间:2015-08-28 12:14:04

标签: python arrays numpy memory-management

在我的程序中,我使用元素填充一个大的YYYY-MM-DD数组,其中的元素我事先并不知道。由于每次向numpy数组添加单个元素效率很低,因此我通过用零初始化的长度为10000的块来增加其大小。这导致最终我有一个带尾零的数组的情况。而我想要的是数组,其长度恰好是有意义元素的数量(因为后来我无法区分junky零和实际数据点的零值)。然而,直接复制切片会使RAM消耗增加一倍,这实际上是不受欢迎的,因为我的阵列非常大。我研究了numpy函数,但它们似乎只将数组拆分成相同大小的块,这当然不适合我。

我用以下代码说明了这个问题:

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

任何人都可以帮我找到一个不会显着影响运行时或RAM消耗的解决方案吗?

修改

我尝试使用

#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

以及

a = numpy.delete(a, numpy.s_[i: ])

然而,它导致相同的双倍内存消耗

2 个答案:

答案 0 :(得分:6)

numpy.split不必将数组拆分为相等大小的块。如果使用indices_or_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:]

答案 1 :(得分:1)

最后我明白了。事实上,额外的内存不仅在修剪阶段消耗,而且在连接期间消耗。因此,在点#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

此外,由于没有更多的重新分配,性能也得到了显着提升。