numpy配列から別の配列にデータをコピーする方法


86

配列aのアドレスを変更せずに、配列bから配列aにデータをコピーする最速の方法は何ですか。外部ライブラリ(PyFFTW)が変更できない配列へのポインタを使用するため、これが必要です。

例えば:

a = numpy.empty(n, dtype=complex)
for i in xrange(a.size):
  a[i] = b[i]

ループなしでそれを行うことは可能ですか?

回答:


86

私は信じている

a = numpy.empty_like (b)
a[:] = b

ディープコピーをすばやく作成します。Funsiが言及しているように、最近のバージョンのnumpyにもcopyto機能があります。


4
+1。しかし、ではないでしょうnumpy.empty、実質的に速くよりもnumpy.zeros
mg007 2012

9
@ M.ElSakaa = bは、への新しい参照を作成するだけbです。a[:] = b「のすべての要素をa同じに設定する」という意味bです。numpy配列は可変型であるため、この違いは重要です。
ブライアンホーキンス

14
@ mg007いくつかのテストを実行したところ、empty()よりも約10%高速であることがわかりましたzeros()。驚くべきことにempty_like()、さらに高速です。copyto(a,b)配列構文よりも高速ですa[:] = bgist.github.com/bhawkins/5095558を
Brian Hawkins

2
@ブライアンホーキンスは正しいです。いつ使用するかnp.copyto(a, b)、いつa = b.astype(b.dtype)速度を向上させるかについては、以下の回答を参照してください:stackoverflow.com/a/33672015/3703716
mab

1
@michael_n驚いたのempty_likeは、よりもはるかに速いことですempty。特に、zeros_likeがよりも遅いためzerosです。ところで、ベンチマークを再実行したところ(現在は更新されています)、との違いはcopyto(a,b)なくなったa[:] = bようです。gist.github.com/bhawkins/5095558
Brian Hawkins


19
a = numpy.array(b)

numpy v1.6までの推奨ソリューションよりもさらに高速で、アレイのコピーも作成します。ただし、numpyの最新バージョンがないため、copyto(a、b)に対してテストできませんでした。


これは配列をコピーするための優れた方法ですが、新しいオブジェクトを作成します。OPは、すでに作成されている配列に値をすばやく割り当てる方法を知っている必要があります。
ブライアンホーキンス

15

あなたの質問に答えるために、私はいくつかの変種で遊んで、それらをプロファイリングしました。

結論:numpyの組み込み関数の別の使用のいずれかにnumpyの配列からデータをコピーするnumpy.array(src)か、numpy.copyto(dst, src)可能な限り。

(ただし、dstメモリがすでに割り当てられている場合は、メモリを再利用するために、常に後者を選択してください。投稿の最後にあるプロファイリングを参照してください。)

プロファイリングの設定

import timeit
import numpy as np
import pandas as pd
from IPython.display import display

def profile_this(methods, setup='', niter=10 ** 4, p_globals=None, **kwargs):
    if p_globals is not None:
        print('globals: {0}, tested {1:.0e} times'.format(p_globals, niter))
    timings = np.array([timeit.timeit(method, setup=setup, number=niter,
                                      globals=p_globals, **kwargs) for 
                        method in methods])
    ranking = np.argsort(timings)
    timings = np.array(timings)[ranking]
    methods = np.array(methods)[ranking]
    speedups = np.amax(timings) / timings

    pd.set_option('html', False)
    data = {'time (s)': timings,
            'speedup': ['{:.2f}x'.format(s) if 1 != s else '' for s in speedups],
            'methods': methods}
    data_frame = pd.DataFrame(data, columns=['time (s)', 'speedup', 'methods'])

    display(data_frame)
    print()

プロファイリングコード

setup = '''import numpy as np; x = np.random.random(n)'''
methods = (
    '''y = np.zeros(n, dtype=x.dtype); y[:] = x''',
    '''y = np.zeros_like(x); y[:] = x''',
    '''y = np.empty(n, dtype=x.dtype); y[:] = x''',
    '''y = np.empty_like(x); y[:] = x''',
    '''y = np.copy(x)''',
    '''y = x.astype(x.dtype)''',
    '''y = 1*x''',
    '''y = np.empty_like(x); np.copyto(y, x)''',
    '''y = np.empty_like(x); np.copyto(y, x, casting='no')''',
    '''y = np.empty(n)\nfor i in range(x.size):\n\ty[i] = x[i]'''
)

