2013-04-25 5 views
9

У меня есть два 2D массивов одного и того же размератест на членство в 2d Numpy массива

a = array([[1,2],[3,4],[5,6]]) 
b = array([[1,2],[3,4],[7,8]]) 

Я хочу знать ряды Ь, которые в.

Так вывод должен быть:

array([ True, True, False], dtype=bool) 

без:

array([any(i == a) for i in b]) 

причиной а и б огромны.

Существует функция, которая делает это, но только для 1D массивов: in1d

+2

Каков фактический тип 'a' и' b'? – unutbu

+0

@unutbu float (можно установить значение int) – amine23

ответ

8

Что мы действительно хотели бы сделать, это использовать np.in1d ... за исключением того, что np.in1d работает только с 1-мерными массивами. Наши массивы многомерны. Тем не менее, мы можем вид массивы в качестве 1-мерного массива строк:

a = a.ravel().view((np.str, a.itemsize*a.shape[1])) 

Например,

In [15]: a = np.array([[1, 2], [2, 3], [1, 3]]) 

In [16]: a = a.ravel().view((np.str, a.itemsize*a.shape[1])) 

In [17]: a.dtype 
Out[17]: dtype('|S8') 

In [18]: a.shape 
Out[18]: (3,) 

In [19]: a 
Out[19]: 
array(['\x01\x00\x00\x00\x02', '\x02\x00\x00\x00\x03', 
     '\x01\x00\x00\x00\x03'], 
     dtype='|S8') 

Это делает каждую строку a строки. Теперь это просто вопрос закреплять это до к np.in1d:

def inNd(a, b, assume_unique=False): 
    a = np.asarray(a, order='C') 
    b = np.asarray(b, order='C') 
    a = a.ravel().view((np.str, a.itemsize * a.shape[1])) 
    b = b.ravel().view((np.str, b.itemsize * b.shape[1])) 
    return np.in1d(a, b, assume_unique) 

import numpy as np 


def inNd(a, b, assume_unique=False): 
    a = np.asarray(a, order='C') 
    b = np.asarray(b, order='C') 
    a = a.ravel().view((np.str, a.itemsize * a.shape[1])) 
    b = b.ravel().view((np.str, b.itemsize * b.shape[1])) 
    return np.in1d(a, b, assume_unique) 

tests = [ 
    (np.array([[1, 2], [2, 3], [1, 3]]), 
    np.array([[2, 2], [3, 3], [4, 4]]), 
    np.array([False, False, False])), 
    (np.array([[1, 2], [2, 2], [1, 3]]), 
    np.array([[2, 2], [3, 3], [4, 4]]), 
    np.array([True, False, False])), 
    (np.array([[1, 2], [3, 4], [5, 6]]), 
    np.array([[1, 2], [3, 4], [7, 8]]), 
    np.array([True, True, False])), 
    (np.array([[1, 2], [5, 6], [3, 4]]), 
    np.array([[1, 2], [5, 6], [7, 8]]), 
    np.array([True, True, False])), 
    (np.array([[-0.5, 2.5, -2, 100, 2], [5, 6, 7, 8, 9], [3, 4, 5, 6, 7]]), 
    np.array([[1.0, 2, 3, 4, 5], [5, 6, 7, 8, 9], [-0.5, 2.5, -2, 100, 2]]), 
    np.array([False, True, True])) 
] 

for a, b, answer in tests: 
    result = inNd(b, a) 
    try: 
     assert np.all(answer == result) 
    except AssertionError: 
     print('''\ 
a: 
{a} 
b: 
{b} 

answer: {answer} 
result: {result}'''.format(**locals())) 
     raise 
else: 
    print('Success!') 

дает

Success! 
+2

Посмотрите как массив записей, я думаю '.view (dtype ([('', a.dtype) * a.shape [1]])) 'это то, что вам нужно, и у вас есть тот же трюк, который работает для любого типа. – Jaime

+0

@Jaime: Я попробовал 'a1d = a.view ([('f0', 'int32'), ('f1', 'int32')])', 'b1d = ...', 'np.in1d ​​(a1d, b1d), но получил TypeError. Если вы увидите путь вокруг этого, я бы с удовольствием узнал. – unutbu

+0

