2つのnumpy配列を織り交ぜる


84

次の配列が与えられていると仮定します。

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

これらを効率的に織り交ぜて、このような3番目の配列を取得するにはどうすればよいでしょうか。

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

と仮定することができますlength(a)==length(b)


1
同じ質問ですが、行列をインターリーブしようとしています。つまり、aとbは3次元であり、必ずしも1次元で同じサイズである必要はありません。注:最初の次元のみをインターリーブする必要があります。
Geronimo

回答:


144

Joshの答えが好きです。もっと平凡で、いつもの、もう少し冗長なソリューションを追加したかっただけです。どちらが効率的かわかりません。似たようなパフォーマンスになると思います。

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 2011年

6
+1私はタイミングをいじってみましたが、入力によっては驚くほどコードが2〜5倍速いようです。これらのタイプの操作の効率は直感的ではないことがまだわかっているのでtimeit、特定の操作がコードのボトルネックであるかどうかをテストするために使用することは常に価値があります。通常、numpyで処理を行う方法は複数あるため、コードスニペットのプロファイルを作成してください。
JoshAdel 2011年

@JoshAdel:.reshape配列の追加コピーを作成する場合、それは2倍のパフォーマンスヒットを説明すると思います。ただし、常にコピーになるとは限りません。5倍の違いは小さなアレイだけだと思いますか?
ポール

私のソリューションを見て.flagsテスト.baseすると、「F」形式に再形成すると、vstackedデータの非表示のコピーが作成されるように見えるため、思ったほど単純なビューではありません。そして不思議なことに、5xは何らかの理由で中間サイズのアレイ専用です。
JoshAdel 2011年

この回答のも​​う1つの利点は、同じ長さの配列に限定されないことです。nアイテムとn-1アイテムを織り合わせることができます。
EliadL

62

ソリューションのパフォーマンスを確認する価値があるのではないかと思いました。そしてこれが結果です:

ここに画像の説明を入力してください

これは、最も賛成され受け入れられた回答(ポールの回答)も最速の選択肢であることを明確に示しています。

コードは他の回答と別の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

他の選択肢よりもわずかに速い可能性があります。

ここに画像の説明を入力してください


2
また、ノートの、受け入れられた答えはより高速でネイティブのPythonのソリューションよりもroundrobin()itertoolsのレシピから。
ブラッド・ソロモン

41

これがワンライナーです:

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

16
うわー、これはとても読めません:)これは、コードに適切なコメントを書かないと、誰かを狂わせる可能性があるケースの1つです。
Ilya Kogan 2011年

9
これは、2つの一般的なnumpyコマンドをつなぎ合わせただけです。コメントが痛くなることはありませんが、それが読めないということではないと思います。
JoshAdel 2011年

1
@JohnAdel、まあ、そうではありませんnumpy.vstack((a,b)).interweave():)
Ilya Kogan

6
@Ilya:私は.interleave()個人的に関数を呼び出したでしょう:)
JoshAdel 2011年

何をしreshapeますか?
ダニエル2017年

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

これにより、2つの配列がインターリーブ/インターレースされ、非常に読みやすいと思います。

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

ラップzipでは、list減価償却の警告を避けるために
ミロ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から2番目の答え。これは私がこれまでに見た中で最高です。これが、複数のソリューションを複数の回答として投稿する必要がある理由です。複数の回答に分けてください。
endolith 2013年

1

もう1つのnp.vstack((a,b)).T.ravel()
ワンライナー:もう1つ:np.stack((a,b),1).ravel()


0

試すこともできnp.insertます。(ソリューションはInterleave 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)

詳細については、documentationおよびtutorialを参照してください。


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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.