Переплетение двух массивов

Предположим, что даны следующие массивы:

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

Как можно было бы эффективно их переплетать, чтобы получить третий массив, подобный этому?

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

Можно предположить, что length(a)==length(b),

14 ответов

Решение

Мне нравится ответ Джоша. Я просто хотел добавить более приземленное, обычное и немного более подробное решение. Я не знаю, что является более эффективным. Я ожидаю, что они будут иметь аналогичные показатели.

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

Я подумал, что стоит проверить, как решения работают с точки зрения производительности. И вот результат:

введите описание изображения здесь

Это ясно показывает, что наиболее одобренный и принятый ответ (ответ Паулса) также является самым быстрым вариантом.

Код был взят из других ответов и из другого 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

Это может быть немного быстрее, чем другие альтернативы:

введите описание изображения здесь

Вот одна строка:

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

Вот более простой ответ, чем некоторые из предыдущих

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

Это будет чередовать / чередовать два массива, и я считаю, что это вполне читабельно:

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

Улучшение ответа @xioxox:

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

Может быть, это более читабельно, чем решение @JoshAdel:

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

Мне нужно было это сделать, но с многомерными массивами по любой оси. Вот быстрая функция общего назначения на этот счет. Он имеет ту же сигнатуру вызова, что и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)

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

У тебя есть варианты сейчас!

Можно также попробовать np.insert, (Решение мигрировало из массивов чередования Interleave)

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 для дополнительной информации.

Еще один однострочный:c = np.vstack((a,b)).transpose().flatten()

Для массива 2D numpy:

      def interleave2d(a, b):
    """Interleave between columns of two arrays"""
    c = np.empty((len(a), a.shape[1] * 2), dtype=a.dtype)
    c[:, 0::2] = a
    c[:, 1::2] = b
    return c

Не самая красивая функция, но мне нужна была такая, которая могла бы чередовать произвольное количество матриц. Может быть, полезно?

       def interleave_narr(*args):
        ''' Given N numpy arrays, interleave arr i+1...i+N'''
        m_sizes = 0
        for m in args:
                m_sizes += m.size
        o = np.empty((m_sizes,), dtype=args[0].dtype)
    
        n_mats = len(args)
        for ii in range(n_mats):
            o[ii::n_mats] = args[ii]
        return o

Еще одна строчка:

      >>> c = np.array([a, b]).T.flatten()
>>> c
array([1, 2, 3, 4, 5, 6])
Другие вопросы по тегам