In my program I fill a large numpy array with elements, number of which I do not know in advance. Since adding single element per go to a numpy array is inefficient, I increase its size by chunks of length 10000 initialized with zeros. This leads to the situation that in the end I have an array with tail of zeros. And what I would like to have is the array, whose length is precisely number of meaningful elements (because later I cannot distinguish junky zeros from actual data points with zero value). Straightforward copying of slicing, however, doubles the RAM consumption, which is really undesirable since my arrays are quite large. I looked into numpy.split functions, but they seem to split arrays only into chunks of the equal size, which of course does not suit me.
I illustrate the problem with the following code:
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 ')
This outputs:
#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
Can anyone help me to find a solution that does not penalize significantly runtime or RAM consumption?
Edit:
I tried to use
a = numpy.delete(a, numpy.s_[i: ])
as well as
a = numpy.split(a, (i, ))[0]
However, it results in the same doubled memory consumption
np.fromiter, but I assume your generator is just for testing and not what you're actually using. Also, if you yield scalars instead of arrays (as yourelement) that will be much faster of course, unless eachelementwill actually have some length in your use case.arraygeneration is a step in big program that contributes only a tiny fraction of total runtime, therefore the speed is not critical. On the other hand, this step was the memory bottleneck. And the generator is of course much more complex and involves receiving data from the network.