NaNで満たされたnumpy行列を作成する


195

私は次のコードを持っています:

r = numpy.zeros(shape = (width, height, 9))

width x height x 9ゼロで満たされた行列を作成します。代わりNaNに、簡単な方法でsに初期化する関数または方法があるかどうかを知りたいです。


2
1つの注意点は、NumPyには整数のNA値がないことです(Rとは異なります)。参照してください落とし穴のパンダリストを。したがってnp.nan、intに変換すると失敗します。
smci 2013

smciは正しいです。NumPyの場合、そのようなNaN値はありません。したがって、タイプとNumPyによって、NaNにどの値が存在するかが決まります。これに気付いていない場合は、問題が発生します
MasterControlProgram

回答:


271

numpyでのベクトル演算にループが必要になることはほとんどありません。初期化されていない配列を作成して、一度にすべてのエントリに割り当てることができます。

>>> a = numpy.empty((3,3,))
>>> a[:] = numpy.nan
>>> a
array([[ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN]])

私はa[:] = numpy.nanここで、そしてa.fill(numpy.nan)Blaenkによって投稿された代替案の時間を計っています:

$ python -mtimeit "import numpy as np; a = np.empty((100,100));" "a.fill(np.nan)"
10000 loops, best of 3: 54.3 usec per loop
$ python -mtimeit "import numpy as np; a = np.empty((100,100));" "a[:] = np.nan" 
10000 loops, best of 3: 88.8 usec per loop

タイミングはndarray.fill(..)、より速い代替案としての好みを示しています。OTOH、私は一度にスライス全体に値を割り当てることができるnumpyの便利な実装が好きです。コードの意図は非常に明確です。

ndarray.fillインプレースその動作を実行し、そのnumpy.empty((3,3,)).fill(numpy.nan)代わりに返されますNone


8
あなたのコードの意図がより明確であることに同意します。しかし、公平なタイミング(または、あなたがまだそれらを投稿したという事実)に感謝します。感謝します:)
ホルヘイスラエル

2
私はこれが好きですa = numpy.empty((3, 3,)) * numpy.nanfill割り当て方法よりも時間がかかりますが、遅いですが、ワンライナーです!!
heltonbiker 2012

2
この回答を見てください:stackoverflow.com/questions/10871220/...
イワン

3
私はこの.fill()方法を好みますが、配列が大きくなるにつれて速度の違いはほとんどなくなります。
naught101

4
...なぜならnp.empty([2, 5])、配列を作成し、fill()その配列をその場で変更しますが、コピーや参照は返しません。np.empty(2, 5)名前で呼び出す(「変数に割り当てる」)場合は、インプレース操作を行う前に行う必要があります。あなたがそうするならば、同じようなことが起こります[1, 2, 3].insert(1, 4)。リストが作成され、4が挿入されますが、リストへの参照を取得することはできません(したがって、ガベージコレクションが行われたと見なすことができます)。文字列などの不変データでは、インプレースで操作できないため、コピーが返されます。パンダは両方を行うことができます。
flutefreak7

163

別のオプションはnumpy.full、NumPy 1.8+で利用可能なオプションであるを使用することです。

a = np.full([height, width, 9], np.nan)

これはかなり柔軟性があり、必要な他の数値で埋めることができます。


19
私はこれを検討したい最も正しいそれは何eactlyあるので、答えfullのためのものです。 np.empy((x,y))*np.nan優れた次点です(そしてnumpyの古いバージョンとの互換性があります)。
travc

これは遅いfill python -mtimeit "import numpy as np; a = np.empty((100,100));" "a.fill(np.nan)" 100000 loops, best of 3: 13.3 usec per loop python -mtimeit "import numpy as np; a = np.full((100,100), np.nan);" 100000 loops, best of 3: 18.5 usec per loop
ファルナバズ

5
@Farnabazタイミングループ内に同等のコードを配置すると、ほぼ同じになります。2つのメソッドは基本的に同じですが、最初のメソッドではタイマーの外側に "np.empty"があるだけです。python -mtimeit "import numpy as np; a = np.empty((1000,1000)); a.fill(np.nan)" 1000 loops, best of 3: 381 usec per loop $ python -mtimeit "import numpy as np; a = np.full((1000,1000), np.nan);" 1000 loops, best of 3: 383 usec per loop
スコットスタニーウィッツ

47

