【问题标题】:NumPy array initialization (fill with identical values)NumPy 数组初始化(填充相同的值)
【发布时间】:2011-08-18 23:36:39
【问题描述】:

我需要创建一个长度为n 的NumPy 数组,其中每个元素都是v

还有什么比:

a = empty(n)
for i in range(n):
    a[i] = v

我知道zerosones 适用于v = 0, 1。我可以使用v * ones(n),但它vNone 时它不起作用,并且也 s> 会慢很多。

【问题讨论】:

  • 在我的电脑上,对于 0 的情况,在循环中使用 a = np.zeros(n)a.fill(0) 快。这与我的预期相反,因为我认为a=np.zeros(n) 需要分配和初始化新内存。如果有人能解释一下,我将不胜感激。
  • 你不能把 None 放在一个 numpy 数组中,因为单元格是用特定的数据类型创建的,而 None 有它自己的类型,实际上是一个指针。
  • @Camion 是的,我现在知道了 :) 当然v * ones(n) 仍然很糟糕,因为它使用了昂贵的乘法。不过,将* 替换为+,而v + zeros(n) 在某些情况下会出奇地好(stackoverflow.com/questions/5891410/…)。
  • max,而不是在添加 v 之前创建一个带有零的数组,使用 var = np.empty(n) 创建它为空然后用 'var[:] = v' 填充它会更快。 (顺便说一句,np.full() 和这个一样快)

标签: python arrays numpy


【解决方案1】:

我相信fill 是最快的方法。

a = np.empty(10)
a.fill(7)

您还应该始终避免像在示例中那样进行迭代。一个简单的 a[:] = v 将使用 numpy broadcasting 完成您的迭代。

【讨论】:

  • 谢谢。在查看fill 时,我发现repeat 更适合我的需求。
  • 您介意更新您的答案,说您对a[:]=v 的推荐实际上比fill 总体上更快吗?
  • @max 更快吗?广播是一种更通用的填充数组的方法,我猜它会更慢或等于 fill 的非常狭窄的用例。
【解决方案2】:

您可以使用numpy.tile,例如:

v = 7
rows = 3
cols = 5
a = numpy.tile(v, (rows,cols))
a
Out[1]: 
array([[7, 7, 7, 7, 7],
       [7, 7, 7, 7, 7],
       [7, 7, 7, 7, 7]])

虽然tile 旨在“平铺”一个数组(而不是本例中的标量),但它可以完成这项工作,创建任何大小和维度的预填充数组。

