numpy.array a un comportement bizarre avec l'opérateur / =?

Sep 11 2020

J'essaie de normaliser un tableau de nombres dans la plage (0, 1] afin de pouvoir les utiliser comme poids pour un random.choice pondéré (), alors j'ai entré cette ligne:

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

Cependant, Pycharm a déclaré qu'il y avait un paramètre non rempli pour la max()fonction ( Parameter 'initial' unfilled). J'ai essayé cela dans le REPL avec l'opérateur / = et avec la division "régulière" ( a = a / b) et j'ai obtenu des résultats différents pour les deux et une erreur différente de celle que Pycharm pensait:

>>> 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.        ])

J'ai également réalisé que pour un aléatoire pondéré, les poids devaient être additionnés à un plutôt que d'être normalisés à celui-ci. Mais le diviser par la somme a donné exactement la même chose en TypeErrorutilisant l'opération / = (mais Pycharm pensait que c'était correct):

>>> 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'ai-je rencontré ici? S'agit-il d'un bug bizarre dans Numpy ou est-ce que l'opérateur / = a une utilisation différente ou quelque chose? Je sais qu'ils utilisent __truediv__et __itruediv__mais je ne vois pas pourquoi l'un a un problème et l'autre pas. J'ai confirmé ce comportement avec la dernière version de Numpy de pip (1.19.2 sur Windows x64).

Réponses

1 Fahim Sep 11 2020 at 23:24

C'est parce que numpy se soucie du type. Lorsque vous appliquez la division, vous passez intà float. Mais numpy ne vous laissera pas faire ça! C'est pourquoi vos valeurs devraient déjà être présentes float. Essaye ça:

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

Mais pourquoi l'autre a-t-il fonctionné? C'est parce que ce n'est pas une opération «sur place». Par conséquent, un nouvel emplacement mémoire est en cours de création. Nouvelle variable, nouveau type, donc numpy s'en fiche ici.