【问题标题】:dynamic arrays and speed in python - fastest way to grow an arraypython中的动态数组和速度-增长数组的最快方法
【发布时间】:2016-01-12 01:10:37
【问题描述】:

我发现了一些关于这个问题的一般帖子(尤其是列表与数组),但我想知道是否有人知道使用 numpy.append 或重新分配条目是否更快?

具体来说,如果您知道您将拥有一个最大大小为 100 的数组,但不确定最终大小,那么最好:

array_to_mod = np.zeros(100)
for something in loop:
    array_to_mod[something] = new_value
final_array = array_to_mod[0:len(loop)]

其中循环是一些你事先不知道的数字,除非它低于 100,或者类似:

final_array = np.array([])
for something in loop:
    final_array = np.append(final_array, new_value)

想法?

【问题讨论】:

  • 我会选择第一个。
  • 正如@Divakar 建议的那样,我也认为保留最大空间量(如果它接近最终形状)然后返回一个view 或一个copy 仅有趣的部分会比迭代连接现有数组更有效。

标签: python arrays numpy


【解决方案1】:

性能测试:

def func1(new_value):
    array_to_mod = np.zeros(100)
    for i in range(0,100):
        array_to_mod[i] = new_value
    final_array = array_to_mod[0:len(range(0,100))]
    return final_array

def func2(new_value):
    final_array = np.array([])
    for i in range(0,100):
        final_array = np.append(final_array, new_value)
    return(final_array)

In [236]: %timeit func1(1)
10000 loops, best of 3: 23.5 us per loop

In [237]: %timeit func2(1)
1000 loops, best of 3: 789 us per loop

所以第一种方法要快得多,你应该像评论中提到的@Divakar 那样使用它

【讨论】:

    【解决方案2】:

    np.append 显然是重复使用的错误选择。这只是np.concatenate 的封面。在这种情况下,它实际上是:

    final_array = np.concatenate(final_array, [new_value])
    

    它用一个新值创建一个新数组。每次迭代都创建一个新数组是最耗时的(而不是复制)。

    但是列表追加是一个不错的选择 -

    def func3(new_value):
        alist=[]
        for i in range(0,100):
            alist.append(new_value)
        return np.array(alist)
    

    在我的快速测试中,它与Anton's func1 一样快。

    func3 可以用列表推导式重写,速度适度提高。

     return np.array([new_value for _ in range(0,100)])
    

    但这里的速度是原来的 2 倍:

    def func4(new_value):
        return np.fromiter([new_value for _ in range(0,100)], int, count=100)
    

    fromiter 的表达式可以是一个生成器,尽管在这种情况下它没有任何区别。

    【讨论】:

      【解决方案3】:

      我同意对于 numpy 数组,案例 1 通常应该更快,但计时是正确的方法。

      同样对于矩阵,如果要追加一列 1(或 0),复制数组比内部的 hstack 方法更快。

      temp = np.copy(X)
      X = np.ones([m,n+1])
      X[:,1:] = temp
      del temp
      

      执行速度比

      X = np.hstack( [np.ones([m, 1]), X] )
      

      在许多情况下,后者仍然是首选,因为它简洁甚至可读性。

      如果你知道最后附加了多少元素,你也许可以收集它们并将数组堆叠在一起:

      array_to_mod = np.zeros(100)
      def stack(old, new):
          out = np.ones(len(old)+len(new))
          out[0:len(old)] = old
          out[len(old):] = new
          return out
      

      【讨论】:

        【解决方案4】:

        根据numpy.append documentation

        值被附加到该数组的副本中。

        所以第二种方法的复杂度为 O(n²),而第一种方法的复杂度为 O(n)。

        另外一点:numpy.array 单独访问很慢,所以你在 python 列表上会更快。这里最好的方法可能是:

        final_list = []
        for something in loop:
            final_list.append(new_value)
        final_array=np.array(final_list)
        

        最后,numpy 一维数组是为向量化而设计的,所以不能用 for 循环来管理。实现这一目标取决于具体问题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-11-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-23
          • 2021-07-13
          相关资源
          最近更新 更多