NumPy配列のインプレース型変換


127

のNumPy配列が与えられた場合、int32それをfloat32 インプレースに変換するにどうすればよいですか なので基本的には

a = a.astype(numpy.float32)

配列をコピーせずに。大きいです。

これを行う理由は、の計算に2つのアルゴリズムがあるためですa。1つはの配列を返し、もう1つはの配列をint32返しますfloat32(これは2つの異なるアルゴリズムに固有です)。以降のすべての計算では、aがの配列であると想定していfloat32ます。

現在、を介して呼び出されるC関数で変換を行っていctypesます。Pythonでこれを行う方法はありますか?


を使用するのctypesは、を使用するのと同じくらい「Pythonで」numpyです。:)
Karl Knechtel、2010

3
@Karl:いいえ。C関数を自分でコーディングしてコンパイルする必要があるためです。
Sven Marnach、2010

ああなるほど。あなたはおそらくこれについてSOLだと思います。
Karl Knechtel、2010

3
@Andrew:コピーを返すかどうかを判断する方法はたくさんあります。その1つは、ドキュメントを読むことです。
Sven Marnach、2011年

1
インプレースとは、単に「元の配列と同じメモリを使用する」ことを意味します。受け入れられた答えを見てください。最後の部分は、新しい値が実際に同じメモリを上書きしたことを示しています。
Sven Marnach

回答:


110

異なるdtypeでビューを作成し、ビューにインプレースでコピーできます。

import numpy as np
x = np.arange(10, dtype='int32')
y = x.view('float32')
y[:] = x

print(y)

収量

array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.], dtype=float32)

変換が適所に行われたことを示すために、から xへのコピーがy変更されたことに注意してくださいx

print(x)

プリント

array([         0, 1065353216, 1073741824, 1077936128, 1082130432,
       1084227584, 1086324736, 1088421888, 1090519040, 1091567616])

26
異なるバイトサイズ(32〜16ビットなど)のdtype間の変換が必要な(私のような)注意:このメソッドは、y.size <> x.sizeであるため失敗します。論理的に考えてみてください:-(
Juh_

このソリューションはいくつかの古いバージョンのNumpyで機能しましたか?私が行うとnp.arange(10, dtype=np.int32).view(np.float32)numpyの1.8.2に、私が得ますarray([ 0.00000000e+00, 1.40129846e-45, ... [snip] ... 1.26116862e-44], dtype=float32)
Bas Swinckels 2015年

3
@BasSwinckels:それは予想通りです。変換すると、が割り当てられy[:] = xます。
unutbu 2015年

元の回答と@Juh_で参照されているitemsize(ビット数)についてのポイントを明確にする例:a = np.arange(10, dtype='float32'); b = a[::-1]; c = np.vstack((a,b)); d = c.view('float64')このコードは10 + 10 float32を取り、20ではなく10になります
dcanelhas

1
このインプレース変更により、メモリ使用量を節約できますが、単純なx.astype(float)変換よりも時間がかかります。スクリプトがMemoryErrorに接していない限り、お勧めしません。
hpaulj

158

更新:この関数は、可能な場合にのみコピーを回避するため、これはこの質問に対する正しい答えではありません。unutbuの答えは正しいです。


a = a.astype(numpy.float32, copy=False)

numpy astypeにはコピーフラグがあります。なぜそれを使わないのですか?


14
このパラメーターがNumPyリリースでサポートされると、もちろん使用できますが、現在は開発ブランチでのみ使用できます。そして私がこの質問をしたとき、それはまったく存在しませんでした。
スヴェンマルナッハ

2
@SvenMarnach少なくとも私のバージョン(1.7.1)ではサポートされています。
PhilMacKay 2013

最新のnumpyバージョンのpython3.3で完全に動作するようです。
2013年

1
これは、a = a.view((float、len(a.dtype.names)))よりも約700倍遅い
JJ

14
コピーフラグは、変更がコピーなしで実行できる場合、コピーなしで実行されることを示すだけです。ただし、タイプが異なるため、常にコピーされます。
coderforlife 2015年

14

次のように変換せずに配列タイプを変更できます。

a.dtype = numpy.float32

しかし、最初にすべての整数を対応する浮動小数点数として解釈されるものに変更する必要があります。これを行う非常に遅い方法は、次のstructようなpythonのモジュールを使用することです。

def toi(i):
    return struct.unpack('i',struct.pack('f',float(i)))[0]

...配列の各メンバーに適用されます。

しかし、おそらくもっと速い方法は、numpyのctypeslibツール(私はこれに慣れていない)を利用することでしょう。

-編集-

ctypeslibは機能していないようなので、通常のnumpy.astype方法で変換を続行しますが、メモリ制限内のブロックサイズで続行します。

a[0:10000] = a[0:10000].astype('float32').view('int32')

...完了したら、dtypeを変更します。

以下は、互換性のあるすべてのdtypeのタスクを実行し(同じサイズの項目を持つdtypeでのみ機能)、ユーザーがブロックサイズを制御できる任意の形状の配列を処理する関数です。

import numpy

def astype_inplace(a, dtype, blocksize=10000):
    oldtype = a.dtype
    newtype = numpy.dtype(dtype)
    assert oldtype.itemsize is newtype.itemsize
    for idx in xrange(0, a.size, blocksize):
        a.flat[idx:idx + blocksize] = \
            a.flat[idx:idx + blocksize].astype(newtype).view(oldtype)
    a.dtype = newtype

a = numpy.random.randint(100,size=100).reshape((10,10))
print a
astype_inplace(a, 'float32')
print a

1
ご回答有難うございます。正直なところ、これは大規模な配列にはあまり役立つとは思いません- 非常に遅いです。配列のデータを別の型として再解釈するのは簡単a.view(numpy.float32)です。たとえば、呼び出します。難しいのは、実際にデータを変換することです。 numpy.ctypeslib実際にデータを変換するのではなく、データを再解釈するのに役立ちます。
Sven Marnach、2010

OK。私はあなたのメモリ/プロセッサの制限が何であったかわかりませんでした。私の編集を参照してください。
ポール

更新していただきありがとうございます。それをブロックごとに行うのは良い考えです-おそらく現在のNumPyインターフェースで得られる最高のものです。ただし、この場合は、おそらく現在のctypesソリューションを使用します。
Sven Marnach、2010

-1
import numpy as np
arr_float = np.arange(10, dtype=np.float32)
arr_int = arr_float.view(np.float32)

配列を変更するには、view()とパラメーター 'dtype'を使用します。


質問の目的は、実際にデータを適切に変換することでした。最後の行のタイプをに修正した後int、この答えは既存のデータを別のタイプとして再解釈するだけであり、これは私が求めていたものではありません。
Sven Marnach

どういう意味ですか?dtypeはメモリ内のデータの外観にすぎませんが、実際に機能します。ただし、np.astypeでは、パラメーター 'casting'は変換メソッドのデフォルト 'unsafe'を制御できます。
蒋志强

ええ、私は最初に受け入れられた答えに同意します。ただし、arr_.astype(new_dtype、copy = False)は、新しく割り当てられた配列を返します。どのように満足することdtypeorderおよびsubok配列のコピーを返すための要件を?私はそれを解決しません。
蒋志强

-5

これを使って:

In [105]: a
Out[105]: 
array([[15, 30, 88, 31, 33],
       [53, 38, 54, 47, 56],
       [67,  2, 74, 10, 16],
       [86, 33, 15, 51, 32],
       [32, 47, 76, 15, 81]], dtype=int32)

In [106]: float32(a)
Out[106]: 
array([[ 15.,  30.,  88.,  31.,  33.],
       [ 53.,  38.,  54.,  47.,  56.],
       [ 67.,   2.,  74.,  10.,  16.],
       [ 86.,  33.,  15.,  51.,  32.],
       [ 32.,  47.,  76.,  15.,  81.]], dtype=float32)

5
それはコピーではないのですか?確認してもう少し説明していただけますか?
Michele d'Amico、2015

-5

a = np.subtract(a, 0., dtype=np.float32)


1
このコードスニペットが解決策となる可能性がありますが、説明を含めると、投稿の品質向上に役立ちます。あなたは将来の読者のための質問に答えていることを覚えておいてください、そしてそれらの人々はあなたのコード提案の理由を知らないかもしれません。
Sebastialonso

なぜこれがその場での変換である必要があるのですか?numpy.subtractコピーを返してくれませんか?名前だけがa別のデータのチャンクに再利用されています...これについて間違っている場合は、説明してください。
koffein 2017年

これを指摘してくれてありがとう、あなたは正しいようです-コピーが作成されます。
MIO
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.