Вопрос по numpy, performance, python-3.x, cpython, python – Хранение объектов Python в списке Python против массива Numpy фиксированной длины
Выполняя некоторые работы по биоинформатике, я размышлял о последствиях сохранения экземпляров объектов в массиве Numpy, а не в списке Python, но во всех проведенных мною тестах производительность была хуже в каждом случае. Я использую CPython. Кто-нибудь знает причину почему?
В частности:
What are the performance impacts of using a fixed-length arraynumpy.ndarray(dtype=object)
vs. a regular Python list? Initial tests I performed showed that accessing the Numpy array elements was slower than iteration through the Python list, especially when using object methods.
Why is it faster to instantiate objects using a list comprehension such as [ X() for i in range(n) ]
instead of a numpy.empty(size=n, dtype=object)
?
What is the memory overhead of each? I was not able to test this. My classes extensively use __slots__
, if that has any impact.
Они побеждают основную цель массива numpy, и хотя они полезны в крошечной горстке ситуаций, они почти всегда плохой выбор.
Да, доступ к отдельному элементу массива NumPy в Python или итерации по массиву NUMPY в Python медленнее, чем эквивалентная операция сlist
. (Вот почему вы никогда не должны делать что-то вродеy = [item * 2 for item in x]
когдаx
- это массив пустяков.)
Numpy объектные массивы будут иметь немного меньшую нагрузку на память, чем список, но если вы храните столько отдельных объектов Python, вы сначала столкнетесь с другими проблемами с памятью.
Numpy - это, прежде всего, эффективный для памяти контейнер многомерных массивов для единообразных числовых данных. Если вы хотите хранить произвольные объекты в массиве numpy, вам, скорее всего, нужен список.
Суть в том, что если вы хотите эффективно использовать numpy, вам, возможно, придется переосмыслить, как вы структурируете вещи.
Вместо того, чтобы хранить каждый экземпляр объекта в массиве, храните ваш Численная данных в массивном массиве, и если вам нужны отдельные объекты для каждой строки / столбца / чего угодно, сохраняйте индекс в этом массиве в каждом экземпляре.
Таким образом, вы можете быстро работать с числовыми массивами (т.е. использовать numpy вместо списочных представлений).
В качестве быстрого примера того, о чем я говорю, вот тривиальный пример без использования 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
И похожий пример, использующий массивы 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
Есть и другие способы сделать это (вы можете избежать сохранения ссылки наконкретны массив numpy в каждомpoint
, например), но я надеюсь, что это полезный пример.
Отметьте разницу в скорости, с которой они бегут. На моей машине разница в 5 секунд для простой версии и 60 секунд для чистой версии Python.