[Numpy-discussion] Is there a more efficient way to do this?
Brett Olsen
brett.olsen at gmail.com
Wed Aug 8 11:41:05 EDT 2012
On Wed, Aug 8, 2012 at 9:19 AM, Laszlo Nagy <gandalf at shopzeus.com> wrote:
> Is there a more efficient way to calculate the "slices" array below?
>
> I do not want to make copies of DATA, because it can be huge. The
> argsort is fast enough. I just need to create slices for different
> dimensions. The above code works, but it does a linear time search,
> implemented in pure Python code. For every iteration, Python code is
> executed. For 1 million rows, this is very slow. Is there a way to
> produce "slices" with numpy code? I could write C code for this, but I
> would prefer to do it with mass numpy operations.
>
> Thanks,
>
> Laszlo
#Code
import numpy as np
#rows between 100 to 1M
rows = 1000
data = np.random.random_integers(0, 100, rows)
def get_slices_slow(data):
o = np.argsort(data)
slices = []
prev_val = None
sidx = -1
for oidx, rowidx in enumerate(o):
val = data[rowidx]
if not val == prev_val:
if prev_val is None:
prev_val = val
sidx = oidx
else:
slices.append((prev_val, sidx, oidx))
sidx = oidx
prev_val = val
if (sidx >= 0) and (sidx < rows):
slices.append((val, sidx, rows))
slices = np.array(slices, dtype=np.int64)
return slices
def get_slices_fast(data):
nums = np.unique(data)
slices = np.zeros((len(nums), 3), dtype=np.int64)
slices[:,0] = nums
count = 0
for i, num in enumerate(nums):
count += (data == num).sum()
slices[i,2] = count
slices[1:,1] = slices[:-1,2]
return slices
def get_slices_faster(data):
nums = np.unique(data)
slices = np.zeros((len(nums), 3), dtype=np.int64)
slices[:,0] = nums
count = np.bincount(data)
slices[:,2] = count.cumsum()
slices[1:,1] = slices[:-1,2]
return slices
#Testing in ipython
In [2]: (get_slices_slow(data) == get_slices_fast(data)).all()
Out[2]: True
In [3]: (get_slices_slow(data) == get_slices_faster(data)).all()
Out[3]: True
In [4]: timeit get_slices_slow(data)
100 loops, best of 3: 3.51 ms per loop
In [5]: timeit get_slices_fast(data)
1000 loops, best of 3: 1.76 ms per loop
In [6]: timeit get_slices_faster(data)
10000 loops, best of 3: 116 us per loop
So using the fast bincount and array indexing methods gets you about a
factor of 30 improvement. Even just doing the counting in a loop with
good indexing will get you a factor of 2.
~Brett
More information about the NumPy-Discussion
mailing list