web-dev-qa-db-fra.com

Remplacer les valeurs d'un tableau d'index numpy par les valeurs d'une liste

Supposons que vous ayez un tableau numpy et une liste:

>>> a = np.array([1,2,2,1]).reshape(2,2)
>>> a
array([[1, 2],
       [2, 1]])
>>> b = [0, 10]

Je voudrais remplacer les valeurs dans un tableau, de sorte que 1 soit remplacé par 0 et 2 par 10.

J'ai trouvé un problème similaire ici - http://mail.python.org/pipermail//tutor/2011-september/085392.html

Mais en utilisant cette solution:

for x in np.nditer(a):
    if x==1:
        x[...]=x=0
    Elif x==2:
        x[...]=x=10

Me jette une erreur:

ValueError: assignment destination is read-only

Je suppose que c'est parce que je ne peux pas vraiment écrire dans un tableau numpy.

P.S. La taille réelle du tableau numpy est de 514 par 504 et de la liste est de 8. 

18
abudis

Au lieu de remplacer les valeurs une par une, il est possible de remapper tout le tableau comme suit:

import numpy as np
a = np.array([1,2,2,1]).reshape(2,2)
# palette must be given in sorted order
palette = [1, 2]
# key gives the new values you wish palette to be mapped to.
key = np.array([0, 10])
index = np.digitize(a.ravel(), palette, right=True)
print(key[index].reshape(a.shape))

les rendements

[[ 0 10]
 [10  0]]

Le crédit pour l'idée ci-dessus va à @ JoshAdel . C'est nettement plus rapide que ma réponse d'origine:

import numpy as np
import random
palette = np.arange(8)
key = palette**2
a = np.array([random.choice(palette) for i in range(514*504)]).reshape(514,504)

def using_unique():
    palette, index = np.unique(a, return_inverse=True)
    return key[index].reshape(a.shape)

def using_digitize():
    index = np.digitize(a.ravel(), palette, right=True)
    return key[index].reshape(a.shape)

if __== '__main__':
    assert np.allclose(using_unique(), using_digitize())

J'ai comparé les deux versions de cette façon:

In [107]: %timeit using_unique()
10 loops, best of 3: 35.6 ms per loop
In [112]: %timeit using_digitize()
100 loops, best of 3: 5.14 ms per loop
18
unutbu

Eh bien, je suppose que ce dont vous avez besoin est

a[a==2] = 10 #replace all 2's with 10's
30
alex_jordan

Un tableau en lecture seule dans numpy peut être rendu accessible en écriture:

nArray.flags.writeable = True

Ceci permettra alors des opérations d’affectation comme celle-ci:

nArray[nArray == 10] = 9999 # replace all 10's with 9999's

Le vrai problème n’était pas l’affectation elle-même, mais le drapeau en écriture.

22
DorinPopescu

Vous pouvez également utiliser np.choose(idx, vals), où idx est un tableau d'indices indiquant la valeur de vals à mettre à leur place. Les indices doivent cependant être basés sur 0. Assurez-vous également que idx a un type de données entier. Donc, il vous suffira de faire:

np.choose(a.astype(np.int32) - 1, b)
0
jns

J'ai trouvé une autre solution avec la fonction numpy place. (Documentation ici )

En l'utilisant sur votre exemple:

>>> a = np.array([1,2,2,1]).reshape(2,2)
>>> a
array([[1, 2],
   [2, 1]])
>>> np.place(a, a==1, 0)
>>> np.place(a, a==2, 10)
>>> a
array([[ 0, 10],
       [10,  0]])
0
Linda

Je n'ai pas pu définir les indicateurs ni utiliser un masque pour modifier la valeur. En fin de compte, je viens de faire une copie du tableau.

a2 = np.copy(a)
0
Paul Bendevis