web-dev-qa-db-ja.com

numpy ndarrayを「拡張」する良い方法は?

Numpy ndarrayを「拡張」する良い方法はありますか?次のようなndarrayがあるとします。

[[1 2]
 [3 4]]

そして、ゼロを埋めることで各行にさらに要素が含まれるようにします。

[[1 2 0 0 0]
 [3 4 0 0 0]]

強引な方法がいくつかあるに違いないことを知っています(ゼロで大きな配列を作成し、古い小さな配列から要素をコピーするなど)。 numpy.reshapeしかし動作しませんでした:

import numpy as np
a = np.array([[1, 2], [3, 4]])
np.reshape(a, (2, 5))

Numpyからの不満:ValueError: total size of new array must be unchanged

34
clwen

インデックストリックがありますr_およびc_

>>> import numpy as np
>>> a = np.array([[1, 2], [3, 4]])
>>> z = np.zeros((2, 3), dtype=a.dtype)
>>> np.c_[a, z]
array([[1, 2, 0, 0, 0],
       [3, 4, 0, 0, 0]])

これがパフォーマンスが重要なコードである場合、同等のnp.concatenateインデックスのトリックではなく。

>>> np.concatenate((a,z), axis=1)
array([[1, 2, 0, 0, 0],
       [3, 4, 0, 0, 0]])

もあります np.resizeおよびnp.ndarray.resize、ただし、いくつかの制限があります(numpyがメモリにデータをレイアウトする方法のため)ので、それらのdocstringを読んでください。単純に連結する方が良いでしょう。

ところで、私がこれを行う必要があるとき、私は通常あなたが既に述べた基本的な方法でそれを行います(ゼロの配列を作成し、その中に小さな配列を割り当てます)、私はそれで何の問題も見ません!

40
wim

次のように、numpy.padを使用できます。

>>> import numpy as np
>>> a=[[1,2],[3,4]]
>>> np.pad(a, ((0,0),(0,3)), mode='constant', constant_values=0)
array([[1, 2, 0, 0, 0],
       [3, 4, 0, 0, 0]])

ここでnp.padは、「配列aを取得し、その上に0行、その下に0行、その左に0列、その右に3列を追加します。これらの列を埋めますconstant_values "で指定されたconstant

50
Richard

NumPy配列はnot拡張可能であるため、NumPy配列を拡張する「良い」方法はありません。配列が定義されると、メモリ内で占有するスペース(要素の数と各要素のサイズの組み合わせ)は固定され、変更できません。できることは、新しい配列を作成し、その要素の一部を元の配列の要素で置き換えることだけです。

多くの機能が便利に利用できます( np.concatenate 関数とそのnp.*stackショートカット、 np.column_stack 、インデックスルーチン np.r_ およびnp.c_...)、しかしそれだけがあります:便利な機能。それらのいくつかは、Cレベルで最適化されています(np.concatenateと他の人、私は思う)、そうでない人もいます。

大きな配列を「手で」(おそらくゼロで埋める)作成し、最初の配列で自分で埋めるという最初の提案には何もありません。より複雑なソリューションよりも読みやすいかもしれません。

10
Pierre GM

np.column_stackまたはappendを使用する必要があります

import numpy as np

p = np.array([ [1,2] , [3,4] ])

p = np.column_stack( [ p , [ 0 , 0 ],[0,0] ] )

p
Out[277]: 
array([[1, 2, 0, 0],
       [3, 4, 0, 0]])

ただし、追加の方が速いようです:

timeit np.column_stack( [ p , [ 0 , 0 ],[0,0] ] )
10000 loops, best of 3: 61.8 us per loop

timeit np.append(p, [[0,0],[0,0]],1)
10000 loops, best of 3: 48 us per loop

そして、np.c_np.hstack [まだ追加するのが最速のようです]との比較:

In [295]: z=np.zeros((2, 2), dtype=a.dtype)

In [296]: timeit np.c_[a, z]
10000 loops, best of 3: 47.2 us per loop

In [297]: timeit np.append(p, z,1)
100000 loops, best of 3: 13.1 us per loop

In [305]: timeit np.hstack((p,z))
10000 loops, best of 3: 20.8 us per loop

およびnp.concatenate [append]よりも少し高速です:

In [307]: timeit np.concatenate((p, z), axis=1)
100000 loops, best of 3: 11.6 us per loop
8
root

簡単な方法:

# what you want to expand
x = np.ones((3, 3))

# expand to what shape 
target = np.zeros((6, 6))

# do expand
target[:x.shape[0], :x.shape[1]] = x

# print target
array([[ 1.,  1.,  1.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.]])

機能的な方法:

https://stackoverflow.com/a/35751427/163767 から借用します。少し変更します。

def pad(array, reference_shape, offsets=None):
    """
    array: Array to be padded
    reference_shape: Tuple of size of narray to create
    offsets: list of offsets (number of elements must be equal to the dimension of the array)
    will throw a ValueError if offsets is too big and the reference_shape cannot handle the offsets
    """

    if not offsets:
        offsets = np.zeros(array.ndim, dtype=np.int32)

    # Create an array of zeros with the reference shape
    result = np.zeros(reference_shape, dtype=np.float32)
    # Create a list of slices from offset to offset + shape in each dimension
    insertHere = [slice(offsets[dim], offsets[dim] + array.shape[dim]) for dim in range(array.ndim)]
    # Insert the array in the result at the specified offsets
    result[insertHere] = array
    return result
4
Mithril

np.vstack、np.hstack、np.dstackなどの同様のメソッドもあります。 np.concatenteよりもこれらが好きです。どのディメンションが「拡張」されているかが明確になるからです。

temp = np.array([[1, 2], [3, 4]])
np.hstack((temp, np.zeros((2,3))))

numpyの最初の軸が垂直であり、vstackが最初の軸を拡張し、2番目の軸が水平であるためhstackであるため、覚えやすいです。

2
otterb