Temukan baris unik di numpy.array

199

Saya perlu mencari baris unik di a numpy.array.

Sebagai contoh:

>>> a # I have
array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])
>>> new_a # I want to get to
array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 0]])

Saya tahu bahwa saya dapat membuat satu set dan loop di atas array, tetapi saya mencari numpysolusi murni yang efisien . Saya percaya bahwa ada cara untuk mengatur tipe data menjadi batal dan kemudian saya hanya bisa menggunakan numpy.unique, tapi saya tidak tahu bagaimana cara membuatnya bekerja.

Akavall
sumber
11
panda memiliki metode dataframe.drop_duplicates (). Lihat stackoverflow.com/questions/12322779/pandas-unique-dataframe dan pandas.pydata.org/pandas-docs/dev/generated/...
codeape
Terima kasih, tetapi saya tidak bisa menggunakan panda.
Akavall
2
kemungkinan duplikat Menghapus duplikat di setiap baris array numpy
Andy Hayden
1
@Andy Hayden, terlepas dari judulnya, itu bukan duplikat untuk pertanyaan ini. Link codeape adalah duplikat.
Wai Yip Tung
5
Fitur ini akan muncul secara native ke 1.13: github.com/numpy/numpy/pull/7742
Eric

Jawaban:

115

Pada NumPy 1.13, seseorang dapat dengan mudah memilih sumbu untuk pemilihan nilai unik dalam sembarang N-dim array. Untuk mendapatkan baris unik, Anda dapat melakukan:

unique_rows = np.unique(original_array, axis=0)

aiwabdn
sumber
12
Hati-hati dengan fungsi ini. np.unique(list_cor, axis=0)membuat Anda array dengan baris duplikat dihapus ; itu tidak memfilter array ke elemen yang unik di array asli . Lihat di sini , misalnya ..
Brad Solomon
Perhatikan bahwa jika Anda ingin baris unik mengabaikan urutan nilai di baris, Anda dapat mengurutkan array asli dalam kolom langsung terlebih dahulu:original_array.sort(axis=1)
mangecoeur
140

Namun solusi lain yang mungkin

np.vstack({tuple(row) for row in a})
Greg von Winckel
sumber
20
+1 Ini jelas, pendek dan pythonic. Kecuali jika kecepatan adalah masalah nyata, solusi semacam ini harus lebih disukai daripada jawaban IMO yang kompleks dan memiliki suara lebih tinggi.
Bill Cheatham
3
Luar biasa! Kurung kurawal atau fungsi set () berfungsi.
Tian He
2
@Greg von Winckel Bisakah Anda menyarankan sesuatu yang bukan sesuatu yang tidak mengubah urutan.
Laschet Jain
Ya, tetapi tidak dalam satu perintah: x = []; [x.append (tuple (r)) untuk r in a tuple (r) tidak dalam x]; a_unique = array (x);
Greg von Winckel
1
Untuk menghindari FutureWarning, konversikan set ke daftar seperti: np.vstack(list({tuple(row) for row in AIPbiased[i, :, :]})) FutureWarning: array ke stack harus diteruskan sebagai tipe "sequence" seperti list atau tuple. Dukungan untuk iterables non-urutan seperti generator tidak digunakan lagi pada NumPy 1.16 dan akan meningkatkan kesalahan di masa mendatang.
leermeester
111

Opsi lain untuk penggunaan array terstruktur adalah menggunakan tampilan voidtipe yang menggabungkan seluruh baris menjadi satu item:

a = np.array([[1, 1, 1, 0, 0, 0],
              [0, 1, 1, 1, 0, 0],
              [0, 1, 1, 1, 0, 0],
              [1, 1, 1, 0, 0, 0],
              [1, 1, 1, 1, 1, 0]])

b = np.ascontiguousarray(a).view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))
_, idx = np.unique(b, return_index=True)

unique_a = a[idx]

