খণ্ডগুলিতে অ্যারের প্রক্রিয়াজাতকরণের মাধ্যমে এই সমস্যাটি খাঁটি নিম্পিতে কার্যকরভাবে সমাধান করা যেতে পারে:
def find_first(x):
idx, step = 0, 32
while idx < x.size:
nz, = x[idx: idx + step].nonzero()
if len(nz): # found non-zero, return it
return nz[0] + idx
# move to the next chunk, increase step
idx += step
step = min(9600, step + step // 2)
return -1
অ্যারে আকার আকারে প্রক্রিয়া করা হয় step
। step
পদক্ষেপটি যত দীর্ঘ হবে তত দ্রুত শূন্য-অ্যারে (সবচেয়ে খারাপ ক্ষেত্রে) প্রক্রিয়াকরণ করা হচ্ছে। এটি যত কম ছোট, শুরুতে শূন্যহীন অ্যারের দ্রুত প্রসেসিং। কৌশলটি হল একটি ছোট দিয়ে শুরু করা step
এবং এটি তাত্পর্যপূর্ণভাবে বাড়ানো। অধিকন্তু, সীমিত সুবিধার কারণে এটি কিছু প্রান্তিকের উপরে বাড়িয়ে দেওয়ার দরকার নেই।
আমি সমাধানটিকে খাঁটি ndarary.nonzero এবং numba সমাধানের সাথে 10 মিলিয়ন অ্যারে ভাসমানের সাথে তুলনা করেছি।
import numpy as np
from numba import jit
from timeit import timeit
def find_first(x):
idx, step = 0, 32
while idx < x.size:
nz, = x[idx: idx + step].nonzero()
if len(nz):
return nz[0] + idx
idx += step
step = min(9600, step + step // 2)
return -1
@jit(nopython=True)
def find_first_numba(vec):
"""return the index of the first occurence of item in vec"""
for i in range(len(vec)):
if vec[i]:
return i
return -1
SIZE = 10_000_000
# First only
x = np.empty(SIZE)
find_first_numba(x[:10])
print('---- FIRST ----')
x[:] = 0
x[0] = 1
print('ndarray.nonzero', timeit(lambda: x.nonzero()[0][0], number=100)*10, 'ms')
print('find_first', timeit(lambda: find_first(x), number=1000), 'ms')
print('find_first_numba', timeit(lambda: find_first_numba(x), number=1000), 'ms')
print('---- LAST ----')
x[:] = 0
x[-1] = 1
print('ndarray.nonzero', timeit(lambda: x.nonzero()[0][0], number=100)*10, 'ms')
print('find_first', timeit(lambda: find_first(x), number=100)*10, 'ms')
print('find_first_numba', timeit(lambda: find_first_numba(x), number=100)*10, 'ms')
print('---- NONE ----')
x[:] = 0
print('ndarray.nonzero', timeit(lambda: x.nonzero()[0], number=100)*10, 'ms')
print('find_first', timeit(lambda: find_first(x), number=100)*10, 'ms')
print('find_first_numba', timeit(lambda: find_first_numba(x), number=100)*10, 'ms')
print('---- ALL ----')
x[:] = 1
print('ndarray.nonzero', timeit(lambda: x.nonzero()[0][0], number=100)*10, 'ms')
print('find_first', timeit(lambda: find_first(x), number=100)*10, 'ms')
print('find_first_numba', timeit(lambda: find_first_numba(x), number=100)*10, 'ms')
এবং আমার মেশিনে ফলাফল:
---- FIRST ----
ndarray.nonzero 54.733994480002366 ms
find_first 0.0013148509997336078 ms
find_first_numba 0.0002839310000126716 ms
---- LAST ----
ndarray.nonzero 54.56336712999928 ms
find_first 25.38929685000312 ms
find_first_numba 8.022820680002951 ms
---- NONE ----
ndarray.nonzero 24.13432420999925 ms
find_first 25.345200140000088 ms
find_first_numba 8.154927100003988 ms
---- ALL ----
ndarray.nonzero 55.753537260002304 ms
find_first 0.0014760300018679118 ms
find_first_numba 0.0004358099977253005 ms
খাঁটি ndarray.nonzero
নিশ্চিত লুজার। সেরা মামলার জন্য নাম্বার দ্রবণটি 5 গুণ দ্রুততর হয়। এটি সবচেয়ে খারাপ ক্ষেত্রে সার্কা 3 গুণ দ্রুত।