2017-05-11 4 views
2

In meinem Code versuche ich irgendwann, einen Wert eines maskierten Arrays zu ändern, doch Python scheint dies zu ignorieren. Ich denke, dass dies mit der Art und Weise zu tun hat, wie Speicher in Arrays gespeichert wird, als ob ich eine Kopie des Wertes modifizieren würde und nicht den Wert selbst, aber ich bin nicht gut genug darin, um eine Ahnung zu haben, wie man es löst es. HierWie kann ich den Wert eines maskierten Arrays in numpy ändern?

ist eine vereinfachte Version von dem, was ich versuche zu tun:

x = np.zeros((2,5)) # create 2D array of zeroes 
    x[0][1:3] = 5  # replace some values along 1st dimension with 5 

    mask = (x[0] > 0) # create a mask to only deal with the non negative values 

    x[0][mask][1] = 10 # change one of the values that is non negative 

    print x[0][mask][1] # value isn't changed in the original array 

der Ausgang dieser ist:

5.0 

wenn es sein sollte 10.

Jede Hilfe würde sehr geschätzt werden, im Idealfall muss dies skalierbar sein (was bedeutet, dass ich nicht unbedingt die Form von x kenne, oder wo die Werte nicht negativ sind oder welche ich modifizieren muss).

Ich arbeite mit numpy 1.11.0, auf Python 2.7.12 auf Ubuntu 16.04.2

Dank!

+0

Wo möglich mit einem Satz von Indexierungsklammern, nicht mehrere, z. 'x [0, 1: 3]'; 'x [0, Maske]'. Beachten Sie jedoch, dass die Indexierung mit einer booleschen Maske eine Kopie erzeugt. – hpaulj

Antwort

2

Lassen Sie uns g eneralize Ihr Problem ein wenig:

In [164]: x=np.zeros((2,5)) 
In [165]: x[0, [1, 3]] = 5  # index with a list, not a slice 
In [166]: x 
Out[166]: 
array([[ 0., 5., 0., 5., 0.], 
     [ 0., 0., 0., 0., 0.]]) 

Wenn die Indizierung der = direkt vor auftritt, ist es Teil eines __setitem__ und wirkt auf die Original-Array ist. Dies gilt unabhängig davon, ob die Indizierung Slices, eine Liste oder eine boolesche Maske verwendet.

Aber eine Auswahl mit der Liste oder Maske erzeugt eine Kopie.Eine weitere indizierte Zuweisung betrifft nur diese Kopie, nicht das Original.

In [167]: x[0, [1, 3]] 
Out[167]: array([ 5., 5.]) 
In [168]: x[0, [1, 3]][1] = 6 
In [169]: x 
Out[169]: 
array([[ 0., 5., 0., 5., 0.], 
     [ 0., 0., 0., 0., 0.]]) 

Der beste Weg, um dieses ist die Maske selbst zu ändern:

In [170]: x[0, np.array([1,3])[1]] = 6 
In [171]: x 
Out[171]: 
array([[ 0., 5., 0., 6., 0.], 
     [ 0., 0., 0., 0., 0.]]) 

Wenn die mask boolean ist, können Sie es zu Indizierung Array konvertieren müssen

In [174]: mask = x[0]>0 
In [175]: mask 
Out[175]: array([False, True, False, True, False], dtype=bool) 
In [176]: idx = np.where(mask)[0] 
In [177]: idx 
Out[177]: array([1, 3], dtype=int32) 
In [178]: x[0, idx[1]] 
Out[178]: 6.0 

Oder Sie kann die booleschen Werte direkt zwicken

In [179]: mask[1]=False 
In [180]: x[0,mask] 
Out[180]: array([ 6.]) 

Also in Ihrem großen Problem müssen Sie beachten, wenn Indizierung eine Ansicht erzeugt und es eine Kopie ist. Und Sie müssen mit dem Index mit Listen, Arrays und Booleans vertraut sein und verstehen, wie Sie zwischen ihnen wechseln können.

+0

Das ist perfekt danke! Das funktioniert und ist skalierbar, ich muss nur die Art und Weise überdenken, wie ich mich Masken und Arrays annähere. Mir war nicht bewusst, dass Python durch mehrfache Indizierung eine Kopie erstellt hat, aber genau das vermutete ich. –

1

Es ist nicht wirklich ein maskierter Array was Sie erstellt haben:

x = np.zeros((2,5)) 
x[0][1:3] = 5 
mask = (x[0] > 0) 
mask 
Out[14]: array([False, True, True, False, False], dtype=bool) 

Also, das ist nur ein boolean-Array. Um eine maskierte Array zu erstellen, sollten Sie numpy.ma Modul verwenden:

masked_x = np.ma.array(x[0], mask=~(x[0] > 0)) # let's mask first row as you did 
masked_x 
Out[15]: 
masked_array(data = [-- 5.0 5.0 -- --], 
      mask = [ True False False True True], 
     fill_value = 1e+20) 

Jetzt können Sie Ihre maskierte Array ändern, und dementsprechend wird die Hauptanordnung:

masked_x[1] = 10.  
masked_x 
Out[36]: 
masked_array(data = [-- 10.0 5.0 -- --], 
      mask = [ True False False True True], 
     fill_value = 1e+20)  
x 
Out[37]: 
array([[ 0., 10., 5., 0., 0.], 
     [ 0., 0., 0., 0., 0.]]) 

Und feststellen, dass in maskierter Arrays ungültige Einträge markiert als True .

+0

Er kann dieses boolesche Array als Maske verwenden, ohne den Schritt "np.ma.array" zu verwenden. Vermutlich benutzt er den Begriff 'maskiertes Array'. – hpaulj

+0

@hpaulj Wahrscheinlich. Aber ich glaube, der beste Weg, um das zu erreichen, was er will (um die Werte des Ausgangsarrays 'durch die Maske' zu ändern) besteht darin, ein maskiertes Array zu verwenden. Zumindest wenn ich die Frage richtig verstehe. –

+0

Idealerweise wollte ich das so einfach wie möglich, das heißt, ich habe ein Array, mit dem ich arbeiten kann, und dann modifiziere ich dieses Array, ohne Kopien des maskierten Arrays zu erstellen (wie das Modul numpy.ma). @hpauljs Antwort hat es geschafft, danke. –

1

Um zu verstehen, was auf ich dieses Dies läuft darauf hinaus, die irreführende Verwendung von Phantasie Indizierung http://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html

empfiehlt das Lesen geht. Die folgenden Anweisungen sind die gleichen und wie Sie sehen können, ist es direkt auf 10 die Elemente von x mit Maske setzen.

x[0][mask] = 10 
x[0,mask] = 10 
x.__setitem__((0, mask), 10) 

Was Sie auf der anderen Seite tun ist folgende

x[0][mask][1] = 10 
x[0,mask][1] = 10 
x[0,mask].__setitem__(1, 10) 
x.__getitem__((0, mask)).__setitem__(1, 10) 

die eine Kopie mit __getitem __ schafft()

Abschließend müssen Sie überdenken, wie zu ändern diese einzelne Nummer mit einer anderen Maske __setitem() __

+0

Danke! Dies ist genau das, was ich vermutet habe, und der Link, den Sie angegeben haben, ist sehr aufschlussreich. Ich habe @hpauljs Antwort akzeptiert, da er auch eine Lösung zur Verfügung gestellt hat. –

Verwandte Themen