Numpy.array içindeki benzersiz satırları bulun


200

Birinde benzersiz satırlar bulmam gerekiyor numpy.array.

Örneğin:

>>> 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]])

Ben dizi üzerinde bir dizi oluşturmak ve döngü biliyorum, ama verimli bir saf numpyçözüm arıyorum . Veri türünü hükümsüz hale getirmenin bir yolu olduğuna inanıyorum ve sonra sadece kullanabilirim numpy.unique, ancak nasıl çalıştıracağını anlayamadım.


11
pandaların bir dataframe.drop_duplicates () yöntemi vardır. Bkz. Stackoverflow.com/questions/12322779/pandas-unique-dataframe ve pandas.pydata.org/pandas-docs/dev/generated/…
kodea

Teşekkür ederim, ama panda kullanamam.
Akavall


1
@Andy Hayden, başlığa rağmen, bu sorunun kopyası değil. Yine de codeape'in bağlantısı yineleniyor.
Wai Yip Tung

5
Bu özellik yerel olarak 1.13 sürümüne
Eric

Yanıtlar:


115

NumPy 1.13'ten itibaren, herhangi bir N-dim dizisindeki benzersiz değerlerin seçimi için eksen seçilebilir. Benzersiz satırlar elde etmek için aşağıdakiler yapılabilir:

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


12
Bu işleve dikkat edin. yinelenen satırlar kaldırılmış diziyinp.unique(list_cor, axis=0) alır ; diziyi orijinal dizide benzersiz olan öğelere filtrelemez . Buraya bakınız , örneğin ..
Brad Solomon

Satırdaki değerlerin sırasını yok sayan benzersiz satırlar istiyorsanız, orijinal diziyi önce doğrudan sütunlarda sıralayabilirsiniz:original_array.sort(axis=1)
mangecoeur

140

Yine olası bir çözüm daha

np.vstack({tuple(row) for row in a})

20
+1 Bu açık, kısa ve pitoniktir. Hız gerçek bir mesele olmadığı sürece, bu tür çözümler bu IMO'nun karmaşık, daha yüksek oylanan cevaplarına tercih etmelidir.
Bill Cheatham

3
Mükemmel! Kıvırcık parantez veya set () işlevi hile yapar.
Tian He

2
@Greg von Winckel Düzeni değiştirmeyen bir şey olmayan bir şey önerebilir misiniz?
Laschet Jain

Evet, ancak tek bir komutta değil: x = []; [x. x için değilse, r için t için (tuple (r)) ekleyin]; a_unique = dizi (x);
Greg von Winckel

1
Bir FutureWarning'i önlemek için, grubu aşağıdaki gibi bir listeye dönüştürün: np.vstack(list({tuple(row) for row in AIPbiased[i, :, :]})) FutureWarning: yığına diziler, liste veya grup gibi bir "dizi" türü olarak geçirilmelidir. Jeneratörler gibi sıralı olmayan yinelenebilirler için destek, NumPy 1.16'dan itibaren kullanımdan kaldırılmıştır ve gelecekte bir hataya neden olacaktır.
leermeester

111

Yapısal dizilerin kullanımı için başka bir seçenek void, tüm satırı tek bir öğeye birleştiren bir türün görünümünü kullanmaktır :

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]])

DÜZENLEME Eklendi np.ascontiguousarray@ Seberg önerilerini takip. Dizi bitişik değilse yöntem yavaşlar.

DÜZENLEME Yukarıdakiler, belki de netlik pahasına, aşağıdakileri yaparak hafifçe hızlandırılabilir:

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

Ayrıca, en azından benim sistemimde, performans akıllıca lexsort yönteminden daha düşük veya daha iyi:

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

3
Çok teşekkürler. Aradığım cevap bu, bu adımda neler olduğunu açıklayabilir misiniz b = a.view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))?
Akavall

3
@Akavall Verilerinizin np.voidtam satırdaki bayt sayısı boyutunda bir veri türü ile bir görünümü oluşturuyor . Bir np.uint8s dizisine sahipseniz ve np.uint16her iki sütunu tek bir sütun halinde birleştiren, ancak daha esnek olan s olarak görüyorsanız, elde ettiğiniz iki benzer .
Jaime

