【问题标题】:Interweaving two numpy arrays交织两个numpy数组
【发布时间】:2011-07-17 20:27:19
【问题描述】:

假设给定以下数组:

a = array([1,3,5])
b = array([2,4,6])

如何有效地将它们交织在一起,以便获得第三个这样的数组

c = array([1,2,3,4,5,6])

可以假设length(a)==length(b)。

【问题讨论】:

  • 怎么样,同样的问题,但你正试图交错矩阵。即 a 和 b 是 3 维的,并且在第一维中不一定大小相同。注意:只有第一个维度应该交错。

标签: python arrays numpy


【解决方案1】:

另一条线:np.vstack((a,b)).T.ravel()
还有一个:np.stack((a,b),1).ravel()

【讨论】:

    【解决方案2】:

    我需要这样做,但要使用沿任意轴的多维数组。这是一个快速的通用功能。它与np.concatenate 具有相同的调用签名,除了所有输入数组必须具有完全相同相同的形状。

    import numpy as np
    
    def interleave(arrays, axis=0, out=None):
        shape = list(np.asanyarray(arrays[0]).shape)
        if axis < 0:
            axis += len(shape)
        assert 0 <= axis < len(shape), "'axis' is out of bounds"
        if out is not None:
            out = out.reshape(shape[:axis+1] + [len(arrays)] + shape[axis+1:])
        shape[axis] = -1
        return np.stack(arrays, axis=axis+1, out=out).reshape(shape)
    

    【讨论】:

    • +1 用于这种通用配方(适用于 n-dim,沿任意轴交错,适用于任意数量的输入数组,采用可选的 out arg,适用于子类数组)。就个人而言,我更喜欢axis 默认为-1 而不是0,但也许这只是我。您可能想从this question 链接到您的这个答案,它实际上要求输入数组是n 维的。
    【解决方案3】:

    改进@xioxox 的回答:

    import numpy as np
    a = np.array([1,3,5])
    b = np.array([2,4,6])
    inter = np.ravel((a,b), order='F')
    

    【讨论】:

      【解决方案4】:

      我认为检查解决方案在性能方面的表现可能是值得的。结果是这样的:

      这清楚地表明most upvoted and accepted answer (Pauls answer) 也是最快的选项。

      代码取自其他答案和another Q&A:

      # Setup
      import numpy as np
      
      def Paul(a, b):
          c = np.empty((a.size + b.size,), dtype=a.dtype)
          c[0::2] = a
          c[1::2] = b
          return c
      
      def JoshAdel(a, b):
          return np.vstack((a,b)).reshape((-1,),order='F')
      
      def xioxox(a, b):
          return np.ravel(np.column_stack((a,b)))
      
      def Benjamin(a, b):
          return np.vstack((a,b)).ravel([-1])
      
      def andersonvom(a, b):
          return np.hstack( zip(a,b) )
      
      def bhanukiran(a, b):
          return np.dstack((a,b)).flatten()
      
      def Tai(a, b):
          return np.insert(b, obj=range(a.shape[0]), values=a)
      
      def Will(a, b):
          return np.ravel((a,b), order='F')
      
      # Timing setup
      timings = {Paul: [], JoshAdel: [], xioxox: [], Benjamin: [], andersonvom: [], bhanukiran: [], Tai: [], Will: []}
      sizes = [2**i for i in range(1, 20, 2)]
      
      # Timing
      for size in sizes:
          func_input1 = np.random.random(size=size)
          func_input2 = np.random.random(size=size)
          for func in timings:
              res = %timeit -o func(func_input1, func_input2)
              timings[func].append(res)
      
      %matplotlib notebook
      
      import matplotlib.pyplot as plt
      import numpy as np
      
      fig = plt.figure(1)
      ax = plt.subplot(111)
      
      for func in timings:
          ax.plot(sizes, 
                  [time.best for time in timings[func]], 
                  label=func.__name__)  # you could also use "func.__name__" here instead
      ax.set_xscale('log')
      ax.set_yscale('log')
      ax.set_xlabel('size')
      ax.set_ylabel('time [seconds]')
      ax.grid(which='both')
      ax.legend()
      plt.tight_layout()
      

      万一你有 numba 可用,你也可以用它来创建一个函数:

      import numba as nb
      
      @nb.njit
      def numba_interweave(arr1, arr2):
          res = np.empty(arr1.size + arr2.size, dtype=arr1.dtype)
          for idx, (item1, item2) in enumerate(zip(arr1, arr2)):
              res[idx*2] = item1
              res[idx*2+1] = item2
          return res
      

      它可能比其他替代方案稍快:

      【讨论】:

      • 另外值得注意的是,接受的答案比使用 itertools 配方中的 roundrobin() 的原生 Python 解决方案快方式。
      【解决方案5】:

      也可以试试np.insert。 (解决方案迁移自Interleave numpy arrays)

      import numpy as np
      a = np.array([1,3,5])
      b = np.array([2,4,6])
      np.insert(b, obj=range(a.shape[0]), values=a)
      

      请参阅documentation 和tutorial 了解更多信息。

      【讨论】:

        【解决方案6】:

        这是一个比之前的一些更简单的答案

        import numpy as np
        a = np.array([1,3,5])
        b = np.array([2,4,6])
        inter = np.ravel(np.column_stack((a,b)))
        

        在此inter 之后包含:

        array([1, 2, 3, 4, 5, 6])
        

        这个答案似乎也稍微快了一点:

        In [4]: %timeit np.ravel(np.column_stack((a,b)))
        100000 loops, best of 3: 6.31 µs per loop
        
        In [8]: %timeit np.ravel(np.dstack((a,b)))
        100000 loops, best of 3: 7.14 µs per loop
        
        In [11]: %timeit np.vstack((a,b)).ravel([-1])
        100000 loops, best of 3: 7.08 µs per loop
        

        【讨论】:

          【解决方案7】:

          这将交错/交错两个数组,我相信它非常可读:

          a = np.array([1,3,5])      #=> array([1, 3, 5])
          b = np.array([2,4,6])      #=> array([2, 4, 6])
          c = np.hstack( zip(a,b) )  #=> array([1, 2, 3, 4, 5, 6])
          

          【讨论】:

          • 我喜欢这个可读性最强的。尽管它是最慢的解决方案。
          • 将zip 包裹在list 中以避免折旧警告
          【解决方案8】:

          vstack 当然是一个选项,但更直接的解决方案可能是hstack

          >>> a = array([1,3,5])
          >>> b = array([2,4,6])
          >>> hstack((a,b)) #remember it is a tuple of arrays that this function swallows in.
          >>> array([1, 3, 5, 2, 4, 6])
          >>> sort(hstack((a,b)))
          >>> array([1, 2, 3, 4, 5, 6])
          

          更重要的是,这适用于a 和b 的任意形状

          你也可以试试dstack

          >>> a = array([1,3,5])
          >>> b = array([2,4,6])
          >>> dstack((a,b)).flatten()
          >>> array([1, 2, 3, 4, 5, 6])
          

          你现在有了选择!

          【讨论】:

          • -1 首先回答,因为问题与排序无关。 +1 到第二个答案,这是迄今为止我见过的最好的答案。这就是为什么应将多个解决方案作为多个答案发布的原因。请将其拆分为多个答案。
          【解决方案9】:

          也许这比@JoshAdel 的解决方案更具可读性:

          c = numpy.vstack((a,b)).ravel([-1])
          

          【讨论】:

          • ravel 在the documentation 中的order 参数是C、F、A 或K 之一。我认为你真的想要.ravel('F'),用于 FORTRAN 订单(列第一)
          【解决方案10】:

          我喜欢乔希的回答。我只是想添加一个更平凡、更普通、更冗长的解决方案。不知道哪个更有效率。我希望他们会有类似的表现。

          import numpy as np
          a = np.array([1,3,5])
          b = np.array([2,4,6])
          
          c = np.empty((a.size + b.size,), dtype=a.dtype)
          c[0::2] = a
          c[1::2] = b
          

          【讨论】:

          • 除非速度真的很重要,否则我会选择这个,因为它更容易理解,如果有人想再看一遍,这很重要。
          • +1 我玩过时间,你的代码令人惊讶地似乎快了 2-5 倍,具体取决于输入。我仍然发现这些类型的操作的效率是不直观的,因此使用timeit 来测试某个特定操作是否是代码中的瓶颈总是值得的。在 numpy 中做事的方式通常不止一种,所以绝对要配置代码 sn-ps。
          • @JoshAdel:我猜如果.reshape 创建了一个额外的数组副本,那么这可以解释 2 倍的性能损失。但是,我认为它并不总是复制。我猜 5 倍的差异仅适用于小型阵列?
          • 查看.flags 并为我的解决方案测试.base,看起来重塑为“F”格式会创建 vstacked 数据的隐藏副本,所以这不是我想的简单视图这将是。奇怪的是,出于某种原因,5x 仅适用于中等大小的数组。
          • 这个答案的另一个优点是它不限于相同长度的数组。它可以将n 项目与n-1 项目编织在一起。
          【解决方案11】:

          这是一个单行:

          c = numpy.vstack((a,b)).reshape((-1,),order='F')
          

          【讨论】:

          • 哇,这太难读了 :) 这是一种情况,如果你没有在代码中写下正确的注释,它会让人抓狂。
          • 这只是两个常见的 numpy 命令串在一起。我认为它不会那么难读,尽管评论永远不会受到伤害。
          • @JohnAdel,好吧,这不是numpy.vstack((a,b)).interweave() :)
          • @Ilya:我会亲自调用函数.interleave() :)
          • reshape 是做什么的?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-01-02
          • 2014-05-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-08-03
          相关资源
          最近更新 更多