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.