3
@Jaime, np.ascontiguousarraygenel olarak güvenli olmak için bir veya benzeri ekleyebilir misiniz (gerektiğinden biraz daha kısıtlayıcı olduğunu biliyorum, ancak ...). Görüntülemenin beklendiği gibi çalışması için satırların bitişik olması gerekir .
seberg

2
@ConstantineEvans Son zamanlarda yapılan bir eklemedir: numpy 1.6'da, np.uniquebir dizi np.voiddöndürme üzerinde çalışmaya çalışırken, bu tür için birleştirilmemiş birleştirme ile ilgili bir hata döndürür. 1.7 de iyi çalışıyor.
Jaime

9
Bu yöntem kayan nokta sayıları için kullanılırsa -0., eşit olarak karşılaştırılamayacak bir yakalama olduğunu +0., ancak bir elemanlar arası karşılaştırmanın -0.==+0.(ieee şamandıra standardında belirtildiği gibi) olacağını belirtmek gerekir . Bkz. Stackoverflow.com/questions/26782038/…
tom10

29

Bir dizi tuple veya benzer bir veri yapısına dönüştürme bellek maliyetinden kaçınmak istiyorsanız, numpy'nin yapılandırılmış dizilerinden yararlanabilirsiniz.

Hile, orijinal dizinizi, her öğenin orijinal dizinin bir satırına karşılık geldiği yapılandırılmış bir dizi olarak görüntülemektir. Bu bir kopya oluşturmaz ve oldukça etkilidir.

Kısa bir örnek olarak:

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

Neler olduğunu anlamak için aracı sonuçlara bir göz atın.

İşleri yapılandırılmış bir dizi olarak görüntüledikten sonra, dizideki her öğe orijinal dizinizdeki bir satırdır. (Temel olarak, tuples listesine benzer bir veri yapısıdır.)

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')])

Bir kez koştuğumuzda numpy.unique, yapılandırılmış bir dizi geri alırız:

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')])

Daha sonra "normal" bir dizi olarak görüntülememiz gerektiğini ( _son hesaplamanın sonucunu saklar ipython, bu yüzden görüyorsunuz _.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])

Ve sonra bir 2D diziye yeniden şekillendirin ( -1numpy'ye doğru satır sayısını hesaplamasını söyleyen, sütun sayısını veren bir yer tutucudur):

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]])

Açıkçası, daha özlü olmak istiyorsanız, şöyle yazabilirsiniz:

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)

Sonuç:

[[0 1 1 1 0 0]
 [1 1 1 0 0 0]
 [1 1 1 1 1 0]]

Bu aslında çok yavaş, neredeyse tuples kullanmak kadar yavaş görünüyor. Görünüşe göre, bu şekilde yapılandırılmış bir diziyi sıralamak yavaştır.
cge

3
@cge - Daha büyük boyutlu dizilerle deneyin. Evet, bir numpy dizisini sıralamak bir listeyi sıralamaktan daha yavaştır. Bununla birlikte, ndarraları kullandığınız çoğu durumda hız ana faktör değildir. Bellek kullanımı. Bir grup liste, bu çözümden çok daha fazla bellek kullanır . Yeterince büyük bir diziye sahip yeterli belleğiniz olsa bile, bunları bir tuples listesine dönüştürmek hız avantajından daha büyük bir yüke sahiptir.
Joe Kington

@cge - Ah, kullandığını fark etmedim lexsort. Bir tuples listesi kullanmaya atıfta bulunduğunuzu sanıyordum. Evet,lexsort muhtemelen bu durumda daha iyi bir seçenektir. Bunu unutmuş ve aşırı karmaşık bir çözüme atlamıştım.
Joe Kington

20

np.uniqueBen çalıştırdığınızda np.random.random(100).reshape(10,10)tüm benzersiz öğeleri döndürür, ancak benzersiz satırları istersiniz, bu yüzden önce onları tuples'e koymanız gerekir:

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

İstediğinizi yapmak için türleri değiştirdiğinizi görmenin tek yolu budur.


5
+1 Bu açık, kısa ve pitoniktir. Hız gerçek bir mesele olmadığı sürece, bu tür çözümler bu IMO'nun karmaşık, daha yüksek oylanan cevaplarına tercih etmelidir.
Bill Cheatham

