هل هناك NumPy الدالة بإرجاع أول مؤشر من شيء في المصفوفة ؟

StackOverflow https://stackoverflow.com/questions/432112

  •  08-07-2019
  •  | 
  •  

سؤال

وأنا أعلم أن هناك طريقة الثعبان قائمة للعودة أول مؤشر من شيء:

>>> l = [1, 2, 3]
>>> l.index(2)
1

هل هناك شيء مثل هذا NumPy المصفوفات?

هل كانت مفيدة؟

المحلول

نعم، وهنا هو الجواب مجموعة نمباي، array، وقيمة، item، للبحث عن:

itemindex = numpy.where(array==item)

والنتيجة هي الصفوف (tuple) مع جميع المؤشرات الصف الأول، ثم كل المؤشرات العمود.

وعلى سبيل المثال، إذا كان الصفيف بعدين وأنها تحتوي على البند الخاص بك في موقعين ثم

array[itemindex[0][0]][itemindex[1][0]]

وسوف يكون مساويا لالبند الخاص بك وذلك من شأنه

array[itemindex[0][1]][itemindex[1][1]]

numpy.where

نصائح أخرى

إذا كنت بحاجة إلى مؤشر أول حدوث قيمة واحدة فقط, يمكنك استخدام nonzero (أو where, الذي يرقى إلى نفس الشيء في هذه الحالة):

>>> t = array([1, 1, 1, 2, 2, 3, 8, 3, 8, 8])
>>> nonzero(t == 8)
(array([6, 8, 9]),)
>>> nonzero(t == 8)[0][0]
6

إذا كنت بحاجة إلى أول مؤشر من كل من العديد من القيم, يمكنك أن من الواضح أن تفعل الشيء نفسه كما سبق مرارا ، ولكن هناك خدعة التي قد يكون أسرع.التالية يجد مؤشرات العنصر الأول من كل subsequence:

>>> nonzero(r_[1, diff(t)[:-1]])
(array([0, 3, 5, 6, 7, 8]),)

لاحظ أنه يرى بداية كل subsequence من 3s و كل subsequences من 8s:

[1, 1, 1, 2, 2, 3, 8, 3, 8, 8]

حتى انها مختلفة قليلا من العثور على أول حدوث من كل قيمة.في البرنامج الخاص بك, كنت قد تكون قادرة على العمل مع فرز إصدار t للحصول على ما تريد:

>>> st = sorted(t)
>>> nonzero(r_[1, diff(st)[:-1]])
(array([0, 3, 5, 7]),)

ويمكنك أيضا تحويل مجموعة نمباي لسرد في الهواء والحصول على مؤشره. على سبيل المثال،

l = [1,2,3,4,5] # Python list
a = numpy.array(l) # NumPy array
i = a.tolist().index(2) # i will return index of 2
print i

ووسوف طباعة 1.

إذا كنت تنوي استخدام هذا بمثابة مؤشر إلى شيء آخر، يمكنك استخدام مؤشرات منطقية إذا كان صفائف broadcastable. لا تحتاج مؤشرات واضحة. طريقة أبسط المطلقة للقيام بذلك هو مؤشر ببساطة على أساس القيمة الحقيقة.

other_array[first_array == item]

وأي عملية منطقية تعمل:

a = numpy.arange(100)
other_array[first_array > 50]

وهذه الطريقة غير صفرية يأخذ القيم المنطقية، وأيضا:

index = numpy.nonzero(first_array == item)[0][0]

والأصفار هما لالصفوف (tuple) مؤشرات (على افتراض first_array هو 1D) ثم العنصر الأول في مجموعة من المؤشرات.

فقط لإضافة جدا performant ومفيد البديلة على أساس np.ndenumerate العثور على أول مؤشر:

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
    # If no item was found return None, other return types might be a problem due to
    # numbas type inference.

هذا هو سريع جدا ، يتعامل بشكل طبيعي مع المصفوفات متعددة الأبعاد:

>>> arr1 = np.ones((100, 100, 100))
>>> arr1[2, 2, 2] = 2

>>> index(arr1, 2)
(2, 2, 2)

