2012-03-19 15 views
6

Mi chiedo quale sia il modo migliore per normalizzare/standardizzare un numpy recarray. Per chiarire, non sto parlando di una matrice matematica, ma di un array di record che ha anche per es. colonne testuali (come le etichette).Normalizza/normalizza un nuovo tipo di memoria

a = np.genfromtxt("iris.csv", delimiter=",", dtype=None) 
print a.shape 
> (150,) 

Come potete vedere, non posso ad es. processo a[:,:-1] in quanto la forma è monodimensionale.

Il migliore che ho trovato è quello di iterare su tutte le colonne:

for nam in a.dtype.names[:-1]: 
    col = a[nam] 
    a[nam] = (col - col.min())/(col.max() - col.min()) 

modo Qualsiasi più elegante di fare questo? C'è qualche metodo come "normalizzare" o "standardizzare" da qualche parte?

risposta

6

Ci sono diversi modi per farlo, ma alcuni sono più puliti di altri.

Di solito, in numpy, si mantengono i dati di stringa in un array separato.

(Le cose sono un po 'più basso livello rispetto, ad esempio, frame di dati di R. In genere basta avvolgere le cose in una classe per l'associazione, ma mantenere diversi tipi di dati separati.)

Onestamente, isn numpy ottimizzato per gestire tipi di dati "flessibili" come questo (sebbene possa certamente farlo). Cose come pandas forniscono un'interfaccia migliore per i dati "simili al foglio di calcolo" (e i panda sono solo uno strato sopra a numpy).

Tuttavia, gli array strutturati (che è quello che hai qui) ti permetteranno di tagliarli a colonne quando passi in una lista di nomi di campi. (Ad esempio data[['col1', 'col2', 'col3']])

In ogni caso, in un modo è quello di fare qualcosa di simile:

import numpy as np 

data = np.recfromcsv('iris.csv') 

# In this case, it's just all but the last, but we could be more general 
# This must be a list and not a tuple, though. 
float_fields = list(data.dtype.names[:-1]) 

float_dat = data[float_fields] 

# Now we just need to view it as a "regular" 2D array... 
float_dat = float_dat.view(np.float).reshape((data.size, -1)) 

# And we can normalize columns as usual. 
normalized = (float_dat - float_dat.min(axis=0))/float_dat.ptp(axis=0) 

Tuttavia, questo è tutt'altro che ideale. Se si desidera eseguire l'operazione sul posto (come si è attualmente), la soluzione più semplice è quella che si ha già: basta scorrere i nomi dei campi.

Per inciso, utilizzando pandas, si farebbe qualcosa di simile:

import pandas 
data = pandas.read_csv('iris.csv', header=None) 

float_dat = data[data.columns[:-1]] 
dmin, dmax = float_dat.min(axis=0), float_dat.max(axis=0) 

data[data.columns[:-1]] = (float_dat - dmin)/(dmax - dmin) 
+1

+1 Grazie. Questa è una risposta molto istruttiva e perspicace. La suddivisione del set di dati in colonne numeriche e non numeriche è probabilmente la strada da percorrere. Questo rende molte altre operazioni ben definite ed è in effetti ciò che stavo cercando di fare. Non ero a conoscenza dell'opzione di usare 'data [elenco]' per selezionare più colonne. –

1

Quale versione di NumPy stai usando? Con la versione 1.5.1, non ho questo comportamento. Ho fatto un file di testo breve come un esempio, salvato come test.txt:

last,first,country,state,zip 
tyson,mike,USA,Nevada,89146 
brady,tom,USA,Massachusetts,02035 

Quando ho quindi eseguire il codice riportato di seguito, questo è ciò che ottengo:

>>> import numpy as np 
>>> a = np.genfromtxt("/home/ely/Desktop/Python/test.txt",delimiter=',',dtype=None) 
>>> print a.shape 
(3,5) 
>>> print a 
[['last' 'first' 'country' 'state' 'zip'] 
['tyson' 'mike' 'USA' 'Nevada' '89146'] 
['brady' 'tom' 'USA' 'Massachusetts' '02035']] 
>>> print a[0,:-1] 
['last' 'first' 'country' 'state'] 
>>> print a.dtype.names 
None 

Sto solo chiedendo cosa c'è di diverso i tuoi dati.

+0

Nota: questo era inteso come un commento, non una risposta ... solo bisogno di più spazio per mettere nell'esempio sopra. – ely

+0

Ciò che è diverso è che stai ricevendo un array di stringhe, non un array strutturato. Dai un'occhiata al dtype di 'a' nel tuo esempio. –

+0

Certo, ma cosa fa sì che l'array in ingresso sia "strutturato"? Se è solo un file csv, 'genfromtxt()' produce sempre un array di stringhe? – ely

Problemi correlati