Numpy: तेजी से मूल्य का पहला सूचकांक पाते हैं


105

मैं Numpy सरणी में किसी संख्या की पहली घटना का सूचकांक कैसे पा सकता हूं? मेरे लिए गति महत्वपूर्ण है। मुझे निम्नलिखित उत्तरों में कोई दिलचस्पी नहीं है क्योंकि वे पूरी सरणी को स्कैन करते हैं और जब वे पहली घटना पाते हैं तो रुकते नहीं हैं:

itemindex = numpy.where(array==item)[0][0]
nonzero(array == item)[0][0]

नोट 1: उस प्रश्न से कोई भी उत्तर प्रासंगिक नहीं लगता है कि क्या किसी सरणी में किसी चीज़ के पहले सूचकांक को वापस करने के लिए कोई Numpy फ़ंक्शन है?

नोट 2: सी-संकलित विधि का उपयोग करना पायथन लूप को पसंद किया जाता है।

जवाबों:



30

यद्यपि यह आपके लिए बहुत देर हो चुकी है, लेकिन भविष्य के संदर्भ के लिए: सुंबा ( 1 ) का उपयोग करना सबसे आसान तरीका है जब तक कि इसे लागू नहीं किया जाता है। यदि आप एनाकोंडा पायथन वितरण का उपयोग करते हैं तो यह पहले से ही स्थापित होना चाहिए। कोड संकलित किया जाएगा तो यह तेज होगा।

@jit(nopython=True)
def find_first(item, vec):
    """return the index of the first occurence of item in vec"""
    for i in xrange(len(vec)):
        if item == vec[i]:
            return i
    return -1

और फिर:

>>> a = array([1,7,8,32])
>>> find_first(8,a)
2

4
Python3 के लिए बदलने की xrangeजरूरत है range