私は提案された速度の代替案を比較し、十分な大きさのベクトル/行列を埋めるには、val * onesarray(n * [val])を除くすべての代替案が同等に高速であることがわかりました。

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


プロットを再現するコード:

import numpy
import perfplot

val = 42.0


def fill(n):
    a = numpy.empty(n)
    a.fill(val)
    return a


def colon(n):
    a = numpy.empty(n)
    a[:] = val
    return a


def full(n):
    return numpy.full(n, val)


def ones_times(n):
    return val * numpy.ones(n)


def list(n):
    return numpy.array(n * [val])


perfplot.show(
    setup=lambda n: n,
    kernels=[fill, colon, full, ones_times, list],
    n_range=[2 ** k for k in range(20)],
    logx=True,
    logy=True,
    xlabel="len(a)",
)

内部的に同じことをするのでnumpy.full(n, val)遅いより奇妙ですa = numpy.empty(n) .. a.fill(val)
エンドリス

26

知っていnumpy.nanますか?

次のような独自のメソッドを作成できます。

def nans(shape, dtype=float):
    a = numpy.empty(shape, dtype)
    a.fill(numpy.nan)
    return a

その後

nans([3,4])

出力します

array([[ NaN,  NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN,  NaN]])

このコードはメーリングリストのスレッドで見つかりました。


1
やり過ぎのようです。
Mad Physicist

@MadPhysicistそれはあなたの状況に完全に依存します。1つのNaN配列のみを初期化する必要がある場合は、はい、カスタム関数は多分やり過ぎです。ただし、コードの数十箇所でNaN配列を初期化する必要がある場合は、この関数を使用すると非常に便利です。
Xukrao 2018

1
@Xukaro。そのような関数のより柔軟で効率的なバージョンがすでに存在し、他の複数の回答で言及されていることを考えると、実際にはそうではありません。
Mad Physicist、

10

.emptyまたは.fullメソッドをすぐに呼び出さない場合は、常に乗算を使用できます。

>>> np.nan * np.ones(shape=(3,2))
array([[ nan,  nan],
       [ nan,  nan],
       [ nan,  nan]])

もちろん、他の数値でも機能します。

>>> 42 * np.ones(shape=(3,2))
array([[ 42,  42],
       [ 42,  42],
       [ 42, 42]])

しかし、@ u0b34a0f6aeの受け入れられた答えは3倍高速です(numpy構文を記憶するための脳のサイクルではなく、CPUサイクル;):

$ python -mtimeit "import numpy as np; X = np.empty((100,100));" "X[:] = np.nan;"
100000 loops, best of 3: 8.9 usec per loop
(predict)laneh@predict:~/src/predict/predict/webapp$ master
$ python -mtimeit "import numpy as np; X = np.ones((100,100));" "X *= np.nan;"
10000 loops, best of 3: 24.9 usec per loop

6

もう1つの方法はnumpy.broadcast_to(val,n)、サイズに関係なく一定の時間で戻る方法であり、メモリ効率が最も高い(繰り返し要素のビューを返す)。注意点は、戻り値は読み取り専用であることです。

以下は、ニコシュレーマーの回答と同じベンチマークを使用して提案された他のすべての方法のパフォーマンスの比較です。

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


5

言ったように、numpy.empty()はその方法です。ただし、オブジェクトの場合、fill()は、ユーザーが想定しているとおりに動作しない場合があります。

In[36]: a = numpy.empty(5,dtype=object)
In[37]: a.fill([])
In[38]: a
Out[38]: array([[], [], [], [], []], dtype=object)
In[39]: a[0].append(4)
In[40]: a
Out[40]: array([[4], [4], [4], [4], [4]], dtype=object)

たとえば、次のような方法があります。

In[41]: a = numpy.empty(5,dtype=object)
In[42]: a[:]= [ [] for x in range(5)]
In[43]: a[0].append(4)
In[44]: a
Out[44]: array([[4], [], [], [], []], dtype=object)

元の質問とはほとんど関係がないことを除けば、きちんとしています。
Mad Physicist

1
まあ、それは「何か他のもの」がオブジェクトである場合、「numpy行列を0または1以外のものに初期化する」ことについてです:)(より実際には、空のリストで初期化するためにここでgoogleが私を導きました)
ntg

3

ここでまだ言及されていないさらに別の可能性は、NumPyタイルを使用することです。

a = numpy.tile(numpy.nan, (3, 3))

また与える

array([[ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN]])

速度比較についてはわかりません。

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