Đan xen giữa hai mảng numpy


84

Giả sử các mảng sau được đưa ra:

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

Làm thế nào để người ta đan xen chúng một cách hiệu quả để người ta có được mảng thứ ba như thế này

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

Có thể cho rằng length(a)==length(b).


1
Thế còn, cùng một câu hỏi, nhưng bạn đang cố gắng xen kẽ các ma trận. Đó là a và b là 3 chiều, và không nhất thiết phải có cùng kích thước trong chiều đầu tiên. Lưu ý: Chỉ nên xen kẽ chiều đầu tiên.
Geronimo

Câu trả lời:


144

Tôi thích câu trả lời của Josh. Tôi chỉ muốn thêm một giải pháp trần tục hơn, bình thường và dài dòng hơn một chút. Tôi không biết cái nào hiệu quả hơn. Tôi mong đợi họ sẽ có hiệu suất tương tự.

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
Trừ khi tốc độ thực sự thực sự quan trọng, tôi sẽ làm theo điều này vì nó dễ hiểu hơn nhiều, điều quan trọng nếu ai đó muốn xem lại nó.
John Salvatier

6
+1 Tôi đã thử với thời gian và đáng ngạc nhiên là mã của bạn dường như nhanh hơn 2-5 lần tùy thuộc vào đầu vào. Tôi vẫn thấy hiệu quả của các loại hoạt động này là không trực quan, vì vậy nó luôn đáng được sử dụng timeitđể kiểm tra mọi thứ nếu một hoạt động cụ thể là nút cổ chai trong mã của bạn. Thường có nhiều cách để thực hiện mọi thứ trong numpy, vì vậy chắc chắn là các đoạn mã hồ sơ.
JoshAdel

@JoshAdel: Tôi đoán nếu .reshapetạo thêm một bản sao của mảng, thì điều đó sẽ giải thích hiệu suất tăng gấp đôi . Tuy nhiên, tôi không nghĩ nó luôn tạo ra một bản sao. Tôi đoán sự khác biệt 5x chỉ dành cho các mảng nhỏ?
Paul

đang xem xét .flagsvà thử nghiệm .basegiải pháp của tôi, có vẻ như định dạng lại thành định dạng 'F' tạo ra một bản sao ẩn của dữ liệu vstacked, vì vậy đây không phải là một chế độ xem đơn giản như tôi nghĩ. Và kỳ lạ là 5x chỉ dành cho các mảng có kích thước trung bình vì một số lý do.
JoshAdel

Một ưu điểm khác của câu trả lời này là nó không giới hạn ở các mảng có cùng độ dài. Nó có thể dệt ncác mặt hàng với n-1các mặt hàng.
EliadL

62

Tôi nghĩ có thể đáng giá để kiểm tra xem các giải pháp hoạt động như thế nào về mặt hiệu suất. Và đây là kết quả:

nhập mô tả hình ảnh ở đây

Điều này cho thấy rõ ràng rằng câu trả lời được ủng hộ và chấp nhận nhiều nhất (câu trả lời của Pauls) cũng là phương án nhanh nhất.

Mã được lấy từ các câu trả lời khác và từ một Câu hỏi và Đáp khác :

# 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()

Chỉ trong trường hợp bạn có sẵn numba, bạn cũng có thể sử dụng nó để tạo một hàm:

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

Nó có thể nhanh hơn một chút so với các lựa chọn thay thế khác:

nhập mô tả hình ảnh ở đây


2
Cũng cần lưu ý, câu trả lời được chấp nhận nhanh hơn một cách nhanh hơn so với giải pháp Python bản địa với roundrobin()từ các công thức itertools.
Brad Solomon

41

Đây là một lớp lót:

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

16
Wow, thật khó đọc :) Đây là một trong những trường hợp nếu bạn không viết một bình luận thích hợp trong mã, nó có thể khiến ai đó phát điên.
Ilya Kogan

9
Nó chỉ là hai lệnh phức tạp chung được kết hợp với nhau. Tôi sẽ không nghĩ rằng nó không thể đọc được, mặc dù một nhận xét không bao giờ gây đau đớn.
JoshAdel

1
@JohnAdel, à, không phải đâu numpy.vstack((a,b)).interweave():)
Ilya Kogan

6
@Ilya: Tôi sẽ gọi hàm theo .interleave()cách cá nhân :)
JoshAdel

Làm gì reshape?
Danijel

23

Đây là một câu trả lời đơn giản hơn một số câu trước

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

Sau cái này interchứa:

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

Câu trả lời này dường như cũng nhanh hơn một chút:

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

Điều này sẽ xen kẽ / xen kẽ hai mảng và tôi tin rằng nó khá dễ đọc:

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
Tôi thích cái này là dễ đọc nhất. mặc dù thực tế rằng nó là giải pháp chậm nhất.
kimstik

Bọc ziptrong một listđể tránh cảnh báo khấu hao
Milo Wielondek

6

Có thể điều này dễ đọc hơn giải pháp của @ JoshAdel:

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

2
ravel's orderluận trong tài liệu là một trong những C, F, A, hoặc K. Tôi nghĩ bạn thực sự muốn .ravel('F'), đối với đơn đặt hàng FORTRAN (cột đầu tiên)
Nick T

5

Cải thiện câu trả lời của @ 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 chắc chắn là một lựa chọn, nhưng giải pháp đơn giản hơn cho trường hợp của bạn có thể là 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])

và quan trọng hơn, điều này hoạt động với các hình dạng tùy ý ab

Ngoài ra, bạn có thể muốn thử dstack

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

bạn đã có lựa chọn bây giờ!


7
-1 cho câu trả lời đầu tiên vì câu hỏi không liên quan gì đến việc sắp xếp. Câu trả lời từ +1 đến thứ hai, là câu trả lời hay nhất mà tôi đã thấy cho đến nay. Đây là lý do tại sao nhiều giải pháp nên được đăng dưới dạng nhiều câu trả lời. Hãy chia nó thành nhiều câu trả lời.
endolith

1

Một lớp lót khác: np.vstack((a,b)).T.ravel()
Một lớp lót khác:np.stack((a,b),1).ravel()


0

Người ta cũng có thể thử np.insert. (Giải pháp được di chuyển từ các mảng xen kẽ numpy )

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)

Vui lòng xem documentationtutorialđể biết thêm thông tin.


0

Tôi cần phải làm điều này nhưng với các mảng đa chiều dọc theo bất kỳ trục nào. Đây là một chức năng mục đích chung nhanh chóng cho hiệu ứng đó. Nó có chữ ký cuộc gọi giống như np.concatenate, ngoại trừ việc tất cả các mảng đầu vào phải có chính xác hình dạng tương tự.

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.