पायथन 3 + में थोड़ा कोड सुधार: उपयोग में enumerate, के रूप में for i, v in enumerate(vec):; if v == item: return i। (यह पायथन <= 2.7 में एक अच्छा विचार नहीं है, जहां enumerateएक मूल
पुनरावृत्ति के

23

मैंने कई तरीकों के लिए एक बेंचमार्क बनाया है:

  • argwhere
  • nonzero सवाल के रूप में
  • .tostring() @Rob Reilink के जवाब में जैसा है
  • अजगर पाश
  • फोरट्रान लूप

अजगर और फोरट्रान कोड उपलब्ध हैं। मैंने किसी सूची में परिवर्तित करने जैसे असमान लोगों को छोड़ दिया।

लॉग स्केल पर परिणाम। एक्स-एक्सिस सुई की स्थिति है (यह पता लगाना अधिक समय लेता है कि क्या यह सरणी के नीचे है); अंतिम मान एक सुई है जो सरणी में नहीं है। Y- अक्ष इसे खोजने का समय है।

बेंचमार्क परिणाम

सरणी में 1 मिलियन तत्व थे और परीक्षण 100 बार चलाए गए थे। परिणाम अभी भी थोड़ा उतार-चढ़ाव करते हैं, लेकिन गुणात्मक प्रवृत्ति स्पष्ट है: पायथन और f2py पहले तत्व पर छोड़ देते हैं ताकि वे समान रूप से माप सकें। यदि सुई पहले 1% में नहीं है, तो पायथन बहुत धीमा हो जाता है, जबकि f2pyतेज है (लेकिन आपको इसे संकलित करने की आवश्यकता है)।

संक्षेप में, f2py सबसे तेज़ समाधान है , खासकर अगर सुई काफी जल्दी दिखाई देती है।

यह नहीं बनाया गया है जिसमें गुस्सा आ रहा है, लेकिन यह वास्तव में सिर्फ 2 मिनट का काम है। इसे किसी फ़ाइल में जोड़ें search.f90:

subroutine find_first(needle, haystack, haystack_length, index)
    implicit none
    integer, intent(in) :: needle
    integer, intent(in) :: haystack_length
    integer, intent(in), dimension(haystack_length) :: haystack
!f2py intent(inplace) haystack
    integer, intent(out) :: index
    integer :: k
    index = -1
    do k = 1, haystack_length
        if (haystack(k)==needle) then
            index = k - 1
            exit
        endif
    enddo
end

यदि आप इसके अलावा किसी और चीज़ की तलाश में हैं integer, तो बस प्रकार बदलें। फिर संकलन का उपयोग करें:

f2py -c -m search search.f90

जिसके बाद आप (पायथन से) कर सकते हैं:

import search
print(search.find_first.__doc__)
a = search.find_first(your_int_needle, your_int_array)

2
f2py10 की तुलना में 1 आइटम के लिए धीमा क्यों है ?
एरिक

2
@ एरिक, मेरा अनुमान है कि उन पैमानों (10e-6) पर, कि डेटा में सिर्फ शोर है, और वास्तविक प्रति-वस्तु की गति इतनी तेज है कि यह सार्थक रूप से उन n <100 या तो कुल समय में योगदान नहीं करता है
ब्रेंडन

11

आप बूलियन सरणी को पायथन स्ट्रिंग में परिवर्तित कर सकते हैं array.tostring()और फिर खोज () विधि का उपयोग कर सकते हैं:

(array==item).tostring().find('\x01')

इसमें डेटा को कॉपी करना शामिल है, हालांकि, चूंकि पायथन स्ट्रिंग्स को अपरिवर्तनीय होने की आवश्यकता है। एक लाभ यह है कि आप खोज कर सकते हैं उदाहरण के लिए एक उभरते हुए किनारे को खोजें\x00\x01


यह दिलचस्प है, लेकिन बमुश्किल तेजी से, अगर बिल्कुल भी, क्योंकि आपको अभी भी सभी डेटा से निपटने की आवश्यकता है (एक बेंचमार्क के लिए मेरा जवाब देखें)।
मार्क

10

हल किए गए सरणियों के मामले में np.searchsorted


2
यदि सरणी में यह आइटम नहीं है, तो सभी सरणी लंबाई वापस आ जाएगी।
बोरिस तेमा

7

मुझे लगता है कि आपने एक समस्या को मारा है जहां एक अलग विधि और कुछ प्राथमिकताएं हैं सरणी का ज्ञान वास्तव में मदद करेगा। उस तरह की चीज़ जहाँ आपको डेटा के पहले Y प्रतिशत में अपना उत्तर खोजने की एक्स संभावना है। भाग्यशाली होने की उम्मीद के साथ समस्या को विभाजित करना, फिर नेस्टेड सूची समझ या कुछ के साथ अजगर में ऐसा करना।

इस ब्रूट फोर्स को करने के लिए C फ़ंक्शन लिखना ctypes के उपयोग से बहुत कठिन नहीं है ।

C कोड मैंने एक साथ हैक किया (index.c):

long index(long val, long *data, long length){
    long ans, i;
    for(i=0;i<length;i++){
        if (data[i] == val)
            return(i);
    }
    return(-999);
}

और अजगर:

# to compile (mac)
# gcc -shared index.c -o index.dylib
import ctypes
lib = ctypes.CDLL('index.dylib')
lib.index.restype = ctypes.c_long
lib.index.argtypes = (ctypes.c_long, ctypes.POINTER(ctypes.c_long), ctypes.c_long)

import numpy as np
np.random.seed(8675309)
a = np.random.random_integers(0, 100, 10000)
print lib.index(57, a.ctypes.data_as(ctypes.POINTER(ctypes.c_long)), len(a))

और मुझे 92 मिले।

अजगर को एक उचित कार्य में लपेटें और वहां आप जाएं।

इस बीज के लिए C संस्करण बहुत (~ 20x) तेज है (चेतावनी मैं समय के साथ अच्छा नहीं हूं)

import timeit
t = timeit.Timer('np.where(a==57)[0][0]', 'import numpy as np; np.random.seed(1); a = np.random.random_integers(0, 1000000, 10000000)')
t.timeit(100)/100
# 0.09761879920959472
t2 = timeit.Timer('lib.index(57, a.ctypes.data_as(ctypes.POINTER(ctypes.c_long)), len(a))', 'import numpy as np; np.random.seed(1); a = np.random.random_integers(0, 1000000, 10000000); import ctypes; lib = ctypes.CDLL("index.dylib"); lib.index.restype = ctypes.c_long; lib.index.argtypes = (ctypes.c_long, ctypes.POINTER(ctypes.c_long), ctypes.c_long) ')
t2.timeit(100)/100
# 0.005288000106811523

1
यदि सरणी डबल्स है (याद रखें कि अजगर फ्लोट सी डिफ़ॉल्ट रूप से सी डबल्स हैं) तो आपको थोड़ा कठिन सोचना होगा == वास्तव में सुरक्षित नहीं है या आप फ्लोटिंग पॉइंट मानों के लिए क्या चाहते हैं। यह भी मत भूलना कि ctypes का उपयोग करते समय यह एक बहुत अच्छा विचार है कि आपके खस्ता सरणियों को टाइप करें।
ब्रायन लार्सन

धन्यवाद @ ब्रायन लार्सन। मैं शायद इसे आज़माऊंगा। मुझे लगता है कि यह अगले सुन्न संशोधन के लिए एक तुच्छ सुविधा अनुरोध है।
सायबोर्ग

5

@tal ने पहले ही numbaपहले इंडेक्स को खोजने के लिए एक फंक्शन पेश किया था लेकिन यह केवल 1D एरेज़ के लिए काम करता है। साथ np.ndenumerateआप भी एक arbitarly आयामी सरणी में पहले सूचकांक पा सकते हैं:

from numba import njit
import numpy as np

@njit
def index(array, item):
    for idx, val in np.ndenumerate(array):
        if val == item:
            return idx
    return None

नमूना मामला:

>>> arr = np.arange(9).reshape(3,3)
>>> index(arr, 3)
(1, 0)

समय पता चलता है कि यह करने के लिए प्रदर्शन में समान है tals समाधान:

arr = np.arange(100000)
%timeit index(arr, 5)           # 1000000 loops, best of 3: 1.88 µs per loop
%timeit find_first(5, arr)      # 1000000 loops, best of 3: 1.7 µs per loop

%timeit index(arr, 99999)       # 10000 loops, best of 3: 118 µs per loop
%timeit find_first(99999, arr)  # 10000 loops, best of 3: 96 µs per loop

1
यदि आप पहले दिए गए अक्ष के साथ खोजने में रुचि रखते हैं: arrayइसे खिलाने से पहले स्थानांतरित करें np.ndenumerate, जैसे कि आपकी रुचि की धुरी पहले आती है।
चेशायरकैट

धन्यवाद, यह वास्तव में तेजी का क्रम है: ~ 171ms ( np.argwhere) से 717ns (आपका समाधान), आकार की एक सरणी के लिए दोनों (3000000, 12))।
आर्थर सेसमिनी गुस्माओ