>>> unique_a
array([[0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])

EDIT Ditambahkan np.ascontiguousarrayberikut rekomendasi @ seberg. Ini akan memperlambat metode jika array belum berdekatan.

EDIT Di atas dapat sedikit dipercepat, mungkin dengan mengorbankan kejelasan, dengan melakukan:

unique_a = np.unique(b).view(a.dtype).reshape(-1, a.shape[1])

Juga, setidaknya pada sistem saya, kinerja bijaksana itu setara, atau bahkan lebih baik, daripada metode lexsort:

a = np.random.randint(2, size=(10000, 6))

%timeit np.unique(a.view(np.dtype((np.void, a.dtype.itemsize*a.shape[1])))).view(a.dtype).reshape(-1, a.shape[1])
100 loops, best of 3: 3.17 ms per loop

%timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]
100 loops, best of 3: 5.93 ms per loop

a = np.random.randint(2, size=(10000, 100))

%timeit np.unique(a.view(np.dtype((np.void, a.dtype.itemsize*a.shape[1])))).view(a.dtype).reshape(-1, a.shape[1])
10 loops, best of 3: 29.9 ms per loop

%timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]
10 loops, best of 3: 116 ms per loop
Jaime
sumber
3
Terima kasih banyak. Ini adalah jawaban yang saya cari, Anda dapat menjelaskan apa yang sedang terjadi dalam langkah ini: b = a.view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))?
Akavall
3
@Akavall Ini membuat tampilan data Anda dengan np.voidtipe data ukuran jumlah byte dalam satu baris penuh. Ini mirip dengan dua yang Anda dapatkan jika Anda memiliki array np.uint8s dan melihatnya sebagai np.uint16s, yang menggabungkan setiap dua kolom menjadi satu, tetapi lebih fleksibel.
Jaime
3
@ Jaime, dapatkah Anda menambahkan np.ascontiguousarrayatau serupa agar secara umum aman (saya tahu ini sedikit lebih ketat dari yang diperlukan, tapi ...). Baris harus bersebelahan agar tampilan berfungsi seperti yang diharapkan.
seberg
2
@ConstantineEvans Ini adalah tambahan baru-baru ini: di numpy 1.6, mencoba untuk menjalankan np.uniquepada array np.voidpengembalian kesalahan terkait dengan mergesort tidak diimplementasikan untuk jenis itu. Ini berfungsi dengan baik di 1,7 sekalipun.
Jaime
9
Perlu dicatat bahwa jika metode ini digunakan untuk angka floating point ada tangkapan yang -0.tidak akan membandingkan sama dengan +0., sedangkan perbandingan elemen-oleh-elemen akan memiliki -0.==+0.(seperti yang ditentukan oleh standar float ieee). Lihat stackoverflow.com/questions/26782038/…
tom10
29

Jika Anda ingin menghindari biaya memori dari konversi ke serangkaian tupel atau struktur data serupa lainnya, Anda dapat mengeksploitasi susunan terstruktur numpy.

Caranya adalah dengan melihat array asli Anda sebagai array terstruktur di mana setiap item sesuai dengan deretan array asli. Ini tidak membuat salinan, dan cukup efisien.

Sebagai contoh cepat:

import numpy as np

data = np.array([[1, 1, 1, 0, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [1, 1, 1, 0, 0, 0],
                 [1, 1, 1, 1, 1, 0]])

ncols = data.shape[1]
dtype = data.dtype.descr * ncols
struct = data.view(dtype)

uniq = np.unique(struct)
uniq = uniq.view(data.dtype).reshape(-1, ncols)
print uniq

Untuk memahami apa yang terjadi, lihat hasil perantara.

Setelah kami melihat sesuatu sebagai array terstruktur, setiap elemen dalam array adalah baris di array asli Anda. (Pada dasarnya, ini adalah struktur data yang mirip dengan daftar tupel.)

In [71]: struct
Out[71]:
array([[(1, 1, 1, 0, 0, 0)],
       [(0, 1, 1, 1, 0, 0)],
       [(0, 1, 1, 1, 0, 0)],
       [(1, 1, 1, 0, 0, 0)],
       [(1, 1, 1, 1, 1, 0)]],
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])

In [72]: struct[0]
Out[72]:
array([(1, 1, 1, 0, 0, 0)],
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])

Setelah kami jalankan numpy.unique, kami akan mendapatkan array terstruktur kembali:

In [73]: np.unique(struct)
Out[73]:
array([(0, 1, 1, 1, 0, 0), (1, 1, 1, 0, 0, 0), (1, 1, 1, 1, 1, 0)],
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])

Yang kemudian perlu kita lihat sebagai array "normal" ( _menyimpan hasil perhitungan terakhir ipython, itulah mengapa Anda melihatnya _.view...):

In [74]: _.view(data.dtype)
Out[74]: array([0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0])

Dan kemudian membentuk kembali menjadi array 2D ( -1adalah placeholder yang memberitahu numpy untuk menghitung jumlah baris yang benar, berikan jumlah kolom):

In [75]: _.reshape(-1, ncols)
Out[75]:
array([[0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])

Jelas, jika Anda ingin lebih ringkas, Anda bisa menuliskannya sebagai:

import numpy as np

def unique_rows(data):
    uniq = np.unique(data.view(data.dtype.descr * data.shape[1]))
    return uniq.view(data.dtype).reshape(-1, data.shape[1])

data = np.array([[1, 1, 1, 0, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [0, 1, 1, 1, 0, 0],
                 [1, 1, 1, 0, 0, 0],
                 [1, 1, 1, 1, 1, 0]])
print unique_rows(data)

Yang mengakibatkan:

[[0 1 1 1 0 0]
 [1 1 1 0 0 0]
 [1 1 1 1 1 0]]
Joe Kington
sumber
Ini sebenarnya tampak sangat lambat, hampir sama lambatnya dengan menggunakan tuple. Menyortir array terstruktur seperti ini lambat, rupanya.
cge
3
@cge - Cobalah dengan array berukuran lebih besar. Ya, mengurutkan array numpy lebih lambat daripada mengurutkan daftar. Kecepatan bukanlah pertimbangan utama dalam kebanyakan kasus di mana Anda menggunakan ndarrays. Ini penggunaan memori. Daftar tupel akan menggunakan memori jauh lebih banyak daripada solusi ini. Bahkan jika Anda memiliki cukup memori, dengan array yang cukup besar, mengubahnya menjadi daftar tuple memiliki overhead yang lebih besar daripada keuntungan kecepatan.
Joe Kington
@ co - Ah, saya tidak melihat Anda menggunakan lexsort. Saya pikir Anda merujuk menggunakan daftar tupel. Ya, lexsortmungkin opsi yang lebih baik dalam hal ini. Saya sudah lupa tentang itu, dan melompat ke solusi yang terlalu rumit.
Joe Kington
20

np.uniqueketika saya menjalankannya np.random.random(100).reshape(10,10)mengembalikan semua elemen individu yang unik, tetapi Anda menginginkan baris yang unik, jadi pertama-tama Anda harus memasukkannya ke dalam tupel:

array = #your numpy array of lists
new_array = [tuple(row) for row in array]
uniques = np.unique(new_array)

Itulah satu-satunya cara saya melihat Anda mengubah jenis untuk melakukan apa yang Anda inginkan, dan saya tidak yakin apakah daftar iterasi yang akan diubah menjadi tuple tidak apa-apa dengan "tidak mengulangi" Anda.

Ryan Saxe
sumber
5
+1 Ini jelas, pendek dan pythonic. Kecuali jika kecepatan adalah masalah nyata, solusi semacam ini harus lebih disukai daripada jawaban IMO yang kompleks dan memiliki suara lebih tinggi.
Bill Cheatham
Saya lebih suka ini daripada solusi yang diterima. Kecepatan bukan masalah bagi saya karena saya mungkin hanya memiliki < 100baris per doa. Ini menggambarkan dengan tepat bagaimana melakukan unik atas baris dilakukan.
rayryeng
4
Ini sebenarnya tidak berfungsi untuk data saya, uniquesmengandung elemen unik. Berpotensi saya salah memahami bentuk yang diharapkan array- bisakah Anda lebih tepat di sini?
FooBar
@ ryan-saxe Saya suka ini pythonic tetapi ini bukan solusi yang baik karena baris kembali ke uniquesdiurutkan (dan karena itu berbeda dari baris di array). B = np.array([[1,2],[2,1]]); A = np.unique([tuple(row) for row in B]); print(A) = array([[1, 2],[1, 2]])
jmlarson
16

np.unique bekerja dengan mengurutkan array yang diratakan, kemudian melihat apakah setiap item sama dengan sebelumnya. Ini dapat dilakukan secara manual tanpa perataan:

ind = np.lexsort(a.T)
a[ind[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]]

Metode ini tidak menggunakan tupel, dan harus jauh lebih cepat dan lebih sederhana daripada metode lain yang diberikan di sini.

CATATAN: Versi sebelumnya ini tidak memiliki ind tepat setelah [, yang berarti bahwa indeks yang salah digunakan. Juga, Joe Kington menunjukkan bahwa ini memang membuat berbagai salinan perantara. Metode berikut ini membuat lebih sedikit, dengan membuat salinan yang diurutkan dan kemudian menggunakan tampilan itu:

b = a[np.lexsort(a.T)]
b[np.concatenate(([True], np.any(b[1:] != b[:-1],axis=1)))]

Ini lebih cepat dan menggunakan lebih sedikit memori.

Juga, jika Anda ingin menemukan baris unik di ndarray terlepas dari berapa banyak dimensi dalam array, berikut ini akan berfungsi:

b = a[lexsort(a.reshape((a.shape[0],-1)).T)];
b[np.concatenate(([True], np.any(b[1:]!=b[:-1],axis=tuple(range(1,a.ndim)))))]

Masalah yang tersisa yang menarik adalah jika Anda ingin mengurutkan / unik di sepanjang sumbu arbitrer dari array dimensi arbitrer, sesuatu yang akan lebih sulit.

Edit:

Untuk menunjukkan perbedaan kecepatan, saya menjalankan beberapa tes di ipython dari tiga metode berbeda yang dijelaskan dalam jawaban. Dengan a persis Anda , tidak ada banyak perbedaan, meskipun versi ini sedikit lebih cepat:

In [87]: %timeit unique(a.view(dtype)).view('<i8')
10000 loops, best of 3: 48.4 us per loop

In [88]: %timeit ind = np.lexsort(a.T); a[np.concatenate(([True], np.any(a[ind[1:]]!= a[ind[:-1]], axis=1)))]
10000 loops, best of 3: 37.6 us per loop

In [89]: %timeit b = [tuple(row) for row in a]; np.unique(b)
10000 loops, best of 3: 41.6 us per loop

Namun, dengan versi yang lebih besar, versi ini menjadi jauh lebih cepat:

In [96]: a = np.random.randint(0,2,size=(10000,6))

In [97]: %timeit unique(a.view(dtype)).view('<i8')
10 loops, best of 3: 24.4 ms per loop

In [98]: %timeit b = [tuple(row) for row in a]; np.unique(b)
10 loops, best of 3: 28.2 ms per loop

In [99]: %timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!= a[ind[:-1]],axis=1)))]
100 loops, best of 3: 3.25 ms per loop
cge
sumber
Sangat bagus! Di samping catatan, itu memang membuat beberapa salinan perantara. (misalnya a[ind[1:]]salinan, dll.) Di sisi lain, solusi Anda umumnya 2-3x lebih cepat daripada menambang sampai Anda kehabisan ram.
Joe Kington
Poin yang bagus. Ternyata, upaya saya untuk mengambil salinan perantara dengan hanya menggunakan indeks membuat metode saya menggunakan lebih banyak memori dan berakhir lebih lambat daripada hanya membuat salinan array yang diurutkan, karena a_sorted [1:] bukan salinan a_sorted .
cge
Apa yang ada dtypedalam timing Anda? Saya pikir Anda salah. Di sistem saya, menelepon np.uniqueseperti yang dijelaskan dalam jawaban saya sedikit lebih cepat daripada menggunakan salah satu dari dua rasa Anda np.lexsort. Dan ini sekitar 5x lebih cepat jika array untuk menemukan uniques memiliki bentuk (10000, 100). Bahkan jika Anda memutuskan untuk mengimplementasikan kembali apa yang np.uniquedilakukan untuk memangkas waktu eksekusi (minor), mengecilkan setiap baris menjadi satu objek menjalankan perbandingan lebih cepat daripada harus memanggil np.anyperbandingan kolom, terutama untuk jumlah kolom yang lebih tinggi.
Jaime
@cge: Anda mungkin bermaksud 'np.any' alih-alih standar 'any' yang tidak mengambil argumen kata kunci.
M. Toya
@Jaime - Saya percaya dtypeitu adil a.dtype, yaitu tipe data dari data yang dilihat, seperti yang dilakukan oleh Joe Kington dalam jawabannya. Jika ada banyak kolom, cara lain (tidak sempurna!) Untuk membuat hal-hal cepat menggunakan lexsortadalah dengan hanya mengurutkan pada beberapa kolom. Ini khusus data karena orang perlu tahu kolom mana yang menyediakan varians yang cukup untuk disortir dengan sempurna. Misalnya a.shape = (60000, 500)- semacam pada 3 kolom pertama: ind = np.lexsort((a[:, 2], a[:, 1], a[:, 0])). Penghematan waktu cukup besar, tetapi penafian lagi: mungkin tidak menangkap semua kasus - itu tergantung pada data.
n1k31t4
9