>>> arr2 = np.ones(20)
>>> arr2[5] = 2

>>> index(arr2, 2)
(5,)

هذا يمكن أن يكون أسرع بكثير (لأنها تفقد أعصابها العملية) من أي نهج باستخدام np.where أو np.nonzero.


ومع ذلك np.argwhere يمكن أيضا التعامل برشاقة مع المصفوفات متعددة الأبعاد (سوف تحتاج إلى يدويا يلقي إلى tuple و ليس تماس) ولكن كان يمكن أن تفشل إذا تم العثور على أي تطابق:

>>> tuple(np.argwhere(arr1 == 2)[0])
(2, 2, 2)
>>> tuple(np.argwhere(arr2 == 2)[0])
(5,)

l.index(x) إرجاع أصغر أنا مثل أن أنا هو مؤشر أول حدوث العاشر في القائمة.

يمكن للمرء أن نفترض بأمان أن index() وظيفة في بيثون هو تنفيذها بحيث يتوقف بعد العثور على المباراة الأولى ، و هذه النتائج في أفضل أداء متوسط.

لإيجاد عنصر وقف بعد أول مباراة في NumPy مجموعة استخدام التكرار (ndenumerate).

In [67]: l=range(100)

In [68]: l.index(2)
Out[68]: 2

NumPy مجموعة:

In [69]: a = np.arange(100)

In [70]: next((idx for idx, val in np.ndenumerate(a) if val==2))
Out[70]: (2L,)

نلاحظ أن كلتا الطريقتين index() و next بإرجاع خطأ إذا كان العنصر غير موجود.مع next, يمكن للمرء أن استخدام الوسيطة الثانية إلى إرجاع قيمة خاصة في حالة عنصر لم يتم العثور, على سبيل المثال

In [77]: next((idx for idx, val in np.ndenumerate(a) if val==400),None)

وهناك وظائف أخرى في NumPy (argmax, where, ، nonzero) التي يمكن استخدامها لإيجاد عنصر في صفيف ، ولكن لديهم كل العيب من الذهاب من خلال كل مجموعة تبحث عن كل الحوادث, وبالتالي لا يجري الأمثل لإيجاد العنصر الأول.نلاحظ أيضا أن where و nonzero عودة المصفوفات ، لذلك تحتاج إلى تحديد العنصر الأول للحصول على المؤشر.

In [71]: np.argmax(a==2)
Out[71]: 2

In [72]: np.where(a==2)
Out[72]: (array([2], dtype=int64),)

In [73]: np.nonzero(a==2)
Out[73]: (array([2], dtype=int64),)

المقارنة الوقت

مجرد التحقق من ذلك على صفائف كبيرة الحل باستخدام التكرار هو أسرع عندما بحثت البند هو في بداية مجموعة (باستخدام %timeit في IPython شل):

In [285]: a = np.arange(100000)

In [286]: %timeit next((idx for idx, val in np.ndenumerate(a) if val==0))
100000 loops, best of 3: 17.6 µs per loop

In [287]: %timeit np.argmax(a==0)
1000 loops, best of 3: 254 µs per loop

In [288]: %timeit np.where(a==0)[0][0]
1000 loops, best of 3: 314 µs per loop

هذا هو مفتوح NumPy جيثب المسألة.

انظر أيضا: Numpy:العثور على أول مؤشر قيمة سريع

لمؤشر على أي معايير، يمكنك ذلك شيء كما يلي:

In [1]: from numpy import *
In [2]: x = arange(125).reshape((5,5,5))
In [3]: y = indices(x.shape)
In [4]: locs = y[:,x >= 120] # put whatever you want in place of x >= 120
In [5]: pts = hsplit(locs, len(locs[0]))
In [6]: for pt in pts:
   .....:         print(', '.join(str(p[0]) for p in pt))
4, 4, 0
4, 4, 1
4, 4, 2
4, 4, 3
4, 4, 4

وهنا وظيفة سريعة لتفعل ما list.index () لا، إلا لا تثير استثناء إذا هو لم يتم العثور عليه. حذار - وربما هذا هو بطيء جدا على صفائف كبيرة. ربما يمكنك قرد التصحيح هذا إلى صفائف إذا كنت تفضل استخدامها كوسيلة من وسائل.

