python - 在 Python 列表中存储 Python 对象与固定长度的 Numpy 数组

标签 python performance numpy python-3.x cpython

在做一些生物信息学工作时,我一直在思考将对象实例存储在 Numpy 数组而不是 Python 列表中的后果,但在我进行的所有测试中,每个实例的性能都更差。我正在使用 CPython。有谁知道原因吗?

具体来说:

  • 与常规 Python 列表相比,使用固定长度数组 numpy.ndarray(dtype=object) 对性能有何影响?我执行的初始测试表明,访问 Numpy 数组元素比通过 Python 列表进行迭代要慢,尤其是在使用对象方法时。
  • 为什么使用 [ X() for i in range(n) ] 而不是 numpy.empty(size=n, dtype =对象)
  • 每个的内存开销是多少?我无法对此进行测试。如果有任何影响,我的类(class)广泛使用 __slots__

最佳答案

不要在 numpy 中使用对象数组来做这样的事情。

它们违背了 numpy 数组的基本目的,虽然它们在极少数情况下很有用,但它们几乎总是一个糟糕的选择。

是的,在 python 中访问 numpy 数组的单个元素或在 python 中遍历 numpy 数组比使用 list 的等效操作要慢。 (这就是为什么当 x 是一个 numpy 数组时,你不应该做类似 y = [item * 2 for item in x] 的原因。)

Numpy 对象数组的内存开销比列表略低,但如果您要存储那么多单独的 Python 对象,您将首先遇到其他内存问题。

Numpy 首先是一个内存高效的多维数组容器,用于统一数值数据。如果您想在 numpy 数组中保存任意对象,您可能需要一个列表。


我的观点是,如果您想有效地使用 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

还有其他方法可以做到这一点(例如,您可能希望避免在每个 point 中存储对特定 numpy 数组的引用),但我希望它是一个有用的例子。

注意它们运行速度的差异。在我的机器上,numpy 版本相差 5 秒,纯 python 版本相差 60 秒。

关于python - 在 Python 列表中存储 Python 对象与固定长度的 Numpy 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11232597/

相关文章:

python - 构建这个简单工厂类的更 pythonic 方法是什么?

C++(哈希)映射速度优化

android - UI 应该中断的最长时间是多少?

python - 跳过每组中的前 n 行

Python/Scipy : Find "bounded" min/max of a matrix

python - 无法使用for循环处理大量数据

python - 如何从一组日期列中获取最大日期值

python - 计算 Pandas 几列中项目的平均值

Python 包装。指定多次发布后的python版本要求

performance - 微调 HTML5 Phonegap 应用程序