Tìm các hàng độc đáo trong numpy.array


199

Tôi cần tìm các hàng duy nhất trong a numpy.array.

Ví dụ:

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

Tôi biết rằng tôi có thể tạo một tập hợp và lặp trên mảng, nhưng tôi đang tìm kiếm một numpygiải pháp thuần túy hiệu quả . Tôi tin rằng có một cách để đặt loại dữ liệu thành vô hiệu hóa và sau đó tôi chỉ có thể sử dụng numpy.unique, nhưng tôi không thể tìm ra cách làm cho nó hoạt động.


11
gấu trúc có một phương thức dataframe.drop_d repeatates (). Xem stackoverflow.com/questions/12322779/pandas-unique-dataframepandas.pydata.org/pandas-docs/dev/generated/ trộm
codeape

Cảm ơn bạn, nhưng tôi không thể sử dụng gấu trúc.
Akavall


1
@Andy Hayden, mặc dù tiêu đề, nó không phải là một bản sao cho câu hỏi này. liên kết của codeape là một bản sao mặc dù.
Wai Yip Tung

5
Tính năng này sắp có tới 1.13: github.com/numpy/numpy/pull/7742
Eric

Câu trả lời:


115

Kể từ NumPy 1.13, người ta có thể chỉ cần chọn trục để chọn các giá trị duy nhất trong bất kỳ mảng N-dim nào. Để có được các hàng duy nhất, người ta có thể làm:

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


12
Cẩn thận với chức năng này. np.unique(list_cor, axis=0)đưa bạn mảng với các hàng trùng lặp được loại bỏ ; nó không lọc mảng thành các phần tử duy nhất trong mảng ban đầu . Xem ở đây , ví dụ ..
Brad Solomon

Lưu ý rằng nếu bạn muốn các hàng duy nhất bỏ qua thứ tự các giá trị trong hàng, bạn có thể sắp xếp mảng ban đầu trong các cột trực tiếp trước:original_array.sort(axis=1)
mangecoeur

140

Một giải pháp khả thi khác

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

20
+1 Điều này rõ ràng, ngắn và pythonic. Trừ khi tốc độ là một vấn đề thực sự, các loại giải pháp này nên được ưu tiên hơn các câu trả lời phức tạp, được bình chọn cao hơn cho câu hỏi này IMO.
Bill Cheatham

3
Thông minh! Niềng răng xoăn hoặc hàm set () thực hiện thủ thuật.
Tian He

2
@Greg von Winckel Bạn có thể đề xuất một cái gì đó không phải thứ gì đó không thay đổi thứ tự.
Laschet Jain

Có, nhưng không phải trong một lệnh duy nhất: x = []; [x.append (tuple (r)) cho r trong a nếu tuple (r) không ở x]; a_unique = mảng (x);
Greg von Winckel

1
Để tránh FutureWarning, hãy chuyển đổi tập hợp thành một danh sách như: np.vstack(list({tuple(row) for row in AIPbiased[i, :, :]})) FutureWarning: mảng thành ngăn xếp phải được chuyển qua dưới dạng loại "chuỗi" như danh sách hoặc bộ dữ liệu. Hỗ trợ cho các lần lặp không theo thứ tự như các trình tạo không được chấp nhận kể từ NumPy 1.16 và sẽ gây ra lỗi trong tương lai.
leermeester

111

Một tùy chọn khác cho việc sử dụng các mảng có cấu trúc là sử dụng chế độ xem voidkiểu tham gia toàn bộ hàng vào một mục:

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 Đã thêm np.ascontiguousarraytheo khuyến nghị của @ seberg. Điều này sẽ làm chậm phương thức nếu mảng không liền kề.

EDIT Ở trên có thể được tăng tốc một chút, có lẽ với chi phí rõ ràng, bằng cách làm:

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

Ngoài ra, ít nhất là trên hệ thống của tôi, hiệu năng của nó là ngang bằng, hoặc thậm chí tốt hơn so với phương pháp 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

3
Cảm ơn rất nhiều. Đây là câu trả lời mà tôi đang tìm kiếm, bạn có thể giải thích những gì đang diễn ra trong bước này : b = a.view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))?
Akavall

3
@Akavall Nó đang tạo chế độ xem dữ liệu của bạn với np.voidloại dữ liệu có kích thước bằng số byte trong một hàng đầy đủ. Nó giống như hai thứ bạn nhận được nếu bạn có một mảng np.uint8s và xem nó là np.uint16s, kết hợp mỗi hai cột thành một cột duy nhất, nhưng linh hoạt hơn.
Jaime

