2012-06-27 11 views
9

Podczas wykonywania niektórych prac z zakresu bioinformatyki rozważałem konsekwencje przechowywania instancji obiektów w tablicy Numpy zamiast listy w Pythonie, ale we wszystkich testach Osiągnąłem gorszy występ w każdym przypadku. Używam CPython. Czy ktoś wie, dlaczego?Przechowywanie obiektów w języku Python na liście w języku Python w porównaniu z macierzą Numpy o stałej długości

Konkretnie:

  • Jakie są skutki Wyniki wykorzystania tablicę stałej długości numpy.ndarray(dtype=object) porównaniu z regularnym liście Python? Wstępne testy, które przeprowadziłem, wykazały, że dostęp do elementów tablicy Numpy był wolniejszy niż iteracja na liście Pythona, szczególnie przy użyciu metod obiektowych.
  • Dlaczego szybsze jest tworzenie instancji obiektów za pomocą funkcji sprawdzania listy, takiej jak [ X() for i in range(n) ] zamiast numpy.empty(size=n, dtype=object)?
  • Co to jest obciążenie pamięci każdego z nich? Nie byłem w stanie tego przetestować. Moje zajęcia intensywnie używają __slots__, jeśli ma to jakikolwiek wpływ.

Odpowiedz

16

Nie używaj tablic obiektów w numpy do takich rzeczy.

Pokonują podstawowy cel tablicy numpy, a gdy są przydatne w niewielkiej liczbie sytuacji, prawie zawsze są złym wyborem.

Tak, uzyskanie dostępu do pojedynczego elementu tablicy numpy w python lub iterowanie przez tablicę numpy w pythonie jest wolniejsze niż równoważna operacja z list. (Dlatego nigdy nie powinieneś robić czegoś takiego jak y = [item * 2 for item in x], gdy x jest tablicą numpy.)

Macierze obiektów Numpy będą miały nieco mniejszy narzut pamięci niż lista, ale jeśli przechowujesz wiele pojedynczych obiektów Pythona, Najpierw napotkasz inne problemy z pamięcią.

Numpy jest przede wszystkim efektywnym pod względem pamięci, wielowymiarowym pojemnikiem tablicowym dla jednolitych danych liczbowych. Jeśli chcesz przechowywać dowolne obiekty w tablicy numpy, prawdopodobnie potrzebujesz listy.


Chodzi mi o to, że jeśli chcesz efektywnie używać numpy, może być konieczne ponowne przemyślenie struktury.

Zamiast przechowywać każdą instancję obiektu w tablicy numpy, przechowuj swoje dane numeryczne w tablicy numpy, a jeśli potrzebujesz osobnych obiektów dla każdego wiersza/kolumny/cokolwiek, przechowuj indeks do tej tablicy w każdym wystąpieniu.

W ten sposób można szybko pracować z tablicami numerycznymi (np. Za pomocą numpy zamiast z listą).

Jako szybki przykład tego, co mówię, tu jest trywialny przykład bez użycia 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 

i podobny przykład za pomocą numpy tablice:

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 

Istnieją inne sposoby Aby to zrobić (możesz chcieć uniknąć zapisywania odwołania do konkretnej tablicy w każdym point, ale mam nadzieję, że jest to przydatny przykład.

Zwróć uwagę na różnicę prędkości, z jaką działają. Na mojej maszynie różnica wynosi 5 sekund w przypadku wersji numpy w porównaniu z 60 sekund w przypadku wersji z czystym pythonem.