3

यदि आपकी सूची को क्रमबद्ध किया गया है , तो आप 'बिसेक्ट' पैकेज के साथ सूचकांक की बहुत जल्दी खोज कर सकते हैं । यह O (n) के बजाय O (लॉग (n)) है।

bisect.bisect(a, x)

सरणी में x पाता है, निश्चित रूप से किसी भी सी-रूटीन की तुलना में पहले के सभी तत्वों (लंबे समय तक पर्याप्त सूचियों के लिए) के माध्यम से जाने वाले मामले में जल्दी।

कभी-कभी जान लेना अच्छा होता है।


>>> cond = "import numpy as np;a = np.arange(40)" timeit("np.searchsorted(a, 39)", cond)3.47867107391 सेकंड के लिए काम करता है। timeit("bisect.bisect(a, 39)", cond2)7.0661458969116 सेकंड के लिए काम करता है। ऐसा लगता है कि numpy.searchsortedसॉर्ट किए गए सरणियों के लिए बेहतर है (कम से कम ints के लिए)।
बोरिस तेमा

2

जहां तक ​​मुझे पता है कि बूलियन सरणियों पर केवल np.any और np.all लघु-परिचालित हैं।

आपके मामले में, सुन्न को दो बार पूरे सरणी से गुजरना पड़ता है, एक बार बूलियन स्थिति बनाने के लिए और दूसरी बार सूचकांकों को खोजने के लिए।

