2012-06-27 12 views
9

Al hacer un trabajo bioinformático, he estado reflexionando sobre las ramificaciones de almacenar instancias de objetos en una matriz Numpy en lugar de una lista de Python, pero en todas las pruebas He hecho que el rendimiento fue peor en todos los casos. Estoy usando CPython. ¿Alguien sabe el motivo por qué?Almacenar objetos de Python en una lista de Python vs. una matriz Numpy de longitud fija

Específicamente:

  • ¿Cuáles son los impactos en el rendimiento de la utilización de una matriz de longitud fija numpy.ndarray(dtype=object) frente a una lista de Python regular? Las pruebas iniciales que realicé mostraron que el acceso a los elementos de la matriz Numpy era más lento que la iteración a través de la lista de Python, especialmente cuando se usan métodos de objetos.
  • ¿Por qué es más rápido crear instancias de objetos utilizando una lista de comprensión como [ X() for i in range(n) ] en lugar de numpy.empty(size=n, dtype=object)?
  • ¿Cuál es la sobrecarga de memoria de cada uno? No pude probar esto. Mis clases usan ampliamente __slots__, si eso tiene algún impacto.

Respuesta

16

No utilice matrices de objetos en numpy para cosas como esta.

Derrotan el propósito básico de una matriz numpy, y si bien son útiles en un pequeño puñado de situaciones, casi siempre son una mala elección.

Sí, acceder a un elemento individual de una matriz numpy en python o iterar a través de una matriz numpy en python es más lento que la operación equivalente con list. (Razón por la cual nunca se debe hacer algo como y = [item * 2 for item in x] cuando x es una matriz numpy.)

numpy matrices de objetos tendrán una sobrecarga de memoria ligeramente inferior a una lista, pero si usted está almacenando que muchos objetos pitón individuales, Primero se encontrará con otros problemas de memoria.

Numpy es, ante todo, un contenedor de matriz multidimensional eficiente en cuanto a la memoria para datos numéricos uniformes. Si desea mantener objetos arbitrarios en una matriz numpy, es probable que desee una lista.


Mi punto es que si desea utilizar numpy efectivamente, puede que tenga que volver a pensar en cómo se está estructurando cosas.

En lugar de almacenar cada instancia de objeto en una matriz numpy, almacenar sus datos numéricos en una matriz numpy, y si necesita objetos separados para cada fila/columna/lo que sea, almacenar un índice dentro de esa matriz en cada caso.

De esta forma puede operar los arreglos numéricos rápidamente (es decir, usando numpy en lugar de listas de comprensión).

Como un ejemplo rápido de lo que estoy hablando, he aquí un ejemplo trivial sin utilizar numpy:

from random import random 

class PointSet(object): 
    def __init__(self, numpoints): 
     self.points = [Point(random(), random()) for _ in xrange(numpoints)] 

    def update(self): 
     for point in self.points: 
      point.x += random() - 0.5 
      point.y += random() - 0.5 

class Point(object): 
    def __init__(self, x, y): 
     self.x = x 
     self.y = y 

points = PointSet(100000) 
point = points.points[10] 

for _ in xrange(1000): 
    points.update() 
    print 'Position of one point out of 100000:', point.x, point.y 

Y un ejemplo similar utilizando matrices numpy:

import numpy as np 

class PointSet(object): 
    def __init__(self, numpoints): 
     self.coords = np.random.random((numpoints, 2)) 
     self.points = [Point(i, self.coords) for i in xrange(numpoints)] 

    def update(self): 
     """Update along a random walk.""" 
     # The "+=" is crucial here... We have to update "coords" in-place, in 
     # this case. 
     self.coords += np.random.random(self.coords.shape) - 0.5 

class Point(object): 
    def __init__(self, i, coords): 
     self.i = i 
     self.coords = coords 

    @property 
    def x(self): 
     return self.coords[self.i,0] 

    @property 
    def y(self): 
     return self.coords[self.i,1] 


points = PointSet(100000) 
point = points.points[10] 

for _ in xrange(1000): 
    points.update() 
    print 'Position of one point out of 100000:', point.x, point.y 

Hay otras maneras para hacer esto (es posible que desee evitar el almacenamiento de una referencia a un matriz numpy específica en cada point, por ejemplo), pero espero que sea un ejemplo útil.

Tenga en cuenta la diferencia en la velocidad a la que se ejecutan. En mi máquina, es una diferencia de 5 segundos para la versión de numpy frente a 60 segundos para la versión de python puro.

Cuestiones relacionadas