расстояние попарного хемминга между массивами numpy, учитывая только ненулевые значения - PullRequest
2 голосов
/ 29 апреля 2020

Я хочу рассчитать попарно расстояние Хемминга для двумерного numpy массива.

Мои массивы

A
array([[-1,  0, -1,  0, -1,  0],
       [ 1,  0,  0,  0,  0,  0],
       [ 0,  0,  1,  1,  1,  0],
       [ 0,  0, -1,  1,  0,  0],
       [ 0,  0,  0,  0, -1,  0]], dtype=int8)

Я хочу вычислить расстояние Хемминга между строками A, но учитывая только ненулевые значения. Если одна из записей равна нулю, мы не включаем ее в расчет.

Мой вывод должен быть

B
array([[0, 1, 2, 0, 0],
       [1, 0, 0, 0, 0],
       [2, 0, 0, 1, 1],
       [0, 0, 1, 0, 0],
       [0, 0, 1, 0, 0]], dtype=int8) 

Ответы [ 2 ]

1 голос
/ 29 апреля 2020

Если ваши массивы имеют только нули и единицы, то у вас есть следующее свойство: r1 * r2 будет содержать 0 в пропущенных местах, -1, если элементы различаются, и +1, где они одинаковы. Поэтому вы хотите умножить все возможные комбинации вместе и посчитать количество записей меньше нуля для каждой строки.

Вы берете продукт с вещанием:

B = np.count_nonzero(A[:, None, :] * A[None, :, :] < 0, axis=-1)

Если вам нужно обобщить для значений, которые не всегда равны -1 и +1, вы можете использовать аналогичный прием для явной проверки на равенство. Для двух позиций a, b количество a * b * (a - b) будет отличным от нуля тогда и только тогда, когда оба значения отличны от нуля и отличаются:

A1 = A[:, None, :]
A2 = A[None, :, :]
B = np.count_nonzero(A1 * A2 * (A1 - A2), axis=-1)

Если вы хотите записать условие явно, вы можете сделать

np.count_nonzero((A1 != A2) & (A1 != 0) & (A2 != 0), axis=-1)
1 голос
/ 29 апреля 2020

Я чувствую, что для этого должен быть более простой способ (с точки зрения скорости все должно быть в порядке, поскольку все основано на массивах, читаемость немного сложна). Но вот рабочее решение:

from itertools import permutations

b = np.zeros((a.shape[0], a.shape[0]))
idx = np.array(list(permutations(range(a.shape[0]),2)))
b[tuple(idx.T)] = np.count_nonzero(np.logical_and(a[idx.T][0,:]-a[idx.T][1,:], np.logical_and(a[idx.T][0,:]!=0, a[idx.T][1,:]!=0)), axis=1)

Сначала вы создаете все возможные комбинации строк, используя itertools 'permutations в качестве индексов, а затем для каждой пары строк подсчитывает ненулевые значения в логических и из вычесть из них и ненулевые значения из них :

вывод:

[[0. 1. 2. 0. 0.]
 [1. 0. 0. 0. 0.]
 [2. 0. 0. 1. 1.]
 [0. 0. 1. 0. 0.]
 [0. 0. 1. 0. 0.]]
...