2016-11-18 4 views
7

У меня есть 3D-массив numpy, и я хочу только уникальные 2D-под-массивы.Уникальная 2D-поддиапазона Numpy

Вход:

[[[ 1 2] 
    [ 3 4]] 

[[ 5 6] 
    [ 7 8]] 

[[ 9 10] 
    [11 12]] 

[[ 5 6] 
    [ 7 8]]] 

Выход:

[[[ 1 2] 
    [ 3 4]] 

[[ 5 6] 
    [ 7 8]] 

[[ 9 10] 
    [11 12]]] 

Я попытался конвертировано подмассивы в строку (ToString() метод), а затем использовать np.unique, но после преобразования в Numpy массива, он удалил последние байты в \ x00, поэтому я не могу преобразовать его с помощью np.fromstring().

Пример:

import numpy as np 
a = np.array([[[1,2],[3,4]],[[5,6],[7,8]],[[9,10],[11,12]],[[5,6],[7,8]]]) 
b = [x.tostring() for x in a] 
print(b) 
c = np.array(b) 
print(c) 
print(np.array([np.fromstring(x) for x in c])) 

Выход:

[b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00', b'\x05\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x08\x00\x00\x00', b'\t\x00\x00\x00\n\x00\x00\x00\x0b\x00\x00\x00\x0c\x00\x00\x00', b'\x05\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x08\x00\x00\x00'] 
[b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04' 
b'\x05\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x08' 
b'\t\x00\x00\x00\n\x00\x00\x00\x0b\x00\x00\x00\x0c' 
b'\x05\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x08'] 

--------------------------------------------------------------------------- 
ValueError        Traceback (most recent call last) 
<ipython-input-86-6772b096689f> in <module>() 
     5 c = np.array(b) 
     6 print(c) 
----> 7 print(np.array([np.fromstring(x) for x in c])) 

<ipython-input-86-6772b096689f> in <listcomp>(.0) 
     5 c = np.array(b) 
     6 print(c) 
----> 7 print(np.array([np.fromstring(x) for x in c])) 

ValueError: string size must be a multiple of element size 

Я также попытался вид, но я действительно не знаю, как использовать его. Вы можете мне помочь?

+1

Это [ новая функция] (https://github.com/numpy/numpy/pull/7742) в предстоящем 1.13, как 'np.unique (a, axis = 0)'. Вы можете просто скопировать новую реализацию и использовать ее в своем коде, так как версия 1.13 еще не выпущена – Eric

ответ

3

Использование @Jaime's post, чтобы решить наш случай обнаружения уникальных 2D подмассива, я пришел с этим решением, которое в основном добавляет перепрофилирование к view шаг -

def unique2D_subarray(a): 
    dtype1 = np.dtype((np.void, a.dtype.itemsize * np.prod(a.shape[1:]))) 
    b = np.ascontiguousarray(a.reshape(a.shape[0],-1)).view(dtype1) 
    return a[np.unique(b, return_index=1)[1]] 

Пример запуска -

In [62]: a 
Out[62]: 
array([[[ 1, 2], 
     [ 3, 4]], 

     [[ 5, 6], 
     [ 7, 8]], 

     [[ 9, 10], 
     [11, 12]], 

     [[ 5, 6], 
     [ 7, 8]]]) 

In [63]: unique2D_subarray(a) 
Out[63]: 
array([[[ 1, 2], 
     [ 3, 4]], 

     [[ 5, 6], 
     [ 7, 8]], 

     [[ 9, 10], 
     [11, 12]]]) 
+0

Спасибо за ваш ответ! Итак, если я хорошо понял, dtype задает последовательность байтов (не реально любого типа) размера a.dtype.itemsize * размер подмассива? И непрерывный массив нужен, потому что dtype указан как последовательность байтов? Мне очень жаль дублированного вопроса, но я не понимаю из сообщения @ Хайме. –

+0

@ Peťan Ну, вы правы в первой части. Во второй части о необходимости быть «смежным». Я тоже не слишком разбираюсь в этом. Возможно, стоит опубликовать комментарий к этому сообщению, я думаю. Если я должен угадать, я бы сказал, что ваша вторая часть кажется логичной, но да, эти две части связаны. – Divakar

1

Одно решение было бы использовать набор, чтобы отслеживать, какие суб массивы вы видели:

seen = set([]) 
new_a = [] 

for j in a: 
    f = tuple(list(j.flatten())) 
    if f not in seen: 
     new_a.append(j) 
     seen.add(f) 

print np.array(new_a) 

Или используя NumPy только:

print np.unique(a).reshape((len(unique)/4, 2, 2)) 

>>> [[[ 1 2] 
     [ 3 4]] 

    [[ 5 6] 
     [ 7 8]] 

    [[ 9 10] 
     [11 12]]] 
+2

Итак, [этот ответ] (http://stackoverflow.com/a/22941699/102441) от комментария, указанного выше – Eric

+0

Вы потеряли порядок вспомогательных массивов с таким ответом – kezzos

+0

Если только скопировать массив в набор и затем вернуться к массиву, порядок будет потерян, это правда, но сделано так, как это делается в приведенном выше коде, t быть потерянным. –

1

В numpy_indexed пакет (отказ от ответственности: Я его автор) предназначен для эффективного и векторизованного использования таких операций:

import numpy_indexed as npi 
npi.unique(a) 
Смежные вопросы