Berikut adalah variasi lain untuk jawaban pygtonic @Greg

np.vstack(set(map(tuple, a)))
divenex
sumber
9

Saya telah membandingkan alternatif kecepatan yang disarankan dan menemukan bahwa, secara mengejutkan, uniquesolusi void view bahkan sedikit lebih cepat daripada numpy yang asli uniquedengan axisargumen tersebut. Jika Anda mencari kecepatan, Anda pasti mau

numpy.unique(
    a.view(numpy.dtype((numpy.void, a.dtype.itemsize*a.shape[1])))
    ).view(a.dtype).reshape(-1, a.shape[1])

masukkan deskripsi gambar di sini


Kode untuk mereproduksi plot:

import numpy
import perfplot


def unique_void_view(a):
    return numpy.unique(
        a.view(numpy.dtype((numpy.void, a.dtype.itemsize*a.shape[1])))
        ).view(a.dtype).reshape(-1, a.shape[1])


def lexsort(a):
    ind = numpy.lexsort(a.T)
    return a[ind[
        numpy.concatenate((
            [True], numpy.any(a[ind[1:]] != a[ind[:-1]], axis=1)
            ))
        ]]


def vstack(a):
    return numpy.vstack({tuple(row) for row in a})


def unique_axis(a):
    return numpy.unique(a, axis=0)


