Pertanyaan Python: indeks persimpangan numpy array


Bagaimana saya bisa mendapatkan indeks titik-titik persimpangan antara dua array numpy? Saya bisa mendapatkan nilai yang berpotongan dengan intersect1d:

import numpy as np

a = np.array(xrange(11))
b = np.array([2, 7, 10])
inter = np.intersect1d(a, b)
# inter == array([ 2,  7, 10])

Tapi bagaimana saya bisa mendapatkan indeks a nilai-nilai dalam inter?


32
2017-07-14 12:47


asal


Jawaban:


Anda bisa menggunakan array boolean yang dihasilkan oleh in1d untuk mengindeks arange. Membalikkan a sehingga indeks berbeda dari nilai-nilai:

>>> a[::-1]
array([10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0])
>>> a = a[::-1]

intersect1d masih mengembalikan nilai yang sama ...

>>> numpy.intersect1d(a, b)
array([ 2,  7, 10])

Tapi in1d mengembalikan array boolean:

>>> numpy.in1d(a, b)
array([ True, False, False,  True, False, False, False, False,  True,
       False, False], dtype=bool)

Yang dapat digunakan untuk mengindeks suatu rentang:

>>> numpy.arange(a.shape[0])[numpy.in1d(a, b)]
array([0, 3, 8])
>>> indices = numpy.arange(a.shape[0])[numpy.in1d(a, b)]
>>> a[indices]
array([10,  7,  2])

Untuk menyederhanakan hal di atas, Anda bisa menggunakannya nonzero - Ini mungkin pendekatan yang paling benar, karena mengembalikan daftar tuple yang seragam X, Y... koordinat:

>>> numpy.nonzero(numpy.in1d(a, b))
(array([0, 3, 8]),)

Atau, dengan kata lain:

>>> numpy.in1d(a, b).nonzero()
(array([0, 3, 8]),)

Hasilnya dapat digunakan sebagai indeks untuk array dengan bentuk yang sama seperti a tanpa masalah.

>>> a[numpy.nonzero(numpy.in1d(a, b))]
array([10,  7,  2])

Tetapi perhatikan bahwa dalam banyak situasi, masuk akal hanya untuk menggunakan array boolean itu sendiri, daripada mengubahnya menjadi satu set indeks non-boolean.

Akhirnya, Anda juga bisa meneruskan array boolean ke argwhere, yang menghasilkan hasil yang sedikit berbeda yang tidak sesuai untuk pengindeksan, tetapi mungkin berguna untuk tujuan lain.

>>> numpy.argwhere(numpy.in1d(a, b))
array([[0],
       [3],
       [8]])

36
2017-07-14 12:59



Jika Anda perlu mendapatkan nilai unik seperti yang diberikan oleh intersect1d:

import numpy as np

a = np.array([range(11,21), range(11,21)]).reshape(20)
b = np.array([12, 17, 20])
print(np.intersect1d(a,b))
#unique values

inter = np.in1d(a, b)
print(a[inter])
#you can see these values are not unique

indices=np.array(range(len(a)))[inter]
#These are the non-unique indices

_,unique=np.unique(a[inter], return_index=True)

uniqueIndices=indices[unique]
#this grabs the unique indices

print(uniqueIndices)
print(a[uniqueIndices])
#now they are unique as you would get from np.intersect1d()

Keluaran:

[12 17 20]
[12 17 20 12 17 20]
[1 6 9]
[12 17 20]

2
2017-09-20 21:47



Untuk Python >= 3.5, ada solusi lain untuk melakukannya

Solusi Lain

Mari kita selesaikan langkah demi langkah ini.

Berdasarkan kode asli dari pertanyaan

import numpy as np

a = np.array(range(11))
b = np.array([2, 7, 10])
inter = np.intersect1d(a, b)

Pertama, kita membuat array numpy dengan nol

c = np.zeros(len(a))
print (c)
>>> [ 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.]

Kedua, ubah nilai array dari c menggunakan indeks berpotongan. Oleh karena itu, kami punya

c[inter] = 1
print (c)
>>>[ 0.  0.  1.  0.  0.  0.  0.  1.  0.  0.  1.]

Langkah terakhir, gunakan karakteristik np.nonzero(), itu akan mengembalikan persis indeks tidak ada istilah yang Anda inginkan.

inter_with_idx = np.nonzero(c)
print (inter_with_idx)
>>>array([ 2, 7, 10])

Referensi

[1] numpy.nonzero 


0
2018-01-17 09:30