for n, it in ((2, 6), (3, 6), (3.8, 6), (4, 6), (5, 5), (6, 4.5)):
    profile_this(methods[:-1:] if n > 2 else methods, setup, 
                 niter=int(10 ** it), p_globals={'n': int(10 ** n)})

結果インテルi7のCPU、CPythonとのv3.5.0、numpyのv1.10.1上のWindows 7用。


また、これはセットアップの一部であるため、値のコピー中に宛先のメモリがすでに事前に割り当てられているプロファイリングのバリアントの結果を参照してくださいy = np.empty_like(x)


またx.copy()、同じくらい高速でnp.array(x)、構文がはるかに好きです:$ python3 -m timeit -s "import numpy as np; x = np.random.random((100, 100))" "x.copy()"- 100000 loops, best of 3: 4.7 usec per loop。についても同様の結果が得られnp.array(x)ます。Linuxでi5-4210Uとnumpy1.10.4を使用してテスト
Marco Sulla

はいマルコ、それはむしろ個人的な好みの問題です。しかし、それnp.copyはより寛容であることに注意してください:np.copy(False)、スローしnp.copy(None)ながら、まだ動作します。また、メソッド構文の代わりに関数を使用して、このコード行で何を実行したいかをより正確に宣言します。a = None; a.copy()AttributeError: 'NoneType' object has no attribute 'copy'
mab 2016年

1
まあ、事実np.copy(None)はエラーをスローしませんが、本当に非Pythonです。使用するもう1つの理由a.copy():)
Marco Sulla

1
これらのベンチマークをPython2.7.12、NumPy 1.11.2で実行したところ、y[:] = x現在はcopyto(y, x)。よりもわずかに高速であることがわかりました。gist.github.com/bhawkins/7cdbd5b9372cb798e34e21f92279d2dcの
Brian Hawkins

10

あなたは簡単に使うことができます:

b = 1*a

これが最速の方法ですが、いくつかの問題もあります。dtypeofaを直接定義せず、ofもチェックしないと、問題が発生する可能性がdtypeありbます。例えば:

a = np.arange(10)        # dtype = int64
b = 1*a                  # dtype = int64

a = np.arange(10.)       # dtype = float64
b = 1*a                  # dtype = float64

a = np.arange(10)        # dtype = int64
b = 1. * a               # dtype = float64

要点を明確にできればと思います。たった1回の小さな操作でデータ型を変更できる場合があります。


1
いいえ。そうすると、新しいアレイが作成されます。これは、b = a.copy()と同等です。
Charles Brunet 2011年

申し訳ありませんが、私はあなたを取得しません。新しいアレイを作成するとはどういう意味ですか?ここに示されている他のすべてのメソッドは同じ動作をします。a = numpy.zeros(len(b))またはa = numpy.empty(n,dtype=complex)、新しいアレイも作成します。
ahelm 2011年

2
a = numpy.empty(1000)があるとします。ここで、メモリ内のアドレスを変更せずに、データを入力する必要があります。a [0] = 1を実行すると、配列を再作成せず、配列の内容を変更するだけです。
Charles Brunet 2011年

1
@CharlesBrunet配列は、ある時点で作成する必要があります。この巧妙なワンライナーは、1回の操作ですべてを実行します。
heltonbiker 2013年

7

あなたができることはたくさんあります:

a=np.copy(b)
a=np.array(b) # Does exactly the same as np.copy
a[:]=b # a needs to be preallocated
a=b[np.arange(b.shape[0])]
a=copy.deepcopy(b)

うまくいかないこと

a=b
a=b[:] # This have given my code bugs 

1

使わない理由

a = 0 + b

以前の掛け算と似ていると思いますが、もっと簡単かもしれません。

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