perfplot.show(
    setup=lambda n: numpy.random.randint(2, size=(n, 20)),
    kernels=[unique_void_view, lexsort, vstack, unique_axis],
    n_range=[2**k for k in range(15)],
    logx=True,
    logy=True,
    xlabel='len(a)',
    equality_check=None
    )
Nico Schlömer
sumber
1
Jawaban yang sangat bagus, satu poin minor vstack_dict:, tidak pernah menggunakan dict, kurung kurawal adalah pemahaman set, dan oleh karena itu perilakunya hampir identik dengan vstatck_set. Karena, vstack_dictgaris kinerja hilang untuk grafik mondar-mandir, sepertinya itu hanya ditutupi oleh vstack_setgrafik kinerja, karena mereka sangat mirip!
Akavall
Terima kasih balasannya. Saya telah memperbaiki plot untuk memasukkan hanya satu vstackvarian.
Nico Schlömer
8

Saya tidak menyukai jawaban ini karena tidak ada yang menangani array titik mengambang dalam aljabar linear atau ruang vektor, di mana dua baris “sama” berarti “dalam beberapa 𝜀”. Satu jawaban yang memiliki ambang toleransi, https://stackoverflow.com/a/26867764/500207 , menganggap ambang tersebut sebagai elemen-bijaksana dan desimal presisi , yang berfungsi untuk beberapa kasus tetapi tidak secara matematis umum seperti jarak vektor benar.

Ini versi saya:

from scipy.spatial.distance import squareform, pdist

