2012-03-19 10 views
6

Me pregunto cuál es la mejor forma de normalizar/estandarizar un numpy recarray. Para dejar en claro, no estoy hablando de una matriz matemática, sino de una matriz de registros que también tiene, p. columnas textuales (como etiquetas).Normalize/Standardize a nuamy recarray

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

Como puede ver, no puedo, p. proceso a[:,:-1] ya que la forma es unidimensional.

El mejor que he encontrado es iterar sobre todas las columnas:

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

manera Cualquier más elegante de hacer esto? ¿Hay algún método como "normalizar" o "estandarizar" en alguna parte?

Respuesta

6

Hay varias maneras de hacerlo, pero algunas son más limpias que otras.

Normalmente, en numpy, mantiene los datos de la cadena en una matriz separada.

(Las cosas son un poco más bajo nivel que, por ejemplo, las tramas de datos del R. Por lo general, acaba de envolver las cosas en una clase de la asociación, pero mantener diferentes tipos de datos por separado.)

Honestamente, ¿no numpy 'optimizado para manejar tipos de datos' flexibles 'como este (aunque ciertamente puede hacerlo). Cosas como pandas proporcionan una mejor interfaz para los datos de "hoja de cálculo" (y pandas es solo una capa en la parte superior de numpy).

Sin embargo, las matrices estructuradas (que es lo que tiene aquí) le permitirán dividirlas en columnas cuando pasa una lista de nombres de campo. (Por ejemplo data[['col1', 'col2', 'col3']])

En cualquier caso, una forma es hacer algo como esto:

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) 

Sin embargo, esto está lejos de ser ideal. Si desea realizar la operación in situ (como lo hace actualmente), la solución más fácil es la que ya tiene: simplemente itere sobre los nombres de los campos.

Por cierto, utilizando pandas, que haría algo como esto:

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 Gracias. Esta es una respuesta muy informativa y perspicaz. Es probable que dividir el conjunto de datos en columnas numéricas y no numéricas sea el camino a seguir. Esto hace que muchas otras operaciones estén bien definidas y es, de hecho, lo que estaba tratando de hacer. No estaba al tanto de la opción de usar 'data [list]' para seleccionar varias columnas. –

1

¿Qué versión de NumPy está usando? Con la versión 1.5.1, no obtengo este comportamiento. Hice un archivo de texto corto como ejemplo, guardado como test.txt:

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

Cuando a continuación, ejecutar el siguiente código, esto es lo que me sale:

>>> 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 

me pregunto lo que es diferente acerca tu información.

+0

Nota: esto fue un comentario, no una respuesta ... solo necesitaba más espacio para poner en el ejemplo anterior. – ely

+0

Lo que es diferente es que está obteniendo una matriz de cadenas, no una matriz estructurada. Eche un vistazo al tipo de 'a' en su ejemplo. –

+0

Claro, pero ¿qué causa que la matriz entrante sea 'estructurada'? Si es solo un archivo csv, ¿'genfromtxt()' no producirá siempre una matriz de cadenas? – ely

Cuestiones relacionadas