def ndindex(ndarray, item):
    if len(ndarray.shape) == 1:
        try:
            return [ndarray.tolist().index(item)]
        except:
            pass
    else:
        for i, subarray in enumerate(ndarray):
            try:
                return [i] + ndindex(subarray, item)
            except:
                pass

In [1]: ndindex(x, 103)
Out[1]: [4, 0, 3]

لالمصفوفات 1D، أنصح np.flatnonzero(array == value)[0]، وهو ما يعادل كلا np.nonzero(array == value)[0][0] وnp.where(array == value)[0][0] لكنها تتجنب بشاعة علبته والصفوف (tuple) 1-العنصر.

وهناك الكثير من العمليات في نمباي التي ربما وضعها معا لتحقيق ذلك. هذا سيعود مؤشرات من العناصر يساوي البند:

numpy.nonzero(array - item)

ويمكنك بعد ذلك اتخاذ العناصر الأولى من القوائم للحصول على عنصر واحد.

واحدة الأبعاد فرز صفائف أنه سيكون أكثر بساطة وكفاءة O(log(n)) استخدام numpy.searchsorted والتي ترجع NumPy صحيح (موقف).على سبيل المثال ،

arr = np.array([1, 1, 1, 2, 3, 3, 4])
i = np.searchsorted(arr, 3)

فقط تأكد من المصفوفة هو بالفعل فرز

تحقق أيضا إذا عاد مؤشر أنا في الواقع يحتوي على بحثت عنصر منذ searchsorted الهدف الرئيسي هو العثور على الأرقام القياسية حيث العناصر التي ينبغي إدراجها للحفاظ على النظام.

if arr[i] == 3:
    print("present")
else:
    print("not present")

وبديل لاختيار العنصر الأول من np.where () هو استخدام تعبير مولد جنبا إلى جنب مع اعدد، مثل:

>>> import numpy as np
>>> x = np.arange(100)   # x = array([0, 1, 2, 3, ... 99])
>>> next(i for i, x_i in enumerate(x) if x_i == 2)
2

لمجموعة اثنين بعد واحد ستفعل:

>>> x = np.arange(100).reshape(10,10)   # x = array([[0, 1, 2,... 9], [10,..19],])
>>> next((i,j) for i, x_i in enumerate(x) 
...            for j, x_ij in enumerate(x_i) if x_ij == 2)
(0, 2)

وميزة هذا النهج هو أنه توقف عن التحقق من عناصر المصفوفة بعد وجدت على المباراة الأولى، في حين الشيكات np.where جميع العناصر لمباراة. ومن شأن التعبير مولد يكون أسرع إذا كان هناك تطابق في مجموعة في وقت مبكر.

numpy_indexed الحزمة (العقد، وأنا صاحبه) يحتوي على ما يعادل vectorized من list.index لnumpy.ndarray. وهذا هو:

sequence_of_arrays = [[0, 1], [1, 2], [-5, 0]]
arrays_to_query = [[-5, 0], [1, 0]]

import numpy_indexed as npi
idx = npi.indices(sequence_of_arrays, arrays_to_query, missing=-1)
print(idx)   # [2, -1]

لقد vectorized هذا الحل الأداء، يعمم على ndarrays، ولديه طرق مختلفة للتعامل مع القيم المفقودة.

ملاحظة:هذا هو بايثون 2.7 الإصدار

يمكنك استخدام وظيفة لامدا للتعامل مع المشكلة ، يعمل على كل NumPy مجموعة قائمة.

your_list = [11, 22, 23, 44, 55]
result = filter(lambda x:your_list[x]>30, range(len(your_list)))
#result: [3, 4]

import numpy as np
your_numpy_array = np.array([11, 22, 23, 44, 55])
result = filter(lambda x:your_numpy_array [x]>30, range(len(your_list)))
#result: [3, 4]

ويمكنك استخدام

result[0]

للحصول على أول مؤشر من تصفية العناصر.

بايثون 3.6, استخدام

list(result)

بدلا من

result
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top