def uniqueRows(arr, thresh=0.0, metric='euclidean'):
    "Returns subset of rows that are unique, in terms of Euclidean distance"
    distances = squareform(pdist(arr, metric=metric))
    idxset = {tuple(np.nonzero(v)[0]) for v in distances <= thresh}
    return arr[[x[0] for x in idxset]]

# With this, unique columns are super-easy:
def uniqueColumns(arr, *args, **kwargs):
    return uniqueRows(arr.T, *args, **kwargs)

Fungsi domain publik di atas digunakan scipy.spatial.distance.pdistuntuk menemukan jarak Euclidean (dapat disesuaikan) antara setiap pasangan baris. Kemudian membandingkan setiap jarak ke yang threshlama untuk menemukan baris yang berada dalam threshsatu sama lain, dan mengembalikan hanya satu baris dari masing-masingthresh -cluster.

Seperti yang ditunjukkan, jarak metrictidak harus Euclidean - pdistdapat menghitung jarak yang beragam termasuk cityblock(norma-Manhattan) dancosine (sudut antara vektor).

Jika thresh=0(default), maka baris harus agak tepat untuk dianggap "unik". Nilai bagus lainnya untuk threshpenggunaan presisi mesin skala, yaitu thresh=np.spacing(1)*1e3,.

Ahmed Fasih
sumber
Jawaban Terbaik. Terima kasih. Ini adalah jawaban paling umum (matematis) yang ditulis sejauh ini. Ini mempertimbangkan matriks sebagai satu set titik data atau sampel dalam ruang dimensi N dan menemukan kumpulan titik yang sama atau serupa (kesamaan didefinisikan oleh jarak Euclidean atau dengan metode lain). Poin-poin ini bisa tumpang tindih poin data atau lingkungan yang sangat dekat. Pada akhirnya, kumpulan poin yang sama atau serupa digantikan oleh salah satu poin (dalam jawaban di atas dengan poin pertama) milik set yang sama. Ini membantu mengurangi redundansi dari cloud titik.
Sanchit
@Sanchit aha, itu adalah poin yang bagus, alih-alih memilih “first” point (sebenarnya itu bisa secara acak acak, karena itu tergantung pada bagaimana Python menyimpan poin dalam a set) sebagai perwakilan dari setiap threshlingkungan berukuran, fungsi dapat memungkinkan pengguna untuk menentukan cara memilih titik itu, misalnya, gunakan "median" atau titik terdekat dengan centroid, dll.
Ahmed Fasih
Tentu. Tanpa keraguan. Saya baru saja menyebutkan poin pertama karena ini adalah apa yang sedang dilakukan oleh program Anda yang benar-benar baik-baik saja.
Sanchit
Hanya koreksi — saya salah mengatakan di atas bahwa baris yang akan dipilih untuk masing-masing- threshcluster akan acak karena sifat unordered dari set. Tentu saja itu adalah brainfart di bagian saya, yang settoko tupel indeks yang berada di thresh-neighborhood, jadi ini findRows tidak pada kenyataannya kembali, untuk setiap thresh-cluster, baris pertama di dalamnya.
Ahmed Fasih
3

Mengapa tidak menggunakan drop_duplicatespanda:

>>> timeit pd.DataFrame(image.reshape(-1,3)).drop_duplicates().values
1 loops, best of 3: 3.08 s per loop

>>> timeit np.vstack({tuple(r) for r in image.reshape(-1,3)})
1 loops, best of 3: 51 s per loop
kalu
sumber
Saya sebenarnya suka jawaban ini. Tentu, itu tidak menggunakan numpy secara langsung, tetapi bagi saya itu yang paling mudah dipahami saat sedang cepat.
noctilux
3

The numpy_indexed paket (disclaimer: Saya penulisnya) membungkus solusi diposting oleh Jaime di nice dan diuji antarmuka, ditambah lagi banyak fitur:

import numpy_indexed as npi
new_a = npi.unique(a)  # unique elements over axis=0 (rows) by default
Eelco Hoogendoorn
sumber
1

np.unique works diberi daftar tuple:

>>> np.unique([(1, 1), (2, 2), (3, 3), (4, 4), (2, 2)])
Out[9]: 
array([[1, 1],
       [2, 2],
       [3, 3],
       [4, 4]])

