numpy.array tiene un comportamiento extraño con / = operador?

Sep 11 2020

Estoy tratando de normalizar una matriz de números en el rango (0, 1] para poder usarlos como pesos para un random.choice () ponderado, así que ingresé esta línea:

# weights is a nonzero numpy.array
weights /= weights.max()

Sin embargo, Pycharm dijo que hay un parámetro sin completar para la max()función ( Parameter 'initial' unfilled). Intenté esto en el REPL con el operador / = y con la división "regular" ( a = a / b) y obtuve resultados diferentes para ambos y un error diferente al que pensaba Pycharm:

>>> a = numpy.array([1,2,3])
>>> a.max()
3
>>> a /= a.max()
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    a /= a.max()
TypeError: No loop matching the specified signature and casting was found for ufunc true_divide
>>> a = a/a.max()
>>> a
array([0.33333333, 0.66666667, 1.        ])

También me di cuenta de que para un aleatorio ponderado, los pesos debían sumar uno en lugar de normalizarse. Pero dividirlo por la suma arrojó exactamente lo mismo TypeErrorusando la operación / = (pero Pycharm pensó que esto estaba bien):

>>> a = numpy.array([1,2,3])
>>> sum(a)
6
>>> a
array([1, 2, 3])
>>> a /= sum(a)
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    a /= sum(a)
TypeError: No loop matching the specified signature and casting was found for ufunc true_divide
>>> a = a / sum(a)
>>> a
array([0.16666667, 0.33333333, 0.5       ])

¿Qué me he encontrado aquí? ¿Es un error extraño en Numpy o el operador / = tiene un uso diferente o algo así? Sé que usan __truediv__y __itruediv__no veo por qué uno tiene un problema y el otro no. He confirmado este comportamiento con la última versión de Numpy de pip (1.19.2 en Windows x64).

Respuestas

1 Fahim Sep 11 2020 at 23:24

Es porque a Numpy le importa el tipo. Cuando aplica la división, está cambiando inta float. ¡Pero numpy no te dejará hacer eso! Es por eso que sus valores ya deberían estar incluidos float. Prueba esto:

>>> a = np.array([1.0,2.0,3.0])
>>> a /= sum(a)
>>> a
array([0.16666667, 0.33333333, 0.5       ])

Pero, ¿por qué funcionó el otro? Es porque esa no es una operación "en el lugar". Por lo tanto, se está creando una nueva ubicación de memoria. Nueva variable, nuevo tipo, por lo tanto, a numpy no le importa aquí.