Это также странно проваливает тестовый пример, который я опубликовал в качестве комментария к ответу @ Jan. – amine23

4
In [1]: import numpy as np 

In [2]: a = np.array([[1,2],[3,4]]) 

In [3]: b = np.array([[3,4],[1,2]]) 

In [5]: a = a[a[:,1].argsort(kind='mergesort')] 

In [6]: a = a[a[:,0].argsort(kind='mergesort')] 

In [7]: b = b[b[:,1].argsort(kind='mergesort')] 

In [8]: b = b[b[:,0].argsort(kind='mergesort')] 

In [9]: bInA1 = b[:,0] == a[:,0] 

In [10]: bInA2 = b[:,1] == a[:,1] 

In [11]: bInA = bInA1*bInA2 

In [12]: bInA 
Out[12]: array([ True, True], dtype=bool) 

должен это сделать ... Не уверен, является ли это еще эффективнее. Вам нужно сделать mergesort, так как другие методы нестабильны.

Edit:

Если у вас есть более чем в 2 колонки и, если строки сортируются уже, вы можете сделать

In [24]: bInA = np.array([True,]*a.shape[0]) 

In [25]: bInA 
Out[25]: array([ True, True], dtype=bool) 

In [26]: for k in range(a.shape[1]): 
    bInAk = b[:,k] == a[:,k] 
    bInA = bInAk*bInA 
    ....:  

In [27]: bInA 
Out[27]: array([ True, True], dtype=bool) 

Существует еще пространство для ускорения, так как в итерации, вы дон 't нужно проверить весь столбец, но только те записи, где текущий bInA - True.

+0

что если 'a = array ([[1,2], [2,3], [1,3]])' и 'b = array ([[2,3 ], [3,3], [4,4]])? – amine23

+0

yes .. Я только что проверил это - тогда это терпит неудачу ... Я пытаюсь исправить это – Jan

+0

Edit/Fix: Использование 'in1d' может завершиться неудачно, потому что оно не проверяет местоположение события ... Изменил его на '==' – Jan

0

модуль NumPy фактически может транслироваться через массив и сказать, какие части являются такие же, как и другие, и возвращать true, если они есть, и false, если они не являются:

import numpy as np 
a = np.array(([1,2],[3,4],[5,6])) #converting to a numpy array 
b = np.array(([1,2],[3,4],[7,8])) #converting to a numpy array 
new_array = a == b #creating a new boolean array from comparing a and b 

Теперь new_array выглядит следующим образом:

[[ True True] 
[ True True] 
[False False]] 

, но это не то, что вы хотите. Таким образом, вы можете транспонировать (перевернуть x и y) массив, а затем сравнить два ряда с затвором &.Это теперь будет создавать 1-D массив, который только возвращает истину, если оба столбца в строке истинны:

new_array = new_array.T #transposing 
result = new_array[0] & new_array[1] #comparing rows 

когда вы print result теперь вы получите то, что вы ищете:

[ True True False] 
+0

Что делать, если 'a = array ([[1,2], [3,4]])' и 'b = array ([[3,4], [1,2]])?? – amine23

+0

было не совсем ясно, что вы хотели иметь возможность сравнивать все. В вашем примере это явно не отображалось ... и вы хотите проверить, находится ли вложенный массив в b без использования цикла for? –

0

Если у вас есть как a=np.array([[1,2],[3,4],[5,6]]) л и b=np.array([[5,6],[1,2],[7,6]]), вы можете превратить их в комплексе 1-D массив:

c=a[:,0]+a[:,1]*1j 
d=b[:,0]+b[:,1]*1j 

весь этот материал в моем интерпретатором выглядит следующим образом :

>>> c=a[:,0]+a[:,1]*1j 
>>> c 
array([ 1.+2.j, 3.+4.j, 5.+6.j]) 
>>> d=b[:,0]+b[:,1]*1j 
>>> d 
array([ 5.+6.j, 1.+2.j, 7.+6.j]) 

И теперь, когда вы только 1D массив, вы можете легко сделать np.in1d(c,d) и Python даст вам:

>>> np.in1d(c,d) 
array([ True, False, True], dtype=bool) 

И с этим вы не нужны никакие петли, по крайней мере, с этими типами данных

Смежные вопросы