Bunu kabul edilen çözüme tercih ederim. Hız benim için bir sorun değil, çünkü < 100her invokasyon başına sadece satırlarım var . Bu, sıralar üzerinde benzersiz performansın nasıl gerçekleştirildiğini tam olarak açıklar.
rayryeng

4
Bu aslında verilerim için çalışmıyor uniques, benzersiz öğeler içeriyor. Potansiyel olarak, beklenen şeklini yanlış anlıyorum array- burada daha kesin olabilir misiniz?
FooBar

@ ryan-saxe Ben bu pitonik gibi ama bu iyi bir çözüm değil çünkü döndü satır uniquessıralanır (ve bu nedenle satırlar farklıdır 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, düzleştirilmiş bir diziyi sıralayarak ve ardından her bir öğenin öncekine eşit olup olmadığına bakarak çalışır. Bu, düzleştirmeden manuel olarak yapılabilir:

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

Bu yöntem tuples kullanmaz ve burada verilen diğer yöntemlerden çok daha hızlı ve basit olmalıdır.

NOT: Bunun önceki bir sürümünde ['nin hemen ardından ind yoktu, bu da yanlış indekslerin kullanıldığı anlamına geliyor. Ayrıca, Joe Kington bunun çeşitli ara kopyalar yaptığı konusunda iyi bir noktaya değiniyor. Aşağıdaki yöntem, sıralı bir kopya oluşturarak ve ardından görünümlerini kullanarak daha az yapar:

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

Bu daha hızlıdır ve daha az bellek kullanır.

Ayrıca, dizide kaç boyut olduğuna bakılmaksızın bir ndarray'de benzersiz satırlar bulmak istiyorsanız , aşağıdakiler işe yarayacaktır:

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)))))]

İlginç bir sorun, rasgele boyutlu bir dizinin rasgele bir ekseni boyunca sıralamak / benzersiz yapmak istiyorsanız, daha zor olacak bir şey olurdu.

Düzenle:

Hız farklılıklarını göstermek için, cevaplarda açıklanan üç farklı yöntemin ipython'unda birkaç test yaptım. İle senin bu sürüm biraz daha hızlı olsa kesin a, çok fazla bir fark yoktur:

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

Bununla birlikte, daha büyük bir a ile bu sürüm çok, çok daha hızlı olur:

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

Çok hoş! Bununla birlikte, bir yan notta, birkaç ara kopya yapar. (örn a[ind[1:]]Öte yandan bir kopyası, vb olduğunu), çözüm genellikle 2-3x daha hızlı benim daha yukarı sen ram tükendi kadardır.
Joe Kington

İyi bir nokta. Anlaşıldığı üzere, sadece dizinleri kullanarak ara kopyaları alma girişimim, yöntemimin daha fazla bellek kullanmasını sağladı ve dizinin sıralı bir kopyasını yapmaktan daha yavaş sonuç verdi, çünkü a_sorted [1:] a_sorted'in bir kopyası değil .
cge

dtypeZamanlamalarınızda neler var ? Bence bunu yanlış anladın. Sistemimde, cevabımda np.uniqueaçıklandığı gibi çağrı yapmak , iki lezzetinizden birini kullanmaktan biraz daha hızlı np.lexsort. Ve benzersizleri bulmak için dizinin şekli varsa yaklaşık 5 kat daha hızlıdır (10000, 100). np.uniqueBazı (küçük) yürütme sürelerini kısaltmak için gerekenleri yeniden uygulamaya karar verseniz bile , her satırı tek bir nesneye daraltmak np.any, özellikle daha yüksek sütun sayıları için sütunların karşılaştırılmasını çağırmaktan daha hızlı karşılaştırmalar yapar .
Jaime

@cge: anahtar kelime argümanı almayan standart 'herhangi' yerine 'np.any' demek istediniz.
M. Toya

