Come rimuovere elementi specifici in un array intorpidito


212

Come posso rimuovere alcuni elementi specifici da una matrice numpy? Di 'che ho

import numpy as np

a = np.array([1,2,3,4,5,6,7,8,9])

Voglio quindi rimuovere 3,4,7da a. Tutto quello che so è l'indice dei valori ( index=[2,3,6]).

Risposte:


286

Usa numpy.delete () - restituisce un nuovo array con sotto-array lungo un asse eliminato

numpy.delete(a, index)

Per la tua domanda specifica:

import numpy as np

a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
index = [2, 3, 6]

new_a = np.delete(a, index)

print(new_a) #Prints `[1, 2, 5, 6, 8, 9]`

Si noti che numpy.delete()restituisce un nuovo array poiché gli scalari di array sono immutabili, simili alle stringhe in Python, quindi ogni volta che viene apportata una modifica ad esso, viene creato un nuovo oggetto. Vale a dire, per citare i delete() documenti :

"Una copia di arr con gli elementi specificati da obj rimossi. Nota che la cancellazione non avviene sul posto ..."

Se il codice che invio ha un output, è il risultato dell'esecuzione del codice.


1
@IngviGautsson Quando hai effettuato la modifica, hai anche modificato i valori corretti per gli elementi da 2, 3, 6 a 3, 4, 7, se esegui il codice ora non ottieni l'output corretto come in origine. "Sto ripristinando la modifica
Levon,

1
AttributeError: l'oggetto 'list' non ha attributi 'delete'
munmunbb

3
@IngviGautsson No, il tuo commento è fuorviante. Funziona come previsto. Tuttavia, la documentazione di numpy.delete () osserva che "spesso è preferibile usare una maschera booleana"; ne viene anche fornito un esempio.
Biggsy,

1
@Levon puoi aggiungere esempi per il 2D?
Matt

7
@IngviGautsson Ti sbagli. Sono necessari gli indici degli elementi da eliminare, non gli elementi stessi.
Le Frite,

64

C'è una funzione incorporata intorpidita per aiutare con quello.

import numpy as np
>>> a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> b = np.array([3,4,7])
>>> c = np.setdiff1d(a,b)
>>> c
array([1, 2, 5, 6, 8, 9])

7
Buono a sapersi. Stavo pensando che np.delete sarebbe più lento, ma purtroppo, il timeit per 1000 numeri interi dice che eliminare è x2 più veloce.
mercoledì

1
Questo è fantastico perché opera sui valori dell'array piuttosto che dover fornire l'indice / gli indici che si desidera rimuovere. Ad esempio:np.setdiff1d(np.array(['one','two']),np.array(['two', 'three']))
MD004,

Questo ordina anche l'output, che potrebbe non essere quello che si desidera. Altrimenti molto bello.
rayzinnz,

La domanda dice "Tutto quello che so è l'indice dei valori". Quindi, si tratta di rimuovere gli oggetti dai loro indici , non di rimuoverli con i loro valori
Sherzod il

35

Un array Numpy è immutabile , il che significa che tecnicamente non è possibile eliminare un elemento da esso. Tuttavia, puoi costruire un nuovo array senza i valori che non desideri, in questo modo:

b = np.delete(a, [2,3,6])

1
+1 per menzionare "immutabile". È bene ricordare che gli array intorpiditi non sono utili per rapidi cambi di dimensione (aggiunta / eliminazione di elementi)
eumiro,

38
tecnicamente, le matrici intorpidite SONO mutabili. Ad esempio, questo: a[0]=1modifica asul posto. Ma non possono essere ridimensionati.
btel,

3
La definizione dice immutabile, ma se assegnando un nuovo valore ti consente di modificarlo, come lo rende immutabile?
JSR

16

Per cancellare per valore:

modified_array = np.delete(original_array, np.where(original_array == value_to_delete))

La domanda riguarda la rimozione di oggetti per indici , non la rimozione di oggetti con un valore specifico
Sherzod

5

Non essendo una persona insensibile, ho fatto una foto con:

>>> import numpy as np
>>> import itertools
>>> 
>>> a = np.array([1,2,3,4,5,6,7,8,9])
>>> index=[2,3,6]
>>> a = np.array(list(itertools.compress(a, [i not in index for i in range(len(a))])))
>>> a
array([1, 2, 5, 6, 8, 9])

Secondo i miei test, questo supera numpy.delete(). Non so perché sarebbe così, forse a causa delle piccole dimensioni dell'array iniziale?

