Найти разность множеств между двумя большими массивами (матрицами) в Python
У меня есть два больших двумерных массива, и я хотел бы найти их разность наборов, принимая их строки в качестве элементов. В Matlab код для этого будет setdiff(A,B,'rows')
, Массивы достаточно велики, чтобы очевидные циклические методы, о которых я мог подумать, занимают слишком много времени.
3 ответа
Это должно работать, но в настоящее время не работает в 1.6.1 из-за недоступной сортировки слиянием для создаваемого представления. Он работает в предварительной версии 1.7.0. Это должен быть самый быстрый способ, так как представления не должны копировать какую-либо память:
>>> import numpy as np
>>> a1 = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> a2 = np.array([[4,5,6],[7,8,9],[1,1,1]])
>>> a1_rows = a1.view([('', a1.dtype)] * a1.shape[1])
>>> a2_rows = a2.view([('', a2.dtype)] * a2.shape[1])
>>> np.setdiff1d(a1_rows, a2_rows).view(a1.dtype).reshape(-1, a1.shape[1])
array([[1, 2, 3]])
Вы можете сделать это в Python, но это может быть медленно:
>>> import numpy as np
>>> a1 = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> a2 = np.array([[4,5,6],[7,8,9],[1,1,1]])
>>> a1_rows = set(map(tuple, a1))
>>> a2_rows = set(map(tuple, a2))
>>> a1_rows.difference(a2_rows)
set([(1, 2, 3)])
Вот хорошая альтернатива чисто NumPy решение, которое работает для 1.6.1. Он создает промежуточный массив, так что это может или не может быть проблемой для вас. Это также не зависит от какого-либо ускорения от отсортированного массива или нет (как setdiff
скорее всего).
from numpy import *
# Create some sample arrays
A =random.randint(0,5,(10,3))
B =random.randint(0,5,(10,3))
В качестве примера, это то, что я получил - обратите внимание, что есть один общий элемент:
>>> A
array([[1, 0, 3],
[0, 4, 2],
[0, 3, 4],
[4, 4, 2],
[2, 0, 2],
[4, 0, 0],
[3, 2, 2],
[4, 2, 3],
[0, 2, 1],
[2, 0, 2]])
>>> B
array([[4, 1, 3],
[4, 3, 0],
[0, 3, 3],
[3, 0, 3],
[3, 4, 0],
[3, 2, 3],
[3, 1, 2],
[4, 1, 2],
[0, 4, 2],
[0, 0, 3]])
Мы ищем, когда (L1) расстояние между строками равно нулю. Это дает нам матрицу, которая в точках, где она равна нулю, это элементы, общие для обоих списков:
idx = where(abs((A[:,newaxis,:] - B)).sum(axis=2)==0)
В качестве проверки:
>>> A[idx[0]]
array([[0, 4, 2]])
>>> B[idx[1]]
array([[0, 4, 2]])
Я не уверен, к чему вы клоните, но вы получите логический массив, в котором 2 массива не равны, и он будет очень быстрым:
import numpy as np
a = np.random.randn(5, 5)
b = np.random.randn(5, 5)
a[0,0] = 10.0
b[0,0] = 10.0
a[1,1] = 5.0
b[1,1] = 5.0
c = ~(a-b==0)
print c
[[False True True True True]
[ True False True True True]
[ True True True True True]
[ True True True True True]
[ True True True True True]]