交织两个numpy数组


84

假设给出以下数组:

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

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

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

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


1
怎么样,同样的问题,但是你试图交织矩阵。即a和b是3维的,并且不一定在第一维上是相同的尺寸。注意:仅第一维应该是交错的。
Geronimo

Answers:


144

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

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
除非速度真的很重要,否则我会选择它,因为它会更容易理解,如果有人再次考虑它,这很重要。
John Salvatier

6
+1我在时间上玩弄,您的代码似乎惊人地快了2-5倍,具体取决于输入。我仍然发现这些类型的操作的效率是不直观的,因此,timeit如果某个特定的操作是代码的瓶颈,则值得一试来进行测试。通常,在numpy中有多种处理方法,因此绝对是概要文件代码段。
JoshAdel 2011年

@JoshAdel:我想如果.reshape创建一个数组的额外副本,那么这可以解释2倍的性能下降。但是,我认为它并不总是能够复制。我猜5倍差异仅适用于小型阵列?
保罗

查看.flags并测试.base我的解决方案,看起来好像改成“ F”格式会创建vstacked数据的隐藏副本,所以这不是我想的那样简单的视图。奇怪的是5x由于某种原因仅适用于中等大小的阵列。
JoshAdel 2011年

这个答案的另一个优点是它不仅限于相同长度的数组。它可以nn-1物品编织物品。
EliadL

62

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

在此处输入图片说明

这清楚地表明,最被支持和接受的答案(Pauls答案)也是最快的选择。

该代码取自其他答案和另一个问答

# 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

它可能比其他替代方案要快一些:

在此处输入图片说明


2
另外值得注意的是,公认的答案是这样比用原来的Python的解决方案更快地roundrobin()从迭代工具的食谱。
布拉德·所罗门

41

这里是单线:

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

16
哇,这太难以理解了:)这是一种情况,如果您没有在代码中编写适当的注释,就会使人发疯。
Ilya Kogan

9
这只是两个常见的numpy命令串在一起。我不会以为这是不可读的,尽管评论永远不会伤害您。
JoshAdel 2011年

1
@JohnAdel,好吧,这不是numpy.vstack((a,b)).interweave():)
Ilya Kogan

6
@Ilya:我本应该.interleave()亲自调用该函数的:)
JoshAdel

怎么reshape办?
Danijel

23

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

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

10

这将交错/交错两个数组,我相信它是很可读的:

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])

2
我最喜欢这本书。尽管这是最慢的解决方案。
kimstik '19

ziplist避免折旧警告
米洛Wielondek

6

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

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

2
ravelorder在参数文件是以下之一CFA,或K。我认为您确实想要.ravel('F')FORTRAN订单(列优先)
Nick T

5

改善@xioxox的答案:

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

1

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])

更重要的是,这适用于任意形状的ab

另外你可能想尝试一下 dstack

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

您现在有选择!


7
-1为第一个答案,因为问题与排序无关。+1是第二个答案,这是我到目前为止所见最好的答案。这就是为什么应将多个解决方案发布为多个答案的原因。请分成多个答案。
endolith



0

我需要执行此操作,但要沿任意轴使用多维数组。这是实现此目的的快速通用功能。它具有与相同的调用签名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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.