Dengan daftar daftar yang dimunculkannya a TypeError: unhashable type: 'list'

kode kode
sumber
sepertinya tidak bekerja pada milikku. Setiap tuple adalah dua string, bukan dua angka float
mjp
tidak berfungsi, ia mengembalikan daftar elemen yang bukan tupel
Mohanad Kaleia
1

Berdasarkan jawaban di halaman ini saya telah menulis sebuah fungsi yang mereplikasi kemampuan unique(input,'rows')fungsi MATLAB , dengan fitur tambahan untuk menerima toleransi untuk memeriksa keunikan. Ini juga mengembalikan indeks sedemikian rupa sehingga c = data[ia,:]dan data = c[ic,:]. Silakan laporkan jika Anda melihat perbedaan atau kesalahan.

def unique_rows(data, prec=5):
    import numpy as np
    d_r = np.fix(data * 10 ** prec) / 10 ** prec + 0.0
    b = np.ascontiguousarray(d_r).view(np.dtype((np.void, d_r.dtype.itemsize * d_r.shape[1])))
    _, ia = np.unique(b, return_index=True)
    _, ic = np.unique(b, return_inverse=True)
    return np.unique(b).view(d_r.dtype).reshape(-1, d_r.shape[1]), ia, ic
Arash_D_B
sumber
1

Di luar @Jaime jawaban yang sangat baik, cara lain untuk menutup baris adalah dengan menggunakan a.strides[0](dengan asumsi aC-berdekatan) yang sama dengan a.dtype.itemsize*a.shape[0]. Selanjutnya void(n)adalah jalan pintas untuk dtype((void,n)). akhirnya kami sampai pada versi terpendek ini:

a[unique(a.view(void(a.strides[0])),1)[1]]

Untuk

[[0 1 1 1 0 0]
 [1 1 1 0 0 0]
 [1 1 1 1 1 0]]
BM
sumber
0

Untuk tujuan umum seperti 3D atau array bertingkat multidimensi yang lebih tinggi, coba ini:

import numpy as np

def unique_nested_arrays(ar):
    origin_shape = ar.shape
    origin_dtype = ar.dtype
    ar = ar.reshape(origin_shape[0], np.prod(origin_shape[1:]))
    ar = np.ascontiguousarray(ar)
    unique_ar = np.unique(ar.view([('', origin_dtype)]*np.prod(origin_shape[1:])))
    return unique_ar.view(origin_dtype).reshape((unique_ar.shape[0], ) + origin_shape[1:])

yang memenuhi dataset 2D Anda:

a = np.array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])
unique_nested_arrays(a)

memberi:

array([[0, 1, 1, 1, 0, 0],
   [1, 1, 1, 0, 0, 0],
   [1, 1, 1, 1, 1, 0]])

Tetapi juga array 3D seperti:

b = np.array([[[1, 1, 1], [0, 1, 1]],
              [[0, 1, 1], [1, 1, 1]],
              [[1, 1, 1], [0, 1, 1]],
              [[1, 1, 1], [1, 1, 1]]])
unique_nested_arrays(b)

memberi:

array([[[0, 1, 1], [1, 1, 1]],
   [[1, 1, 1], [0, 1, 1]],
   [[1, 1, 1], [1, 1, 1]]])
Tara
sumber
Menggunakan unique return_indexseperti yang dilakukan Jaime seharusnya membuat returnbaris terakhir lebih sederhana. Cukup indekskan bagian asli arpada sumbu kanan.
hpaulj
0

Tidak satu pun dari jawaban ini yang berhasil untuk saya. Saya berasumsi karena baris unik saya berisi string dan bukan angka. Namun jawaban dari utas lain ini berhasil:

Sumber: https://stackoverflow.com/a/38461043/5402386

Anda dapat menggunakan metode daftar .count () dan .index ()

coor = np.array([[10, 10], [12, 9], [10, 5], [12, 9]])
coor_tuple = [tuple(x) for x in coor]
unique_coor = sorted(set(coor_tuple), key=lambda x: coor_tuple.index(x))
unique_count = [coor_tuple.count(x) for x in unique_coor]
unique_index = [coor_tuple.index(x) for x in unique_coor]
mjp
sumber
0