【讨论】:

    【解决方案3】:

    为 Numpy 1.7.0 更新:(向@Rolf Bartstra 致敬。)

    a=np.empty(n); a.fill(5) 最快。

    按速度降序排列:

    %timeit a=np.empty(10000); a.fill(5)
    100000 loops, best of 3: 5.85 us per loop
    
    %timeit a=np.empty(10000); a[:]=5 
    100000 loops, best of 3: 7.15 us per loop
    
    %timeit a=np.ones(10000)*5
    10000 loops, best of 3: 22.9 us per loop
    
    %timeit a=np.repeat(5,(10000))
    10000 loops, best of 3: 81.7 us per loop
    
    %timeit a=np.tile(5,[10000])
    10000 loops, best of 3: 82.9 us per loop
    

    【讨论】:

    • 为最近的和直接的np.full() 添加时间会很有用。在我的机器上,使用 NumPy 1.8.1,它比不那么直接的 fill() 版本慢了大约 15%(这​​是出乎意料的,因为 full() 有可能会稍微快一点)。
    • @DavidSanders:我不确定我是否在关注你:fill() 是最快的解决方案。乘法解要慢得多。
    • 注意:如果速度真的是一个问题,使用 10000 的大小而不是 1e4 会产生明显的差异,出于某种原因(full() 几乎慢 50%,@987654330 @)。
    • 只需将我的结果与full() 相加,当数据类型不是明确的浮点数时,它的运行速度要慢得多。否则,它与这里的最佳方法相当(但稍慢)。
    • @user2699 我没有注意到这一点,有 100,000 个元素:full(100000, 5)full(100000, 5, dtype=float)full(100000, 5, dtype=int)a =np.empty(100000); a.fill(5) 在我的机器上都花费大约相同的时间(没有缓存:@ 987654336@) (NumPy 1.11.2)。
    【解决方案4】:

    显然,不仅绝对速度,而且速度顺序(由 user1579844 报告)都取决于机器;这是我发现的:

    a=np.empty(1e4); a.fill(5) 最快;

    按速度降序排列:

    timeit a=np.empty(1e4); a.fill(5) 
    # 100000 loops, best of 3: 10.2 us per loop
    timeit a=np.empty(1e4); a[:]=5
    # 100000 loops, best of 3: 16.9 us per loop
    timeit a=np.ones(1e4)*5
    # 100000 loops, best of 3: 32.2 us per loop
    timeit a=np.tile(5,[1e4])
    # 10000 loops, best of 3: 90.9 us per loop
    timeit a=np.repeat(5,(1e4))
    # 10000 loops, best of 3: 98.3 us per loop
    timeit a=np.array([5]*int(1e4))
    # 1000 loops, best of 3: 1.69 ms per loop (slowest BY FAR!)
    

    因此,请尝试找出并使用您平台上最快的东西。

    【讨论】:

      【解决方案5】:

      NumPy 1.8 引入了np.full(),这是一种比empty() 后跟fill() 更直接的方法,用于创建填充有特定值的数组:

      >>> np.full((3, 5), 7)
      array([[ 7.,  7.,  7.,  7.,  7.],
             [ 7.,  7.,  7.,  7.,  7.],
             [ 7.,  7.,  7.,  7.,  7.]])
      
      >>> np.full((3, 5), 7, dtype=int)
      array([[7, 7, 7, 7, 7],
             [7, 7, 7, 7, 7],
             [7, 7, 7, 7, 7]])
      

      这可以说是创建一个填充了特定值的数组的方式,因为它明确地描述了正在实现的目标(原则上它可以非常有效,因为它执行一项非常具体的任务)。

      【讨论】:

      • 这个 full() 方法对我来说效果很好,但我找不到它的一些文档。谁能指出我正确的地方?
      • 您至少可以在 Python shell 中执行help(numpy.full)。我也很惊讶它不在网络文档中。
      • 在我的系统(Python 2.7,Numpy 1.8)上,np.full() 实际上比 np.empty() 慢一点,然后是 np.fill()。
      • 对于 10,000 个元素,我观察到相同的情况(除了 np.fill() 不存在,应该是 arr.fill()),相差约 10%。如果差异更大,我会在 NumPy 错误跟踪器中提出问题。 :) 我更喜欢更明确和更清晰的代码,因为执行时间的差异如此之小,所以我一直使用np.full()
      • 在我的机器上 np.full() 与 np.array.fill() 的速度相同
      【解决方案6】:

      我想到了np.array(n * [value]),但显然这比所有其他足够大的n 建议要慢。在可读性和速度方面最好的是

      np.full(n, 3.14)
      

      这是与perfplot(我的一个宠物项目)的完整比较。

      两个empty 替代方案仍然是最快的(使用 NumPy 1.12.1)。 full 赶上大型数组。


      生成绘图的代码:

      import numpy as np
      import perfplot
      
      
      def empty_fill(n):
          a = np.empty(n)
          a.fill(3.14)
          return a
      
      
      def empty_colon(n):
          a = np.empty(n)
          a[:] = 3.14
          return a
      
      
      def ones_times(n):
          return 3.14 * np.ones(n)
      
      
      def repeat(n):
          return np.repeat(3.14, (n))
      
      
      def tile(n):
          return np.repeat(3.14, [n])
      
      
      def full(n):
          return np.full((n), 3.14)
      
      
      def list_to_array(n):
          return np.array(n * [3.14])
      
      
      perfplot.show(
          setup=lambda n: n,
          kernels=[empty_fill, empty_colon, ones_times, repeat, tile, full, list_to_array],
          n_range=[2 ** k for k in range(27)],
          xlabel="len(a)",
          logx=True,
          logy=True,
      )
      

      【讨论】:

        【解决方案7】:

        没有 numpy

        >>>[2]*3
        [2, 2, 2]
        

        【讨论】:

        • 建议 [v] * n 会更直接地与 OP 问题相关。
        • This answer 已经提到过这种方法。
        猜你喜欢
        • 2020-12-28
        • 1970-01-01
        • 1970-01-01
        • 2015-08-05
        • 2018-12-31
        • 2018-10-29
        • 1970-01-01
        • 1970-01-01
        • 2014-10-04
        相关资源
        最近更新 更多