@Jaime - Sanırım dtypesadece a.dtype, yani Joe Kington tarafından yanıtında olduğu gibi, görüntülenen verilerin veri türü. Çok sayıda sütun varsa, işleri hızlı bir şekilde kullanmanın başka bir (kusurlu!) Yolu lexsortyalnızca birkaç sütuna göre sıralama yapmaktır. Hangi sütunların mükemmel şekilde sıralamak için yeterli varyans sağladığını bilmesi gerektiğinden, bu veriye özgüdür. Örn a.shape = (60000, 500): sort ilk 3 sütunlarda - ind = np.lexsort((a[:, 2], a[:, 1], a[:, 0])). Zaman tasarrufu oldukça önemlidir, ancak feragatname: tüm durumları yakalamayabilir - verilere bağlıdır.
n1k31t4

9

İşte @Greg pitonik cevabı için başka bir varyasyon

np.vstack(set(map(tuple, a)))

9

Ben hız için önerilen alternatifi karşılaştırmış ve şaşırtıcı bir şekilde, geçersiz görünüm buldum uniqueçözümü bile biraz daha hızlı numpy doğal daha uniqueile axisargüman. Hız arıyorsanız,

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

resim açıklamasını buraya girin


Grafiği yeniden oluşturmak için kod:

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
    )

1
Çok güzel bir cevap, küçük bir nokta:, vstack_dictasla bir dikte kullanmaz, kıvırcık parantezler bir set kavramadır ve bu nedenle davranışı neredeyse aynıdır vstatck_set. Yana vstack_dictperformans çizgisi fro grafik için eksik, bunun sadece kapsadığı ediliyor gibi görünüyor vstack_setonlar çok benzer olduğu için, performans grafiğinin!
Akavall

Cevap için teşekkürler. Ben sadece bir vstackvaryant içerecek şekilde geliştirdim .
Nico Schlömer

8

Bu cevapların hiçbirini beğenmedim, çünkü hiçbiri kayan nokta dizilerini doğrusal bir cebir veya vektör uzayı anlamında işlemez; burada iki satır “eşit”, “bazı within içinde” anlamına gelir. Tolerans eşiği olan bir cevap olan https://stackoverflow.com/a/26867764/500207 , eşiği hem öğe hem de ondalık olarak aldı hassasiyetle aldı, bu da bazı durumlarda işe yarıyor ancak matematiksel olarak genel gerçek vektör mesafesi.

İşte benim versiyonum:

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)

Yukarıdaki herkese açık alan adı işlevi scipy.spatial.distance.pdist , her bir satır çifti arasındaki Öklid (özelleştirilebilir) mesafesini bulmak için kullanılır . Daha sonra, birbirinin threshiçindeki satırları bulmak için her bir mesafeyi bir eskiyle karşılaştırır ve her birinden threshyalnızca bir satır döndürürthresh -cluster öğesinden .

Belirtildiği gibi, mesafenin metricÖklid olması gerekmez - (Manhattan normu) ve (vektörler arasındaki açı ) pdistdahil olmak üzere çeşitli mesafeleri hesaplayabilir .cityblockcosine

Eğer thresh=0(varsayılan), sonra satır bit tam “benzersiz” dikkate alınması gereken olmalıdır. threshÖlçekli makine hassasiyeti için diğer iyi değerler , yani,thresh=np.spacing(1)*1e3 .


En iyi cevap. Teşekkürler. Şimdiye kadar yazılan en (matematiksel) genelleştirilmiş cevaptır. Bir matrisi N-boyutlu uzayda bir veri noktaları kümesi veya örnekleri olarak görür ve aynı veya benzer noktaların bir koleksiyonunu bulur (benzerlik, Öklid mesafesi veya başka herhangi bir yöntemle tanımlanır). Bu noktalar, çakışan veri noktaları veya çok yakın mahalleler olabilir. Sonunda, aynı veya benzer noktaların bir koleksiyonu, aynı sete ait olan herhangi bir nokta ile (yukarıdaki cevapta bir ilk nokta ile) değiştirilir. Bu, bir nokta bulutundan fazlalığı azaltmaya yardımcı olur.
Sanchit

@Manchit aha, bu iyi bir nokta, "ilk" noktayı seçmek yerine (aslında etkili bir şekilde rastgele olabilir, çünkü Python'un noktaları a'ya nasıl depoladığına bağlıdır set), her büyük threshmahallenin temsilcisi olarak , işlev kullanıcı bu noktayı nasıl seçeceğini belirler, örneğin, "medyan" veya centroid'e en yakın noktayı kullanın, vb.
Ahmed Fasih

