Saltar al contenido

Cálculo rápido de la distancia de Hamming entre matrices numpy binarias

Solución:

Hay una función numpy lista que late len((a != b).nonzero()[0]) 😉

np.count_nonzero(a!=b)

En comparación con 1.07μs para np.count_nonzero (a! = B) en mi plataforma, gmpy2.hamdist se reduce a aproximadamente 143ns después de la conversión de cada matriz a un mpz (entero de precisión múltiple):

import numpy as np
from gmpy2 import mpz, hamdist, pack

a = np.array([1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0])
b = np.array([1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1])

Según un consejo de @casevh, la conversión de una matriz 1D de unos y ceros a un objeto gmpy2 mpz se puede realizar de manera razonablemente eficiente con gmpy2.pack (list (reversed (list (matriz))), 1).

# gmpy2.pack reverses bit order but that does not affect
# hamdist since both its arguments are reversed
ampz = pack(list(a),1) # takes about 4.29µs
bmpz = pack(list(b),1)

hamdist(ampz,bmpz)
Out[8]: 7

%timeit hamdist(ampz,bmpz)
10000000 loops, best of 3: 143 ns per loop

para una comparación relativa, en mi plataforma:

%timeit np.count_nonzero(a!=b)
1000000 loops, best of 3: 1.07 µs per loop

%timeit len((a != b).nonzero()[0])
1000000 loops, best of 3: 1.55 µs per loop

%timeit len(np.bitwise_xor(a,b).nonzero()[0])
1000000 loops, best of 3: 1.7 µs per loop

%timeit np.sum(np.bitwise_xor(a,b))
100000 loops, best of 3: 5.8 µs per loop   

El uso de pythran puede traer un beneficio adicional aquí:

$ cat hamm.py
#pythran export hamm(int[], int[])
from numpy import nonzero
def hamm(a,b):
    return len(nonzero(a != b)[0])

Como referencia (sin pythran):

$ python -m timeit -s 'import numpy as np; a = np.random.randint(0,2, 100); b = np.random.randint(0,2, 100); from hamm import hamm' 'hamm(a,b)'
100000 loops, best of 3: 4.66 usec per loop

Mientras que después de la compilación de Pythran:

$ python -m pythran.run hamm.py
$ python -m timeit -s 'import numpy as np; a = np.random.randint(0,2, 100); b = np.random.randint(0,2, 100); from hamm import hamm' 'hamm(a,b)'
1000000 loops, best of 3: 0.745 usec per loop

Eso es aproximadamente un 6x aceleración sobre la implementación numpy, ya que pythran omite la creación de una matriz intermedia al evaluar la comparación de elementos.

También medí:

def hamm(a,b):
    return count_nonzero(a != b)

Y consigo 3.11 usec per loop para la versión de Python y 0.427 usec per loop con el Pythran.

Descargo de responsabilidad: soy uno de los desarrolladores de Pythran.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *