2011-09-09 38 views
5

Me encuentro analizando muchos archivos de datos (generalmente en un archivo .csv o similar) usando el lector csv y un ciclo for para iterar sobre cada línea. Los datos suelen ser una tabla de flotantes, por ejemplo.Manera pitónica de poblar la matriz numpy

reader = csv.reader(open('somefile.csv')) 
header = reader.next() 

res_list = [list() for i in header]  

for line in reader: 
    for i in range(len(line)): 
    res_list[i].append(float(line[i])) 

result_dict = dict(zip(header,res_list)) #so we can refer by column title 

Ésta es una forma aceptable para poblar lo que obtener cada columna como una lista separada sin embargo, yo prefiero que el contenedor de datos por defecto para las listas de artículos (y listas anidadas) ser matrices numpy, ya que 99 veces 100 los números se bombean en varios scripts/funciones de procesamiento y tener el poder de las listas numpy me hace la vida más fácil.

numpy append(arr, item) no se agrega en el lugar y, por lo tanto, requeriría volver a crear matrices para cada punto de la tabla (que es lento e innecesario). También podría iterar sobre la lista de columnas de datos y envolverlas en una matriz después de que haya terminado (que es lo que he estado haciendo), pero a veces no es tan claro sobre cuando He terminado analizar el archivo y puede necesitar agregar cosas a la lista más adelante en la línea de todos modos.

Me preguntaba si hay alguna forma menos pesada de la caldera (para usar la frase usada "pythonic") para procesar tablas de datos de una manera similar, o para poblar matrices (donde el contenedor subyacente es una lista) dinámicamente y sin copiar matrices todo el tiempo.

(En otra nota: es un poco molesto que en general las personas usen columnas para organizar datos pero csv lee en filas si el lector incorporó un argumento read_column (sí, sé que no sería súper eficiente), creo muchas personas se evitaría tener código de placa de la caldera como el anterior para analizar un archivo de datos CSV)

Respuesta

7

No es numpy.loadtxt:.

X = numpy.loadtxt('somefile.csv', delimiter=',') 

Documentation.


Editar: para obtener una lista de matrices numpy,

X = [scipy.array(line.split(','), dtype='float') 
    for line in open('somefile.csv', 'r')] 
+1

He pensado en esto antes, pero tiene algunos problemas, en particular, se requiere que la longitud del registro sea la misma por la formación. Aunque mi pequeño fragmento asume lo mismo, no siempre ocurre (por ejemplo, filas vacías para indicar interrupciones entre las ráfagas de recopilación de datos). – crasic

+0

Si lo entiendo correctamente, vea editar. –

2

creo que es difícil mejorar en gran medida de lo que tiene. Las listas de Python son relativamente baratas de construir y anexar; Las matrices NumPy son más costosas de crear y no ofrecen ningún método .append(). Por lo tanto, su mejor opción es compilar las listas como lo que ya está haciendo y luego forzar al np.array() cuando llegue el momento.

Unos pequeños puntos:

  • Es ligeramente más rápido usar [] para crear una lista de llamar list(). Esta es una cantidad tan pequeña del tiempo de ejecución del programa que puede sentirse libre de ignorar este punto.

  • Cuando no utiliza realmente el índice de bucle, puede usar _ para el nombre de la variable para documentar esto.

  • Por lo general, es mejor iterar en una secuencia que encontrar la longitud de la secuencia, crear un range() y luego indexar la secuencia mucho. Puede usar enumerate() para obtener un índice si también necesita el índice.

Ponlo todo junto y creo que esta es una versión ligeramente mejorada. Pero casi no ha cambiado desde su original, y no puedo pensar en ninguna mejora realmente buena.

reader = csv.reader(open('somefile.csv')) 
header = reader.next() 

res_list = [ [] for _ in header] 

for row in reader: 
    for i, val in enumerate(row): 
     res_list[i].append(float(val)) 

# build dict so we can refer by column title 
result_dict = dict((n, res_list[i]) for i, n in enumerate(header)) 
+0

"NumPy ... no ofrece un método .append() en absoluto" NumPy ciertamente tiene un método de adición. Funciona más o menos como apéndice de pitón, excepto que no está "en su lugar". – doug

+0

@doug: 'a = np.array (rango (3))' tiene éxito. Entonces, 'a.append (4)' da el mensaje 'AttributeError: 'numpy.ndarray' object no tiene el atributo 'append''. Si las matrices NumPy tienen un método '.append()', entonces, ¿qué estoy haciendo mal aquí? – steveha

+0

así que intente esto: a = NP.random.randint (0, 10, 5); a = NP.append (a, [2, 3]). Así que NumPy tiene una función * de anexión *, no un método de adición, ¡lo que hace que tu afirmación en tu respuesta sea completamente correcta! – doug

2

Para cargar datos de manera eficiente a un NumPy Arraya, me gusta fromiter función de NumPy.

ventajas en este contexto:

  • corriente-como carga,

  • pre-especificar los datos de tipo de la matriz reesult, y

  • pre-asignar vacío matriz de salida, que es entonces poblado con la secuencia de iterable.

El primero de ellos es inherent-- fromiter sólo acepta la entrada de datos en forma iterables - los dos últimos son gestionados a través de la segunda y tercera argumentos pasados ​​a fromiter, dtype, y recuento.

>>> import numpy as NP 
>>> # create some data to load: 
>>> import random 
>>> source_iterable = (random.choice(range(100)) for c in range(20)) 

>>> target = NP.fromiter(source_iterable, dtype=NP.int8, count=v.size) 
>>> target 
     array([85, 28, 37, 4, 23, 5, 47, 17, 78, 40, 28, 5, 69, 47, 15, 92, 
      41, 33, 33, 98], dtype=int8) 

Si no desea cargar sus datos usando un iterable, todavía puede pre-asignar de memoria para la matriz de destino, utilizando las funciones NumPy vacío, y empty_like

>>> source_vec = NP.random.rand(10) 
>>> target = NP.empty_like(source_vec) 
>>> target[:] = source_vec 
>>> target 
    array([ 0.5472, 0.5085, 0.0803, 0.4757, 0.4831, 0.3054, 0.1024, 
      0.9073, 0.6863, 0.3575]) 

Alternativamente, puede crear una matriz vacía (preasignada) llamando al vacío, y luego simplemente pasando la forma que desee. Esta función, a diferencia de empty_like, vamos a pasar en el tipo de datos:

>>> target = NP.empty(shape=s.shape, dtype=NP.float) 
>>> target 
    array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]) 
>>> target[:] = source 
>>> target 
    array([ 0.5472, 0.5085, 0.0803, 0.4757, 0.4831, 0.3054, 0.1024, 
      0.9073, 0.6863, 0.3575]) 
+0

+1 para np.fromiter – tdc

Cuestiones relacionadas