uint8 - transpuesta de una matriz python numpy
Numpy: Diferencia entre punto(a, b) y(a*b).sum() (1)
Numpy dot es una de las rutinas que llama a la biblioteca BLAS que vincula en la compilación (o crea su propia cuenta). La importancia de esto es que la biblioteca BLAS puede hacer uso de Multiplicar-acumular operaciones (generalmente Fused-Multiply Add) que limitan el número de redondeos que realiza el cálculo.
Toma lo siguiente:
>>> a=np.ones(1000,dtype=np.float128)+1E-14
>>> (a*a).sum()
1000.0000000000199948
>>> np.dot(a,a)
1000.0000000000199948
No es exacto, pero lo suficientemente cerca.
>>> a=np.ones(1000,dtype=np.float64)+1E-14
>>> np.dot(a,a)
1000.0000000000176 #off by 2.3948e-12
>>> (a*a).sum()
1000.0000000000059 #off by 1.40948e-11
El np.dot(a, a)
será el más preciso de los dos, ya que utiliza aproximadamente la mitad del número de redondeos de punto flotante que hace el ingenuo (a*a).sum()
.
Un libro de Nvidia tiene el siguiente ejemplo para 4 dígitos de precisión. rn
representa 4 redondos a los 4 dígitos más cercanos:
x = 1.0008
x2 = 1.00160064 # true value
rn(x2 − 1) = 1.6006 × 10−4 # fused multiply-add
rn(rn(x2) − 1) = 1.6000 × 10−4 # multiply, then add
Por supuesto, los números de punto flotante no se redondean al decimo sexto lugar decimal en la base 10, pero se entiende la idea.
Colocando np.dot(a,a)
en la notación anterior con algún pseudo código adicional:
out=0
for x in a:
out=rn(x*x+out) #Fused multiply add
Mientras que (a*a).sum()
es:
arr=np.zeros(a.shape[0])
for x in range(len(arr)):
arr[x]=rn(a[x]*a[x])
out=0
for x in arr:
out=rn(x+out)
A partir de esto, es fácil ver que el número se redondea el doble de veces usando (a*a).sum()
comparación con np.dot(a,a)
. Estas pequeñas diferencias sumadas pueden cambiar la respuesta minuciosamente. Los ejemplos adicionales se pueden encontrar here .
Para las matrices numpy 1-D, estas dos expresiones deberían producir el mismo resultado (teóricamente):
(a*b).sum()/a.sum()
dot(a, b)/a.sum()
Este último usa dot()
y es más rápido. ¿Pero cuál es más preciso? ¿Por qué?
Un poco de contexto sigue.
Quería calcular la varianza ponderada de una muestra usando numpy. Encontré la expresión de dot()
en otra respuesta , con un comentario que indica que debería ser más precisa. Sin embargo, no se da ninguna explicación allí.