Elbette. Şüphesiz. İlk noktadan bahsetmiştim, çünkü programınızın yaptığı şey, ki bu tamamen iyi.
Sanchit

Sadece bir düzeltme - Yanlışlıkla yukarıda söyledim, her bir thresh-küme için seçilecek satırın, düzensiz doğası nedeniyle rastgele olacağını set. Benim açımdan bir brainfart var Tabii ki, setolan indeksler depolar küpe threshbu yüzden, -neighborhood findRows yapar her biri için, aslında karşılığında thresh-Küme, içinde ilk satır.
Ahmed Fasih

3

Neden drop_duplicatespandalardan kullanmıyorsunuz :

>>> 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

Aslında bu cevabı seviyorum. Tabii, doğrudan numpy kullanmıyor, ama bana göre hızlı olurken anlaması en kolay olanı.
noctilux

3

Numpy_indexed paketi (uyarı: Ben onun yazarım) güzel Meydanı Jaime tarafından gönderildi çözümü test edilmiş arayüz, artı çok daha fazla özellik sarar:

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

1

np.unique eserlerine tuples listesi verildi:

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

Listelerin bir listesi ile TypeError: unhashable type: 'list'


benimki üzerinde çalışmıyor gibi görünüyor. Her demet iki kayan sayı yerine iki dizedir
mjp

çalışmıyor, tuples değil elemanların bir listesini döndürür
Mohanad Kaleia

1

Bu sayfadaki cevaba dayanarak unique(input,'rows'), benzersizliği kontrol etmek için toleransı kabul eden ek özellik ile MATLAB işlevinin yeteneğini çoğaltan bir işlev yazdım . Ayrıca, c = data[ia,:]ve gibi endeksleri döndürür data = c[ic,:]. Herhangi bir tutarsızlık veya hata görüyorsanız lütfen bildirin.

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

1

@Jaime mükemmel cevabının ötesinde, bir satırı daraltmanın başka bir yolu da eşittir a.strides[0]( aC-bitişik olduğu varsayılır) kullanır a.dtype.itemsize*a.shape[0]. Ayrıca void(n)bir kısayol dtype((void,n)). sonunda bu en kısa sürüme ulaşıyoruz:

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

İçin

[[0 1 1 1 0 0]
 [1 1 1 0 0 0]
 [1 1 1 1 1 0]]

0

3D veya daha yüksek çok boyutlu iç içe diziler gibi genel amaçlar için şunu deneyin:

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:])

2D veri kümenizi karşılayan:

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)

verir:

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

Ama aynı zamanda 3D diziler:

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)

verir:

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

Kullanılması unique return_indexJaime olarak geçen yapmalıdır gelmez returnhat daha basit. Orjinali arsağ eksende endeksleyin .
hpaulj

0

Bu cevapların hiçbiri benim için işe yaramadı. Benzersiz satırlarımın sayıları değil, dizeleri içerdiğini varsayıyorum. Ancak başka bir evreden gelen bu cevap işe yaradı:

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

.Count () ve .index () listesinin yöntemlerini kullanabilirsiniz

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]

0

Aslında mxn sayısal numpy dizisini mx 1 numpy dize dizisine dönüştürebiliriz, lütfen aşağıdaki işlevi kullanmayı deneyin , numpy.unique gibi count , inverse_idx vb. Sağlar:

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

Misal:

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]

-1

Numpy matrisinin tamamını bir liste olarak alalım, ardından bu listeden kopyaları bırakalım ve son olarak benzersiz listemizi tekrar numpy matrisine döndürelim:

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]])

-3

En basit çözüm, satırları dizeler yaparak tek bir öğe yapmaktır. Daha sonra her satır numpy kullanarak benzersizliği için bir bütün olarak karşılaştırılabilir. Bu çözüm genelleştirilebilir, sadece dizinizi diğer kombinasyonlar için yeniden şekillendirmeniz ve aktarmanız gerekir. İşte size sunulan sorunun çözümü.

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)    

Verecek:

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

Nobel ödülümü postayla gönder


Çok verimsiz ve hata eğilimli, örneğin farklı yazdırma seçeneklerinde. Diğer seçenekler açıkça tercih edilir.
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])
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.