2015-11-17 12 views
15

Sto sperimentando con la funzione numpy.where(condition[, x, y]).
Dal numpy documentation, vengo a sapere che se si dà solo un array come input, dovrebbe restituire gli indici in cui la matrice è diverso da zero (vale a dire "True"):l'output di numpy.where (condizione) non è un array, ma una tupla di array: perché?

Se viene dato solo condizioni, restituire il tuple condition.nonzero(), gli indici dove la condizione è True.

Ma se provate, mi restituisce un tupla di due elementi, dove il primo è la lista dei ricercati degli indici, e il secondo è un elemento nullo:

>>> import numpy as np 
>>> array = np.array([1,2,3,4,5,6,7,8,9]) 
>>> np.where(array>4) 
(array([4, 5, 6, 7, 8]),) # notice the comma before the last parenthesis 

quindi la domanda È perché? qual è lo scopo di questo comportamento? in quale situazione questo è utile? In effetti, per ottenere l'elenco di indici desiderato, devo aggiungere l'indicizzazione, come in np.where(array>4)[0], che sembra ... "brutto".


ADDENDUM

capisco (da alcune risposte) che in realtà è una tupla di un solo elemento. Ancora non capisco perché dare l'output in questo modo. Per illustrare come questo non è l'ideale, si consideri il seguente errore (che ha motivato la mia domanda in primo luogo):

>>> import numpy as np 
>>> array = np.array([1,2,3,4,5,6,7,8,9]) 
>>> pippo = np.where(array>4) 
>>> pippo + 1 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: can only concatenate tuple (not "int") to tuple 

in modo che avete bisogno di fare un po 'indicizzazione per accedere alla matrice reale di indici:

>>> pippo[0] + 1 
array([5, 6, 7, 8, 9]) 
+0

E a proposito di 'np.argwhere'? – Divakar

+3

Quello che vuoi è 'np.flatnonzero', che fa' a.ravel().diverso da zero() [0] '. – hpaulj

risposta

21

In Python (1) significa solo 1. () può essere aggiunto liberamente ai numeri di gruppo e alle espressioni per la leggibilità umana (ad esempio (1+3)*3 v (1+3,)*3). Quindi per denotare una tupla di 1 elemento usa (1,) (e richiede anche di usarlo).

Così

(array([4, 5, 6, 7, 8]),) 

è una tupla un elemento, tale elemento essendo un array.

Se si applica where a un array 2D, il risultato sarebbe una tupla di 2 elementi.

Il risultato di where è tale che può essere inserito direttamente in uno slot di indicizzazione, ad es.

a[where(a>0)] 
a[a>0] 

dovrebbe restituire le stesse cose

come farebbe

I,J = where(a>0) # a is 2d 
a[I,J] 
a[(I,J)] 

O con il tuo esempio:

In [278]: a=np.array([1,2,3,4,5,6,7,8,9]) 
In [279]: np.where(a>4) 
Out[279]: (array([4, 5, 6, 7, 8], dtype=int32),) # tuple 

In [280]: a[np.where(a>4)] 
Out[280]: array([5, 6, 7, 8, 9]) 

In [281]: I=np.where(a>4) 
In [282]: I 
Out[282]: (array([4, 5, 6, 7, 8], dtype=int32),) 
In [283]: a[I] 
Out[283]: array([5, 6, 7, 8, 9]) 

In [286]: i, = np.where(a>4) # note the , on LHS 
In [287]: i 
Out[287]: array([4, 5, 6, 7, 8], dtype=int32) # not tuple 
In [288]: a[i] 
Out[288]: array([5, 6, 7, 8, 9]) 
In [289]: a[(i,)] 
Out[289]: array([5, 6, 7, 8, 9]) 

============= =========

np.flatnonzero mostra la modo corretto di restituire un solo array, indipendentemente dalle dimensioni dell'array di input.

In [299]: np.flatnonzero(a>4) 
Out[299]: array([4, 5, 6, 7, 8], dtype=int32) 
In [300]: np.flatnonzero(a>4)+10 
Out[300]: array([14, 15, 16, 17, 18], dtype=int32) 

E 'dottore dice:

Ciò equivale a a.ravel() diverso da zero() [0]

In realtà che è letteralmente quello che la funzione fa..

Appiattendo a rimuove la domanda su cosa fare con più dimensioni. E poi prende la risposta dalla tupla, dandovi una matrice semplice. Con l'appiattimento non ha un caso speciale per gli array 1d.

===========================

@Divakar suggerisce np.argwhere:

In [303]: np.argwhere(a>4) 
Out[303]: 
array([[4], 
     [5], 
     [6], 
     [7], 
     [8]], dtype=int32) 

che fa np.transpose(np.where(a>4))

Oppure, se non ti piace il vettore colonna, si potrebbe trasporre nuovamente

In [307]: np.argwhere(a>4).T 
Out[307]: array([[4, 5, 6, 7, 8]], dtype=int32) 

solo che adesso è un array 1xn.

Potremmo così abbiamo avvolto in wherearray:

In [311]: np.array(np.where(a>4)) 
Out[311]: array([[4, 5, 6, 7, 8]], dtype=int32) 

Un sacco di modi di prendere una matrice il where tupla ([0], i,=, transpose, array, ecc).

+0

ciao @hpaulj, grazie per la risposta. Capisco, è una tupla di 1 elemento. Tuttavia, è necessario l'indicizzazione per accedere alla matrice effettiva, e non capisco perché, cioè perché fornire l'output in questo modo ... Vedere l'addendum nella domanda modificata. – Fabio

+1

L'obiettivo è la coerenza tra tutti gli array. 'np.flatnonzero' mostra il modo corretto per restituire una matrice invece di una tupla. – hpaulj

5

Risposta breve: np.where è progettato per avere un'uscita coerente indipendentemente dalla dimensione della matrice.

Un array bidimensionale ha due indici, quindi il risultato di np.where è una tupla di lunghezza 2 contenente gli indici rilevanti. Si generalizza a una tupla di lunghezza 3 per 3 dimensioni, una tupla di lunghezza 4 per 4 dimensioni o una tupla di lunghezza N per dimensioni N. Con questa regola, è chiaro che in 1 dimensione, il risultato dovrebbe essere una tupla di lunghezza 1.

0

Basta usare la funzione np.asarray. Nel tuo caso:

>>> import numpy as np 
>>> array = np.array([1,2,3,4,5,6,7,8,9]) 
>>> pippo = np.asarray(np.where(array>4)) 
>>> pippo + 1 
array([[5, 6, 7, 8, 9]]) 
+0

Perché è usato 'np.asarray()' al posto di 'np.array()'? – mikey

Problemi correlati