इस मामले में मेरी सिफारिश साइथन का उपयोग करने की होगी। मुझे लगता है कि इस मामले के लिए एक उदाहरण को समायोजित करना आसान होना चाहिए, खासकर अगर आपको अलग-अलग dtypes और आकृतियों के लिए अधिक लचीलेपन की आवश्यकता नहीं है।


2

मुझे अपनी नौकरी के लिए इसकी आवश्यकता थी इसलिए मैंने खुद पायथन और नेम्पी के सी इंटरफेस को पढ़ाया और अपना लिखा। http://pastebin.com/GtcXuLyd यह केवल 1-डी सरणियों के लिए है, लेकिन अधिकांश डेटा प्रकारों (इंट, फ्लोट या स्ट्रिंग्स) के लिए काम करता है और परीक्षण से पता चला है कि यह शुद्ध पायथन में अपेक्षित दृष्टिकोण से लगभग 20 गुना तेज है। numpy।


2

इस समस्या को प्रभावी रूप से शुद्ध रूप से हल किया जा सकता है, जो कि टुकड़ों में सरणी को संसाधित करके:

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

सरणी को आकार के chunk में संसाधित किया गया है step। यह stepकदम जितना लंबा होगा, तेजी से शून्य-सरणी (सबसे खराब स्थिति) का प्रसंस्करण होता है। यह छोटा है, शुरुआत में गैर-शून्य के साथ सरणी का तेजी से प्रसंस्करण। चाल एक छोटे से शुरू करने stepऔर इसे तेजी से बढ़ाने के लिए है। इसके अलावा, सीमित लाभ के कारण इसे कुछ सीमा से ऊपर बढ़ाने की आवश्यकता नहीं है।

मैंने शुद्ध ndarary.nonzero और सुंबा समाधान के साथ 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 गुना तेज है।


2

यदि आप पहले गैर-शून्य तत्व की तलाश कर रहे हैं, तो आप निम्नलिखित हैक का उपयोग कर सकते हैं:

idx = x.view(bool).argmax() // x.itemsize
idx = idx if x[idx] else -1

यह एक बहुत तेज़ "सुन्न-शुद्ध" समाधान है लेकिन यह नीचे चर्चा किए गए कुछ मामलों के लिए विफल रहता है।

समाधान इस तथ्य से लाभ उठाता है कि संख्यात्मक प्रकारों के लिए शून्य के सभी प्रतिनिधित्व बहुत अधिक होते हैं 0। यह सुन्न के boolरूप में अच्छी तरह से लागू होता है । संख्या के हाल के संस्करणों में, प्रकार को argmax()संसाधित करते समय फ़ंक्शन शॉर्ट-सर्किट लॉजिक का उपयोग करता है bool। का आकार bool1 बाइट है।

तो एक की जरूरत है:

  • के रूप में सरणी का एक दृश्य बनाएँ bool। कोई कॉपी नहीं बनाई गई है
  • argmax()शॉर्ट-सर्किट लॉजिक का उपयोग करके पहला गैर-शून्य बाइट खोजने के लिए उपयोग करें
  • //बाइट्स में व्यक्त एकल तत्व के आकार के ऑफसेट के पूर्णांक विभाजन (ऑपरेटर ) द्वारा इस बाइट की ऑफसेट को पहले गैर-शून्य तत्व के सूचकांक में पुनर्गणना करें (x.itemsize )
  • जाँच करें कि x[idx]क्या कोई शून्य शून्य मौजूद होने पर मामले की पहचान करने के लिए वास्तव में गैर-शून्य है

मैंने सुंबा समाधान के खिलाफ कुछ बेंचमार्क बनाया है और इसका निर्माण कर रहा हूं np.nonzero

import numpy as np
from numba import jit
from timeit import timeit

def find_first(x):
    idx = x.view(bool).argmax() // x.itemsize
    return idx if x[idx] else -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 57.63976670001284 ms
find_first 0.0010841979965334758 ms
find_first_numba 0.0002308919938514009 ms
---- LAST ----
ndarray.nonzero 58.96685277999495 ms
find_first 5.923203580023255 ms
find_first_numba 8.762269750004634 ms
---- NONE ----
ndarray.nonzero 25.13398071998381 ms
find_first 5.924289370013867 ms
find_first_numba 8.810063839919167 ms
---- ALL ----
ndarray.nonzero 55.181210660084616 ms
find_first 0.001246920000994578 ms
find_first_numba 0.00028766007744707167 ms

समाधान 33% तेज है सुंबा की तुलना है और यह "सुन्न-शुद्ध" है।

नुकसान:

  • जैसे कि स्वीकार्य स्वीकार्य प्रकारों के लिए काम नहीं करता है object
  • नकारात्मक शून्य के लिए विफल रहता है जो कभी-कभी floatया doubleसंगणना में प्रकट होता है

यह सबसे अच्छा शुद्ध खस्ता समाधान ive की कोशिश की है। उत्तर स्वीकार किया जाना चाहिए। @ टिस्टलिसिल इवी एक सरणी में पहले शून्य तत्व को खोजने के लिए एक समान तेजी से समाधान प्राप्त करने की कोशिश कर रहा है, लेकिन यह हमेशा बूल में परिवर्तित होने की तुलना में धीमी गति से समाप्त होता है, फिर आर्गमिन () चल रहा है। कोई विचार?
Ta946

1
@ Ta946। शून्य प्रविष्टियों की तलाश में चाल का उपयोग नहीं किया जा सकता है। उदाहरण के लिए, गैर-शून्य डबल में इसमें एक शून्य बाइट हो सकती है। यदि आप सुन्न-शुद्ध समाधान की तलाश करते हैं तो मेरे अन्य उत्तर को संशोधित करने का प्रयास करें । देखें stackoverflow.com/a/58294774/4989451xफोन करने से पहले एक स्लाइस को नकार दें nonzero()। यह सुंबा की तुलना में धीमा होगा, लेकिन यह ** शून्य के लिए खोज नहीं करेगा, जबकि पहली शून्य प्रविष्टि की तलाश में इस प्रकार यह आपकी आवश्यकताओं के लिए पर्याप्त तेज़ हो सकता है।
teastisl

1

एक लंबे समय से matlab उपयोगकर्ता के रूप में मैं काफी समय से इस समस्या का कुशल समाधान खोज रहा हूं। अंत में, इस सूत्र में एक प्रस्ताव पर चर्चा से प्रेरित होकर मैंने एक समाधान के साथ आने की कोशिश की है जो यहां सुझाए गए एपीआई के समान लागू हो रहा है , केवल 1D सरणियों का समर्थन कर रहा है।

आप इसे इस तरह से उपयोग करेंगे

import numpy as np
import utils_find_1st as utf1st
array = np.arange(100000)
item = 1000
ind = utf1st.find_1st(array, item, utf1st.cmp_larger_eq)

समर्थित ऑपरेटर हैं: cmp_equal, cmp_not_equal, cmp_larger, cmp_smaller, cmp_larger_eq, cmp_smaller_eq। दक्षता के लिए विस्तार में सी लिखा है।

आप स्रोत, बेंचमार्क और अन्य विवरण यहां पा सकते हैं:

https://pypi.python.org/pypi?name=py_find_1st&:action=display

हमारी टीम में उपयोग के लिए (लिनक्स और मैकोस पर एनाकोंडा) मैंने एनाकोंडा इंस्टॉलर बनाया है जो स्थापना को सरल करता है, आप इसे यहाँ वर्णित के रूप में उपयोग कर सकते हैं।

https://anaconda.org/roebel/py_find_1st


"एक लंबे समय तक matlab उपयोगकर्ता के रूप में" - इसके लिए matlab वर्तनी क्या है?
एरिक

find (X, n) पहला n सूचकांक ढूंढता है जहां X गैर शून्य है। mathworks.com/help/matlab/ref/find.html
A Roebel

0

बस ध्यान दें कि यदि आप खोजों का एक क्रम कर रहे हैं, तो स्ट्रिंग में परिवर्तित करने जैसे कुछ चतुर करने से प्रदर्शन लाभ होता है, यदि खोज आयाम पर्याप्त बड़ा नहीं है, तो बाहरी लूप में खो सकता है। यह देखें कि iterating का प्रदर्शन कैसा है जो ऊपर प्रस्तावित स्ट्रिंग रूपांतरण चाल का उपयोग करता है और find2 जो आंतरिक अक्ष के साथ argmax का उपयोग करता है (साथ ही -1 के रूप में गैर-मैच रिटर्न सुनिश्चित करने के लिए एक समायोजन)

import numpy,time
def find1(arr,value):
    return (arr==value).tostring().find('\x01')

def find2(arr,value): #find value over inner most axis, and return array of indices to the match
    b = arr==value
    return b.argmax(axis=-1) - ~(b.any())


for size in [(1,100000000),(10000,10000),(1000000,100),(10000000,10)]:
    print(size)
    values = numpy.random.choice([0,0,0,0,0,0,0,1],size=size)
    v = values>0

    t=time.time()
    numpy.apply_along_axis(find1,-1,v,1)
    print('find1',time.time()-t)

    t=time.time()
    find2(v,1)
    print('find2',time.time()-t)

आउटपुट

(1, 100000000)
('find1', 0.25300002098083496)
('find2', 0.2780001163482666)
(10000, 10000)
('find1', 0.46200013160705566)
('find2', 0.27300000190734863)
(1000000, 100)
('find1', 20.98099994659424)
('find2', 0.3040001392364502)
(10000000, 10)
('find1', 206.7590000629425)
('find2', 0.4830000400543213)

उस ने कहा, सी में लिखा एक खोज इन दृष्टिकोणों की तुलना में कम से कम थोड़ा तेज होगा


0

इस बारे में कैसा है

import numpy as np
np.amin(np.where(array==item))

2
हालांकि यह कोड प्रश्न का उत्तर दे सकता है, क्यों और / या कैसे का उत्तर देता है के संबंध में अतिरिक्त संदर्भ प्रदान करने से इसके दीर्घकालिक मूल्य में काफी सुधार होगा। कृपया कुछ स्पष्टीकरण जोड़ने के लिए अपने उत्तर को संपादित करें।
स्पाइट

1
मुझे पूरा यकीन है कि यह where(array==item)[0][0]सवाल से भी धीमा है ...
मार्क

-1

आप अपनी सरणी को एक में गुप्त कर सकते हैं listऔर इसका उपयोग कर सकते हैं index():

i = list(array).index(item)

जहाँ तक मेरी जानकारी है, यह एक सी संकलित विधि है।


3
यह सिर्फ np.where से कई बार धीमा परिणाम होने की संभावना है
cwa

1
बहुत ही सही .. मैंने timeit()10000 पूर्णांक की एक सरणी का उपयोग किया - एक सूची में परिवर्तित करना लगभग 100 गुना धीमा था! मैं यह भूल गया था कि सुन्न सरणी के लिए अंतर्निहित डेटा संरचना एक सूची से बहुत अलग है ..
drevicko
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.