Sostituisci i valori negativi in ​​un array numpy


90

C'è un modo semplice per sostituire tutti i valori negativi in ​​un array con 0?

Ho un blocco completo su come farlo usando un array NumPy.

Per esempio

a = array([1, 2, 3, -4, 5])

Devo tornare

[1, 2, 3, 0, 5]

a < 0 dà:

[False, False, False, True, False]

Qui è dove sono bloccato: come utilizzare questo array per modificare l'array originale.

Risposte:


137

Sei a metà strada. Provare:

In [4]: a[a < 0] = 0

In [5]: a
Out[5]: array([1, 2, 3, 0, 5])

89

Prova numpy.clip:

>>> import numpy
>>> a = numpy.arange(-10, 10)
>>> a
array([-10,  -9,  -8,  -7,  -6,  -5,  -4,  -3,  -2,  -1,   0,   1,   2,
         3,   4,   5,   6,   7,   8,   9])
>>> a.clip(0, 10)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

Puoi ritagliare solo la metà inferiore con clip(0).

>>> a = numpy.array([1, 2, 3, -4, 5])
>>> a.clip(0)
array([1, 2, 3, 0, 5])

Puoi ritagliare solo la metà superiore con clip(max=n). (Questo è molto meglio del mio precedente suggerimento, che prevedeva il passaggio NaNal primo parametro e l'utilizzo outper forzare il tipo.):

>>> a.clip(max=2)
array([ 1,  2,  2, -4,  2])

Un altro approccio interessante è usare where:

>>> numpy.where(a <= 2, a, 2)
array([ 1,  2,  2, -4,  2])

Infine, considera la risposta di aix . Preferisco clipper le operazioni semplici perché è auto-documentante, ma la sua risposta è preferibile per le operazioni più complesse.


1
a.clip (0) sarebbe sufficiente poiché l'OP vuole solo sostituire i valori negativi. a.clip (0, 10) escluderebbe qualsiasi cosa sopra 10.
Usagi

1
@ Hiett - L'ho appena provato e il clip ne prenderà uno. Il primo si presume min.
Usagi

deve essere un problema di versione con numpy - ecco il mio output: (Pdb) np.clip (w, 0) *** TypeError: clip () richiede almeno 3 argomenti (2 dati) - mentre: (Pdb) np.clip ( w, 0,1e6) array ([[0., 0.605]])
bph

1
@ Hiett, quale versione di numpy? Hai provato il metodo della clip di a? La funzione incorporata numpy.clipmi dà lo stesso errore, ma il metodo no.
senderle

yeh se lo chiami in questo modo sembra funzionare, ad esempio p w.clip (0) array ([[0., 0.605]]) - quanto strano?
bph

10

Un'altra soluzione Python minimalista senza usare numpy:

[0 if i < 0 else i for i in a]

Non è necessario definire alcuna funzione aggiuntiva.

a = [1, 2, 3, -4, -5.23, 6]
[0 if i < 0 else i for i in a]

rende:

[1, 2, 3, 0, 0, 6]

1
questo è carino - mi chiedevo quale sarebbe la sintassi per inserire l'istruzione if all'interno della comprensione della lista - stavo sbagliando incollandola dopo il ciclo for e solo dopo recuperando due valori, ad esempio [0, 0] per il tuo esempio list
bph

Ho fatto lo stesso quando ho appreso inizialmente la comprensione delle liste e stavo provando cose diverse per testare la mia comprensione - anche per me sembrava più intuitivo metterlo dopo il ciclo for. Ora, però, questo fa :) Mettendolo prima di lo forapplica a ogni elemento della lista, mettendolo dopo, significa che solo se la condizione è soddisfatta entra nella lista risultante.
Levon

2
@Hiett Sta semplicemente usando l'operatore ternario ( i < 0 ? 0 : iin C) all'interno di una lista di comprensione. Metti le parentesi per renderlo più chiaro [(0 if i < 0 else i) for i in a]. Mettere il se dopo sta usando la parte del filtro del costrutto dell'espressione della lista. [(i) for i in a if i < 0]restituirà solo un elenco di elementi inferiori a zero.
Paul S,

2
Numpy è potente perché esegue molti calcoli tramite codice c compilato ed è quindi più veloce. Confrontando questo metodo con gli altri, trovo una differenza di fattore di velocità quasi 10 volte superiore (questo è più lento). Quindi, sebbene intuitivo e facile da leggere, questo non è sicuramente per l'intenso calcolo.
rspencer

4

E ancora un'altra possibilità:

In [2]: a = array([1, 2, 3, -4, 5])

In [3]: where(a<0, 0, a)
Out[3]: array([1, 2, 3, 0, 5])

2

Ecco un modo per farlo in Python senza NumPy. Crea una funzione che restituisca ciò che desideri e usa una comprensione dell'elenco o la funzione mappa .

>>> a = [1, 2, 3, -4, 5]

>>> def zero_if_negative(x):
...   if x < 0:
...     return 0
...   return x
...

>>> [zero_if_negative(x) for x in a]
[1, 2, 3, 0, 5]

>>> map(zero_if_negative, a)
[1, 2, 3, 0, 5]

1
avevo seguito questa strada ma pensavo che ci doveva essere un modo più semplice, più matlab e meno python per farlo con numpy (dato che stavo usando gli array piuttosto che le liste comunque). clip è perfetta
bph
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.