3
@Jaime, bạn có thể thêm một np.ascontiguousarrayhoặc tương tự để nói chung là an toàn không (tôi biết nó hạn chế hơn một chút thì cần thiết, nhưng ...). Các hàng phải liền kề nhau để xem hoạt động như mong đợi.
seberg

2
@ConstantineEvans Đây là một bổ sung gần đây: trong numpy 1.6, cố gắng chạy np.uniquetrên một mảng np.voidtrả về một lỗi liên quan đến sáp nhập không được thực hiện cho loại đó. Nó hoạt động tốt trong 1.7 mặc dù.
Jaime

9
Điều đáng chú ý là nếu phương pháp này được sử dụng cho các số dấu phẩy động thì có một điểm bắt -0.không so sánh bằng +0., trong khi so sánh theo từng yếu tố sẽ có -0.==+0.(như được chỉ định bởi tiêu chuẩn nổi ieee). Xem stackoverflow.com/questions/26782038/ khăn
tom10

29

Nếu bạn muốn tránh chi phí bộ nhớ khi chuyển đổi thành một loạt các bộ dữ liệu hoặc cấu trúc dữ liệu tương tự khác, bạn có thể khai thác các mảng có cấu trúc của numpy.

Mẹo nhỏ là xem mảng ban đầu của bạn dưới dạng một mảng có cấu trúc, trong đó mỗi mục tương ứng với một hàng của mảng ban đầu. Điều này không tạo ra một bản sao, và khá hiệu quả.

Ví dụ nhanh:

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

Để hiểu những gì đang xảy ra, hãy xem kết quả trung gian.

Khi chúng ta xem mọi thứ như một mảng có cấu trúc, mỗi phần tử trong mảng là một hàng trong mảng ban đầu của bạn. (Về cơ bản, đây là cấu trúc dữ liệu tương tự như danh sách các bộ dữ liệu.)

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

Khi chúng tôi chạy numpy.unique, chúng tôi sẽ lấy lại một mảng có cấu trúc:

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

Sau đó chúng ta cần xem như một mảng "bình thường" ( _lưu trữ kết quả của phép tính cuối cùng ipython, đó là lý do tại sao bạn nhìn thấy _.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])

Và sau đó định hình lại thành một mảng 2D ( -1là một trình giữ chỗ cho numpy để tính toán số lượng hàng chính xác, đưa ra số lượng cột):

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

Rõ ràng, nếu bạn muốn ngắn gọn hơn, bạn có thể viết nó dưới dạng:

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)

Kết quả nào trong:

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

Điều này thực sự có vẻ rất chậm, gần như chậm như sử dụng bộ dữ liệu. Sắp xếp một mảng có cấu trúc như thế này là chậm, rõ ràng.
cge ngày

3
@cge - Hãy thử nó với các mảng có kích thước lớn hơn. Có, sắp xếp một mảng numpy chậm hơn so với sắp xếp một danh sách. Tốc độ không phải là sự cân nhắc chính trong hầu hết các trường hợp khi bạn đang sử dụng ndarrays. Đó là sử dụng bộ nhớ. Một danh sách các bộ dữ liệu sẽ sử dụng bộ nhớ lớn hơn nhiều so với giải pháp này. Ngay cả khi bạn có đủ bộ nhớ, với một mảng lớn hợp lý, việc chuyển đổi nó thành một danh sách các bộ dữ liệu có chi phí lớn hơn lợi thế về tốc độ.
Joe Kington

@cge - Ah, tôi không nhận thấy bạn đang sử dụng lexsort. Tôi nghĩ rằng bạn đang đề cập đến việc sử dụng một danh sách các bộ dữ liệu. Vâng, lexsortcó lẽ là lựa chọn tốt hơn trong trường hợp này. Tôi đã quên nó, và nhảy đến một giải pháp quá phức tạp.
Joe Kington

20

np.uniqueKhi tôi chạy nó np.random.random(100).reshape(10,10)sẽ trả về tất cả các phần tử riêng lẻ, nhưng bạn muốn các hàng duy nhất, vì vậy trước tiên bạn cần đặt chúng vào các bộ dữ liệu:

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

Đó là cách duy nhất tôi thấy bạn thay đổi các loại để làm những gì bạn muốn và tôi không chắc liệu danh sách lặp để thay đổi thành tuples có ổn không với việc "không lặp qua"


5
+1 Điều này rõ ràng, ngắn và pythonic. Trừ khi tốc độ là một vấn đề thực sự, các loại giải pháp này nên được ưu tiên hơn các câu trả lời phức tạp, được bình chọn cao hơn cho câu hỏi này IMO.
Bill Cheatham