python -m timeit -s "import numpy as np" -s "import itertools" -s "a = np.array([1,2,3,4,5,6,7,8,9])" -s "index=[2,3,6]" "a = np.array(list(itertools.compress(a, [i not in index for i in range(len(a))])))"
100000 loops, best of 3: 12.9 usec per loop

python -m timeit -s "import numpy as np" -s "a = np.array([1,2,3,4,5,6,7,8,9])" -s "index=[2,3,6]" "np.delete(a, index)"
10000 loops, best of 3: 108 usec per loop

Questa è una differenza abbastanza significativa (nella direzione opposta a quella che mi aspettavo), qualcuno ha idea del perché questo sarebbe il caso?

Ancora più stranamente, il passaggio di numpy.delete()un elenco ha prestazioni peggiori rispetto al passare in rassegna l'elenco e assegnandogli singoli indici.

python -m timeit -s "import numpy as np" -s "a = np.array([1,2,3,4,5,6,7,8,9])" -s "index=[2,3,6]" "for i in index:" "    np.delete(a, i)"
10000 loops, best of 3: 33.8 usec per loop

Modifica: sembra avere a che fare con le dimensioni dell'array. Con array di grandi dimensioni, numpy.delete()è significativamente più veloce.

python -m timeit -s "import numpy as np" -s "import itertools" -s "a = np.array(list(range(10000)))" -s "index=[i for i in range(10000) if i % 2 == 0]" "a = np.array(list(itertools.compress(a, [i not in index for i in range(len(a))])))"
10 loops, best of 3: 200 msec per loop

python -m timeit -s "import numpy as np" -s "a = np.array(list(range(10000)))" -s "index=[i for i in range(10000) if i % 2 == 0]" "np.delete(a, index)"
1000 loops, best of 3: 1.68 msec per loop

Ovviamente, tutto ciò è piuttosto irrilevante, poiché dovresti sempre andare per chiarezza ed evitare di reinventare la ruota, ma l'ho trovato un po 'interessante, quindi ho pensato di lasciarlo qui.


2
Fai attenzione a ciò che effettivamente confronti! Hai a = delte_stuff(a)nella tua prima iterazione, che si ariduce con ogni iterazione. Quando si utilizza la funzione inbuild, non si memorizza il valore in a, che mantiene a nella dimensione originale! Oltre a ciò, puoi velocizzare drasticamente la tua funzione, quando crei un set di indexe controlli contro quello, se eliminare o meno un elemento. Risolvendo entrambe le cose, ottengo 10k articoli: 6,22 msec per ciclo con la tua funzione, 4,48 msec per numpy.delete, che è più o meno quello che ti aspetteresti.
Michael

2
Altri due suggerimenti: invece di np.array(list(range(x)))utilizzare np.arange(x)e per creare l'indice, è possibile utilizzare np.s_[::2].
Michael

1

Se non conosci l'indice, non puoi usarlo logical_and

x = 10*np.random.randn(1,100)
low = 5
high = 27
x[0,np.logical_and(x[0,:]>low,x[0,:]<high)]

1

L'utilizzo np.deleteè il modo più veloce per farlo, se conosciamo gli indici degli elementi che vogliamo rimuovere. Tuttavia, per completezza, vorrei aggiungere un altro modo di "rimuovere" gli elementi dell'array usando una maschera booleana creata con l'aiuto di np.isin. Questo metodo ci consente di rimuovere gli elementi specificandoli direttamente o tramite i loro indici:

import numpy as np
a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])

Rimuovi per indici :

indices_to_remove = [2, 3, 6]
a = a[~np.isin(np.arange(a.size), indices_to_remove)]

Rimuovi per elementi (non dimenticare di ricreare l'originale apoiché è stato riscritto nella riga precedente):

elements_to_remove = a[indices_to_remove]  # [3, 4, 7]
a = a[~np.isin(a, elements_to_remove)]

0

Rimuovi indice specifico (ho rimosso 16 e 21 dalla matrice)

import numpy as np
mat = np.arange(12,26)
a = [4,9]
del_map = np.delete(mat, a)
del_map.reshape(3,4)

Produzione:

array([[12, 13, 14, 15],
      [17, 18, 19, 20],
      [22, 23, 24, 25]])

0

Puoi anche usare i set:

a = numpy.array([10, 20, 30, 40, 50, 60, 70, 80, 90])
the_index_list = [2, 3, 6]

the_big_set = set(numpy.arange(len(a)))
the_small_set = set(the_index_list)
the_delta_row_list = list(the_big_set - the_small_set)

a = a[the_delta_row_list]
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.