ฉันรู้ว่ามีวิธีสำหรับรายการ Python เพื่อกลับดัชนีแรกของบางสิ่ง:
>>> l = [1, 2, 3]
>>> l.index(2)
1
มีอะไรแบบนั้นสำหรับอาร์เรย์ NumPy หรือไม่
ฉันรู้ว่ามีวิธีสำหรับรายการ Python เพื่อกลับดัชนีแรกของบางสิ่ง:
>>> l = [1, 2, 3]
>>> l.index(2)
1
มีอะไรแบบนั้นสำหรับอาร์เรย์ NumPy หรือไม่
คำตอบ:
ใช่นี่คือคำตอบที่กำหนดให้กับอาร์เรย์ NumPy array
และค่าitem
เพื่อค้นหา:
itemindex = numpy.where(array==item)
ผลลัพธ์คือ tuple ที่มีดัชนีแถวแรกทั้งหมดจากนั้นดัชนีทั้งหมด
ตัวอย่างเช่นถ้าอาร์เรย์มีสองมิติและมันมีรายการของคุณในสองตำแหน่ง
array[itemindex[0][0]][itemindex[1][0]]
จะเท่ากับสินค้าของคุณและจะเป็นเช่นนั้น
array[itemindex[0][1]][itemindex[1][1]]
rows, columns = np.where(array==item); first_idx = sorted([r for r, c in zip(rows, columns) if c == 0])[0]
np.argwhere
จะมีประโยชน์มากขึ้นเล็กน้อยที่นี่:itemindex = np.argwhere(array==item)[0]; array[tuple(itemindex)]
where
ทำงานบนอาเรย์ใด ๆ และจะคืนค่าความยาว 3 เมื่อใช้กับอาเรย์ 3 มิติ ฯลฯ
หากคุณต้องการดัชนีของการเกิดครั้งแรกที่มีเพียงค่าเดียวคุณสามารถใช้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]),)
โปรดสังเกตว่ามันพบจุดเริ่มต้นของทั้งการเรียงตามลำดับจาก 3 วินาทีและเรียงตามลำดับจาก 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]),)
r_
ได้บ้าง?
r_
concatenates; หรืออย่างแม่นยำมากขึ้นมันแปลวัตถุชิ้นเพื่อตัดแบ่งตามแต่ละแกน ฉันสามารถใช้hstack
แทนได้ ที่อาจทำให้สับสนน้อยลง ดูเอกสารr_
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ c_
นอกจากนี้ยังมี
vals, locs = np.unique(t, return_index=True)
นอกจากนี้คุณยังสามารถแปลงอาร์เรย์ NumPy เป็นรายการในอากาศและรับดัชนี ตัวอย่างเช่น,
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
[find_list.index(index_list[i]) for i in range(len(index_list))]
find_list
ไปยังอาร์เรย์ NumPy ของobject
(หรืออะไรที่เฉพาะเจาะจงมากขึ้นที่เหมาะสม) find_arr[index_list]
และเพียงแค่ทำ
เพียงเพิ่มนักแสดงที่มีประโยชน์และมีประโยชน์ numbaทางเลือกจาก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,)
@njit
เป็นชวเลขของjit(nopython=True)
ฟังก์ชั่นจะถูกรวบรวมอย่างสมบูรณ์แบบ on-the-fly ในช่วงเวลาของการเรียกใช้ครั้งแรกเพื่อให้การโทรล่าม Python ถูกลบออกอย่างสมบูรณ์
หากคุณกำลังจะใช้สิ่งนี้เป็นดัชนีในสิ่งอื่นคุณสามารถใช้ดัชนีบูลีนได้หากอาร์เรย์นั้นสามารถออกอากาศได้ คุณไม่ต้องการดัชนีที่ชัดเจน วิธีที่ง่ายที่สุดในการทำเช่นนี้คือการจัดทำดัชนีตามค่าความจริง
other_array[first_array == item]
การดำเนินการบูลีนใด ๆ ทำงาน:
a = numpy.arange(100)
other_array[first_array > 50]
วิธีการที่ไม่ใช่ศูนย์รับ booleans เช่นกัน:
index = numpy.nonzero(first_array == item)[0][0]
ศูนย์สองแห่งใช้สำหรับ tuple of indices (สมมติว่า first_array คือ 1D) จากนั้นรายการแรกในอาร์เรย์ของ indices
l.index(x)
ส่งคืนi ที่เล็กที่สุดเช่นiคือดัชนีของการเกิดขึ้นครั้งแรกของ x ในรายการ
หนึ่งสามารถสันนิษฐานได้อย่างปลอดภัยว่ามีการใช้index()
งานฟังก์ชั่นใน Python เพื่อให้หยุดทำงานหลังจากค้นหาคู่แรกและผลลัพธ์นี้มีประสิทธิภาพโดยเฉลี่ยที่ดีที่สุด
สำหรับการค้นหาองค์ประกอบที่หยุดหลังจากการจับคู่ครั้งแรกในอาร์เรย์ 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 GitHub ที่เปิดอยู่
ดูเพิ่มเติมที่: Numpy: ค้นหาดัชนีค่าแรกอย่างรวดเร็ว
%timeit next((idx for idx, val in np.ndenumerate(a) if val==99999))
ทำงานใช่ไหม หากคุณสงสัยว่าทำไมมันช้ากว่า 1,000 เท่า - เป็นเพราะไพทอนวนไปตามแถวที่มีจำนวนมากนั้นช้ามาก
argmax
และwhere
เร็วขึ้นมากในกรณีนี้ (องค์ประกอบการค้นหาที่ส่วนท้ายของอาร์เรย์)
สำหรับอาร์เรย์ที่เรียงลำดับแบบหนึ่งมิติมันจะง่ายกว่าและมีประสิทธิภาพมากกว่า O (บันทึก (n)) เพื่อใช้numpy.searchsortedซึ่งส่งกลับจำนวนเต็ม NumPy (ตำแหน่ง) ตัวอย่างเช่น,
arr = np.array([1, 1, 1, 2, 3, 3, 4])
i = np.searchsorted(arr, 3)
เพียงให้แน่ใจว่าเรียงลำดับแล้ว
ตรวจสอบว่าดัชนีที่ส่งคืนฉันมีองค์ประกอบการค้นหาจริงหรือไม่เนื่องจากวัตถุประสงค์หลักของการค้นหาสารบัญคือการค้นหาดัชนีที่ควรใส่องค์ประกอบเพื่อรักษาลำดับ
if arr[i] == 3:
print("present")
else:
print("not present")
หากต้องการทำดัชนีในเกณฑ์ใด ๆ คุณสามารถทำสิ่งต่อไปนี้ได้:
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 องค์ประกอบ
อีกทางเลือกหนึ่งในการเลือกองค์ประกอบแรกจาก 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 ตรวจสอบองค์ประกอบทั้งหมดเพื่อดูการจับคู่ นิพจน์ตัวสร้างจะเร็วขึ้นหากมีการจับคู่ในช่วงต้นของอาร์เรย์
None
next((i for i, x_i in enumerate(x) if x_i == 2), None)
มีการดำเนินงานจำนวนมากใน NumPy ที่อาจนำมารวมกันเพื่อทำสิ่งนี้ให้สำเร็จ สิ่งนี้จะคืนดัชนีขององค์ประกอบเท่ากับรายการ:
numpy.nonzero(array - item)
จากนั้นคุณสามารถนำองค์ประกอบแรกของรายการเพื่อรับองค์ประกอบเดียว
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]
วิธีการแก้ปัญหานี้มีประสิทธิภาพแบบเวกเตอร์, สรุปทั่วไปเพื่อ ndarrays และมีวิธีการต่างๆในการจัดการกับค่าที่ขาดหายไป
หมายเหตุ: สำหรับรุ่น python 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]
เพื่อรับดัชนีแรกขององค์ประกอบที่ถูกกรอง
สำหรับ python 3.6 ให้ใช้
list(result)
แทน
result
<filter object at 0x0000027535294D30>
Python 3 (ทดสอบบน Python 3.6.3) มีการอัปเดตสำหรับ Python 3 หรือไม่