Tôi thích điều này hơn các giải pháp được chấp nhận. Tốc độ không phải là vấn đề đối với tôi vì tôi chỉ có thể có < 100hàng cho mỗi lần gọi. Điều này mô tả chính xác cách thực hiện duy nhất trên các hàng được thực hiện.
rayryeng

4
Điều này thực sự không hoạt động cho dữ liệu của tôi, uniqueschứa các yếu tố độc đáo. Có khả năng tôi hiểu nhầm hình dạng dự kiến ​​của array- bạn có thể chính xác hơn ở đây không?
FooBar

@ ryan-saxe Tôi thích rằng đây là pythonic nhưng đây không phải là giải pháp tốt vì hàng được trả về uniquesđược sắp xếp (và do đó khác với các hàng trong 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 hoạt động bằng cách sắp xếp một mảng dẹt, sau đó xem xét từng mục có bằng với trước đó không. Điều này có thể được thực hiện thủ công mà không làm phẳng:

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

Phương pháp này không sử dụng bộ dữ liệu, và sẽ nhanh hơn và đơn giản hơn nhiều so với các phương pháp khác được đưa ra ở đây.

LƯU Ý: Phiên bản trước của phiên bản này không có quyền sau khi [, có nghĩa là các chỉ số sai đã được sử dụng. Ngoài ra, Joe Kington cũng nói rõ rằng điều này không tạo ra nhiều bản sao trung gian. Phương pháp sau đây làm cho ít hơn, bằng cách tạo một bản sao được sắp xếp và sau đó sử dụng các khung nhìn của nó:

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

Điều này nhanh hơn và sử dụng ít bộ nhớ hơn.

Ngoài ra, nếu bạn muốn tìm các hàng duy nhất trong một ndarray bất kể có bao nhiêu kích thước trong mảng, thì những điều sau đây sẽ hoạt động:

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

Một vấn đề thú vị còn lại sẽ là nếu bạn muốn sắp xếp / duy nhất dọc theo trục tùy ý của một mảng kích thước tùy ý, điều gì đó sẽ khó khăn hơn.

Biên tập:

Để chứng minh sự khác biệt về tốc độ, tôi đã chạy một vài thử nghiệm trong ipython về ba phương pháp khác nhau được mô tả trong các câu trả lời. Với chính xác của bạn , không có quá nhiều sự khác biệt, mặc dù phiên bản này nhanh hơn một chút:

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

Tuy nhiên, với phiên bản lớn hơn, phiên bản này kết thúc nhanh hơn nhiều:

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

Rất đẹp! Tuy nhiên, trên một lưu ý phụ, nó tạo ra một số bản sao trung gian. (ví dụ: a[ind[1:]]bản sao, v.v.) Mặt khác, giải pháp của bạn thường nhanh hơn 2-3 lần so với của tôi cho đến khi bạn hết ram.
Joe Kington

Điểm tốt. Hóa ra, việc tôi cố gắng loại bỏ các bản sao trung gian bằng cách chỉ sử dụng các chỉ mục đã khiến phương thức của tôi sử dụng nhiều bộ nhớ hơn và kết thúc chậm hơn so với việc tạo một bản sao được sắp xếp của mảng, vì a_soped [1:] không phải là bản sao của a_sort .
cge

Thời dtypegian của bạn là gì? Tôi nghĩ rằng bạn đã sai một. Trên hệ thống của tôi, gọi np.uniquenhư được mô tả trong câu trả lời của tôi nhanh hơn một chút so với sử dụng một trong hai hương vị của bạn np.lexsort. Và nó nhanh hơn khoảng 5 lần nếu mảng tìm thấy đồ cổ có hình dạng (10000, 100). Ngay cả khi bạn quyết định thực hiện lại những gì np.uniquecần cắt bớt một số thời gian thực hiện (nhỏ), việc thu gọn mỗi hàng thành một đối tượng sẽ chạy so sánh nhanh hơn so với việc phải gọi np.anyso sánh các cột, đặc biệt là cho số lượng cột cao hơn.
Jaime

@cge: bạn có thể có nghĩa là 'np.any' thay vì tiêu chuẩn 'bất kỳ' nào không lấy đối số từ khóa.
M. Toya

@Jaime - Tôi tin dtypelà chỉ a.dtype, tức là kiểu dữ liệu của dữ liệu đang được xem, như đã được Joe Kington thực hiện trong câu trả lời của mình. Nếu có nhiều cột, một cách khác (không hoàn hảo!) Để giữ mọi thứ nhanh bằng cách sử dụng lexsortlà chỉ sắp xếp trên một vài cột. Đây là dữ liệu cụ thể vì người ta cần biết cột nào cung cấp đủ phương sai để sắp xếp hoàn hảo. Ví dụ: a.shape = (60000, 500)sắp xếp trên 3 cột đầu tiên : ind = np.lexsort((a[:, 2], a[:, 1], a[:, 0])). Tiết kiệm thời gian là khá đáng kể, nhưng từ chối trách nhiệm một lần nữa: nó có thể không bắt được tất cả các trường hợp - nó phụ thuộc vào dữ liệu.
n1k31t4

9

Đây là một biến thể khác cho câu trả lời pythonic @Greg

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

9

Tôi đã so sánh giải pháp thay thế được đề xuất cho tốc độ và thấy rằng, thật đáng ngạc nhiên, uniquegiải pháp chế độ xem void thậm chí còn nhanh hơn một chút so với bản gốc của numpy uniquevới axisđối số. Nếu bạn đang tìm kiếm tốc độ, bạn sẽ muốn

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

nhập mô tả hình ảnh ở đây


Mã để tái tạo cốt truyện:

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
Câu trả lời rất hay, một điểm nhỏ : vstack_dict, không bao giờ sử dụng dict, niềng răng xoăn là một cách hiểu được thiết lập, và do đó hành vi của nó gần giống với vstatck_set. Vì, vstack_dictdòng hiệu suất bị thiếu cho biểu đồ fro, có vẻ như nó chỉ được bao phủ bởi vstack_setbiểu đồ hiệu suất, vì chúng rất giống nhau!
Akavall

Cảm ơn vi đa trả lơi. Tôi đã cải thiện cốt truyện chỉ bao gồm một vstackbiến thể.
Nico Schlömer

8

Tôi không thích bất kỳ câu trả lời nào trong số những câu trả lời này bởi vì không có câu nào xử lý các mảng dấu phẩy động theo nghĩa đại số tuyến tính hoặc không gian vectơ, trong đó hai hàng là bằng nhau có nghĩa là Hồi trong một số 𝜀. Câu trả lời có ngưỡng dung sai, https://stackoverflow.com/a/26867764/500207 , lấy ngưỡng là chính xác cả yếu tố và thập phân , hoạt động trong một số trường hợp nhưng không chung chung về mặt toán học như một khoảng cách vectơ đúng.

Đây là phiên bản của tôi:

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)

Hàm miền công cộng ở trên sử dụng scipy.spatial.distance.pdistđể tìm khoảng cách Euclide (có thể tùy chỉnh) giữa mỗi cặp hàng. Sau đó, nó so sánh từng khoảng cách với một khoảng cách threshcũ để tìm các hàng nằm trong threshnhau và trả về chỉ một hàng từ mỗi thresh-cluster.

Như đã nói, khoảng cách metrickhông cần phải là Euclidean pdistcó thể tính toán khoảng cách lặt vặt bao gồm cityblock(Manhattan-Norm) và cosine(góc giữa các vectơ).

Nếu thresh=0(mặc định), thì các hàng phải chính xác một chút để được coi là duy nhất. Các giá trị tốt khác để threshsử dụng độ chính xác của máy được chia tỷ lệ, nghĩa là , thresh=np.spacing(1)*1e3.


Câu trả lời tốt nhất. Cảm ơn. Đó là câu trả lời khái quát nhất (về mặt toán học) được viết cho đến nay. Nó coi ma trận là một tập hợp các điểm dữ liệu hoặc mẫu trong không gian N chiều và tìm một tập hợp các điểm giống nhau hoặc tương tự (độ tương tự được xác định bởi khoảng cách Euclide hoặc bằng bất kỳ phương pháp nào khác). Những điểm này có thể chồng chéo các điểm dữ liệu hoặc các vùng lân cận rất gần. Cuối cùng, một tập hợp các điểm giống nhau hoặc tương tự được thay thế bằng bất kỳ điểm nào (trong câu trả lời trên bằng một điểm đầu tiên) thuộc cùng một tập hợp. Điều này giúp giảm sự dư thừa từ một đám mây điểm.
Sanchit

@Sanchit aha, đó là một điểm tốt, thay vì chọn điểm đầu tiên của Google (thực ra nó có thể là ngẫu nhiên, vì nó phụ thuộc vào cách Python lưu trữ các điểm trong a set) như là đại diện của từng threshvùng lân cận, hàm có thể cho phép người dùng chỉ định cách chọn điểm đó, ví dụ: sử dụng điểm trung bình trực tiếp hoặc điểm gần trung tâm nhất, v.v.
Ahmed Fasih

Chắc chắn rồi. Không còn nghi ngờ gì nữa. Tôi chỉ đề cập đến điểm đầu tiên vì đây là những gì chương trình của bạn đang làm mà hoàn toàn tốt.
Sanchit

Chỉ là một chỉnh sửa tôi đã nói sai ở trên rằng hàng sẽ được chọn cho mỗi người threshđộc quyền sẽ là ngẫu nhiên vì tính chất không có thứ tự của set. Tất nhiên đó là một brainfart trên một phần của tôi, các setcửa hàng tuples các chỉ số đó đang trong thresh-neighborhood, vì vậy đây findRows không trên thực tế trở lại, đối với mỗi thresh-cluster, hàng đầu tiên trong đó.
Ahmed Fasih

3

Tại sao không sử dụng drop_duplicatestừ gấu trúc:

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

Tôi thực sự thích câu trả lời này. Chắc chắn, nó không sử dụng trực tiếp numpy, nhưng với tôi đó là cách dễ hiểu nhất trong khi nhanh.
noctilux

3

Các numpy_indexed gói (từ chối trách nhiệm: Tôi là tác giả của nó) kết thúc tốt đẹp giải pháp đăng bởi Jaime trong một tốt đẹp và giao diện thử nghiệm, cộng với nhiều tính năng hơn:

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

1

np.unique làm việc đưa ra một danh sách các bộ dữ liệu:

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

Với một danh sách các danh sách, nó tăng TypeError: unhashable type: 'list'


dường như không làm việc với tôi. Mỗi bộ là hai chuỗi thay vì hai số float
mjp

không hoạt động, nó trả về một danh sách các yếu tố không phải bộ dữ liệu
Mohanad Kaleia

1

Dựa trên câu trả lời trong trang này, tôi đã viết một hàm sao chép khả năng của unique(input,'rows')hàm MATLAB , với tính năng bổ sung để chấp nhận dung sai cho việc kiểm tra tính duy nhất. Nó cũng trả về các chỉ số như vậy c = data[ia,:]data = c[ic,:]. Vui lòng báo cáo nếu bạn thấy bất kỳ sự khác biệt hoặc lỗi.

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

Ngoài câu trả lời xuất sắc @Jaime, một cách khác để thu gọn một hàng là sử dụng a.strides[0](giả sử alà tiếp giáp C) tương đương với a.dtype.itemsize*a.shape[0]. Hơn nữa void(n)là một phím tắt cho dtype((void,n)). Cuối cùng chúng ta cũng đến phiên bản ngắn nhất này:

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

Dành cho

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

0

Đối với mục đích chung như các mảng lồng nhau đa chiều 3D hoặc cao hơn, hãy thử điều này:

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

thỏa mãn dữ liệu 2D của bạn:

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)

cho:

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

Nhưng cũng có mảng 3D như:

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)

cho:

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

Sử dụng unique return_indexnhư Jaime sẽ làm cho returndòng cuối cùng đơn giản hơn. Chỉ cần lập chỉ mục ban đầu artrên trục phải.
hpaulj

0

Không có câu trả lời nào trong số này làm việc cho tôi. Tôi giả sử là các hàng duy nhất của tôi chứa các chuỗi và không phải là số. Tuy nhiên, câu trả lời từ một chủ đề khác đã làm việc:

Nguồn: https://stackoverflow.com/a/38461043/5402386

Bạn có thể sử dụng các phương thức của danh sách .count () và .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]

0

Chúng tôi thực sự có thể biến mảng numpy số mxn thành mảng chuỗi mx 1 numpy, vui lòng thử sử dụng hàm sau, nó cung cấp số đếm , inverse_idx , v.v., giống như 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

Thí dụ:

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

Cho phép lấy toàn bộ ma trận numpy làm danh sách, sau đó thả các bản sao khỏi danh sách này và cuối cùng trả lại danh sách duy nhất của chúng ta trở lại thành ma trận 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]])

-3

Giải pháp đơn giản nhất là biến các hàng thành một mục duy nhất bằng cách tạo chúng thành chuỗi. Mỗi hàng sau đó có thể được so sánh một cách tổng thể vì tính độc đáo của nó bằng cách sử dụng numpy. Giải pháp này có tính khái quát - bạn có thể chỉ cần định hình lại và hoán chuyển mảng của mình cho các kết hợp khác. Đây là giải pháp cho vấn đề được cung cấp.

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)    

Sẽ cho:

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

Gửi giải thưởng cao quý của tôi trong thư


Rất không hiệu quả và dễ bị lỗi, ví dụ với các tùy chọn in khác nhau. Các tùy chọn khác rõ ràng là thích hợp hơn.
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])
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.