Kita benar-benar dapat mengubah array numpy numerik mxn menjadi array string numpy mx 1, silakan coba menggunakan fungsi berikut, ia menyediakan count , inverse_idx dan lain-lain, seperti numpy.unique:

import numpy as np

def uniqueRow(a):
    #This function turn m x n numpy array into m x 1 numpy array storing 
    #string, and so the np.unique can be used

    #Input: an m x n numpy array (a)
    #Output unique m' x n numpy array (unique), inverse_indx, and counts 

    s = np.chararray((a.shape[0],1))
    s[:] = '-'

    b = (a).astype(np.str)

    s2 = np.expand_dims(b[:,0],axis=1) + s + np.expand_dims(b[:,1],axis=1)

    n = a.shape[1] - 2    

    for i in range(0,n):
         s2 = s2 + s + np.expand_dims(b[:,i+2],axis=1)

    s3, idx, inv_, c = np.unique(s2,return_index = True,  return_inverse = True, return_counts = True)

    return a[idx], inv_, c

Contoh:

A = np.array([[ 3.17   9.502  3.291],
  [ 9.984  2.773  6.852],
  [ 1.172  8.885  4.258],
  [ 9.73   7.518  3.227],
  [ 8.113  9.563  9.117],
  [ 9.984  2.773  6.852],
  [ 9.73   7.518  3.227]])

B, inv_, c = uniqueRow(A)

Results:

B:
[[ 1.172  8.885  4.258]
[ 3.17   9.502  3.291]
[ 8.113  9.563  9.117]
[ 9.73   7.518  3.227]
[ 9.984  2.773  6.852]]

inv_:
[3 4 1 0 2 4 0]

c:
[2 1 1 1 2]
Ting On Chan
sumber
-1

Mari kita dapatkan seluruh matriks numpy sebagai daftar, lalu letakkan duplikat dari daftar ini, dan akhirnya kembalikan daftar unik kita kembali ke matriks numpy:

matrix_as_list=data.tolist() 
matrix_as_list:
[[1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 0, 0], [0, 1, 1, 1, 0, 0], [1, 1, 1, 0, 0, 0], [1, 1, 1, 1, 1, 0]]

uniq_list=list()
uniq_list.append(matrix_as_list[0])

[uniq_list.append(item) for item in matrix_as_list if item not in uniq_list]

unique_matrix=np.array(uniq_list)
unique_matrix:
array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 0]])
Mahdi Ghelichi
sumber
-3

Solusi paling mudah adalah membuat baris-baris menjadi satu item dengan membuatnya menjadi string. Setiap baris kemudian dapat dibandingkan secara keseluruhan karena keunikannya menggunakan numpy. Solusi ini dapat digeneralisasi, Anda hanya perlu mengubah bentuk dan mengubah susunan array untuk kombinasi lainnya. Inilah solusi untuk masalah yang diberikan.

import numpy as np

original = np.array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])

uniques, index = np.unique([str(i) for i in original], return_index=True)
cleaned = original[index]
print(cleaned)    

Akan memberi:

 array([[0, 1, 1, 1, 0, 0],
        [1, 1, 1, 0, 0, 0],
        [1, 1, 1, 1, 1, 0]])

Kirim hadiah nobel saya melalui pos

Dave Pena
sumber
Sangat tidak efisien dan rawan kesalahan, misalnya dengan opsi cetak yang berbeda. Pilihan lain jelas lebih disukai.
Michael
-3
import numpy as np
original = np.array([[1, 1, 1, 0, 0, 0],
                     [0, 1, 1, 1, 0, 0],
                     [0, 1, 1, 1, 0, 0],
                     [1, 1, 1, 0, 0, 0],
                     [1, 1, 1, 1, 1, 0]])
# create a view that the subarray as tuple and return unique indeies.
_, unique_index = np.unique(original.view(original.dtype.descr * original.shape[1]),
                            return_index=True)
# get unique set
print(original[unique_index])
YoungLearnsToCoding
sumber