2010-04-14 18 views
19

A menudo, estoy construyendo una matriz por iteración a través de algunos datos, por ejemplo .:Creando una matriz en numpy/scipy por iteración en Python?

my_array = [] 
for n in range(1000): 
    # do operation, get value 
    my_array.append(value) 
# cast to array 
my_array = array(my_array) 

me parece que tengo que construir primero una lista y luego echarlo (el uso de "matriz") a una matriz. ¿Hay alguna forma de evitar esto? Todas estas llamadas de fundición desordenan el código ... ¿cómo puedo construir iterativamente "my_array", siendo una matriz desde el principio?

+0

lo que sucede si no lo haces? – OscarRyz

+2

La razón por la que numpy es tan rápido en primer lugar es que opera con matrices de tamaño constante y no listas dinámicas. Así que deshacerse de él solo para reducir el "desorden" en su código probablemente no sea el camino correcto. Si conoce el tamaño de antemano (1000) preasignelo. Si no lo hace, crear la lista es definitivamente la mejor manera de hacerlo, ya que las listas de python [] son ​​bastante eficientes. – drozzy

Respuesta

-2

Si entiendo bien su pregunta, esto debería hacer lo que quiera:

# the array passed into your function 
ax = NP.random.randint(10, 99, 20).reshape(5, 4) 

# just define a function to operate on some data 
fnx = lambda x : NP.sum(x)**2 

# apply the function directly to the numpy array 
new_row = NP.apply_along_axis(func1d=fnx, axis=0, arr=ax) 

# 'append' the new values to the original array 
new_row = new_row.reshape(1,4) 
ax = NP.vstack((ax, new_row)) 
+4

Como esta es la respuesta aceptada, tengo que decir esto: He visto vstack usado mucho como este. Uno debe ser consciente de que esto es realmente (!) No-eficiente. Si construyes una gran matriz de esta manera, harás muchas operaciones innecesarias de copia de memoria. vea las respuestas debajo de – xaedes

15

La forma recomendada de hacer esto consiste en asignar previamente antes del bucle y el uso de rebanado y la indexación para insertar

my_array = numpy.zeros(1,1000) 
for i in xrange(1000): 
    #for 1D array 
    my_array[i] = functionToGetValue(i) 
    #OR to fill an entire row 
    my_array[i:] = functionToGetValue(i) 
    #or to fill an entire column 
    my_array[:,i] = functionToGetValue(i) 

numpy qué proporcionar un método array.resize(), pero esto será mucho más lento debido al coste de reasignando la memoria dentro de un bucle. Si tiene tiene tiene flexibilidad, entonces me temo que la única manera es crear un array desde un list.

EDITAR: Si le preocupa que esté asignando demasiada memoria para sus datos, usaría el método anterior para asignar en exceso y luego, cuando termine el ciclo, corte los bits no utilizados de la matriz usando array.resize(). Esto será , lejos más rápido que la reasignación constante de la matriz dentro del ciclo.

EDIT: En respuesta al comentario de @ user248237, suponiendo que conoce cualquiera de las dimensiones de la matriz (para simplificar):

my_array = numpy.array(10000, SOMECONSTANT) 

for i in xrange(someVariable): 
    if i >= my_array.shape[0]: 
     my_array.resize((my_array.shape[0]*2, SOMECONSTANT)) 

    my_array[i:] = someFunction() 

#lop off extra bits with resize() here 

El principio general es "asignar más de lo que cree que necesitará, y si las cosas cambian, cambie el tamaño de la matriz lo menos posible ". Duplicar el tamaño podría considerarse excesivo, pero de hecho este es el método utilizado por varias estructuras de datos en varias bibliotecas estándar en otros idiomas (java.util.Vector lo hace de forma predeterminada, por ejemplo. Creo que varias implementaciones de std::vector en C++ también lo hacen)

+2

¿Qué sucede si no sé el tamaño antes de tiempo? – user248237dfsf

+0

Eso tiene sentido, pero supongamos que construí las matrices de esta manera asignando más de lo que necesito, ¿cómo puedo iterar sobre la matriz? Si asigno numpy.zeros (1, 1000) pero solo uso 50 elementos, no quiero iterar hasta que llegue a cero ... el enfoque de sobreasignación parece crear esta extraña situación donde cada tipo de datos de matriz requerirá un diferente condición de "parada" para el bucle. ¿Hay alguna forma de evitar esto? – user248237dfsf

+0

Como dije, puede hacer una llamada final a 'resize()' cuando termine el ciclo. Si reduce la matriz al tamaño correcto, tirará todos los elementos cero. –

29

NumPy proporciona un método 'fromiter':

def myfunc(n): 
    for i in range(n): 
     yield i**2 


np.fromiter(myfunc(5), dtype=int) 

que produce

array([ 0, 1, 4, 9, 16]) 
+1

Cuando usa 'np.fromiter' y conoce el tamaño de la matriz de antemano, puede pasarlo como un parámetro para que la matriz sea preasignada. Esto aumenta el rendimiento inmensamente. Entonces, en el ejemplo anterior, haz: 'np.fromiter (myfunc (5), dtype = int, count = 5)' –