2009-08-24 13 views
24

フォーク、gotchasここで、NumpyはストレートPythonと異なりますか?

NumpyがPythonと異なるところには、厄介な点があり、時間がかかる点がありますか?

"その瞬間の恐怖は私が 決して忘れることはありません!"
"女王は言った。"もしあなたがいなければ、 覚書を書いてください。 "

たとえば、NaNは常に問題があります。あなたはそれを実行せずにこれを説明することができ 場合は、自分でポイントを与える -

from numpy import array, NaN, isnan 

pynan = float("nan") 
print pynan is pynan, pynan is NaN, NaN is NaN 
a = (0, pynan) 
print a, a[1] is pynan, any([aa is pynan for aa in a]) 

a = array((0, NaN)) 
print a, a[1] is NaN, isnan(a[1]) 

(私はノックではないよnumpyのを、そこに良い仕事の多くは、ちょうど落とし穴のよくある質問やWikiのは有用であろうと思います。)

編集:私は半ダースの雑用を集めることを望んでいた(ナンシーを学ぶ人々の驚き)。
一般的な問題やよくある説明がある場合は、 をコミュニティWikiに追加することについて話し合うことができます(どこですか?) これまでのところ十分ではないようです。

+5

はコミュニティウィキにする必要があります – SilentGhost

+1

プリミティブタイプについては触れていません。これはPythonの浮動小数点がnp.floatなどと同等であることを意味しますか? – g33kz0r

答えて

21

私にとって最大の問題は、ほぼすべての標準演算子が、配列全体に分散するようにオーバーロードされていることでした。

リストおよびアレイ

>>> l = range(10) 
>>> l 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
>>> import numpy 
>>> a = numpy.array(l) 
>>> a 
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 

乗算の定義はPythonのリストを複製するが、Pythonのリストに定義されていないnumpyのアレイ

>>> l * 2 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
>>> a * 2 
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]) 

加算および除算にわたって分配

>>> l + 2 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: can only concatenate list (not "int") to list 
>>> a + 2 
array([ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) 
>>> l/2.0 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unsupported operand type(s) for /: 'list' and 'float' 
>>> a/2.0 
array([ 0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5]) 

配列のようなリストを扱うためにNumpyがオーバーロードする場合があります

>>> a + a 
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]) 
>>> a + l 
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]) 
+2

はい、それも私を得ました。単純なテーブルの列:op、python、numpy はこれを解決します。 – denis

+2

実際には、 '' a + a'' **はリストに定義されています**。それらを連結します。 –

3
print pynan is pynan, pynan is NaN, NaN is NaN 

これは同一のオブジェクトであるかどうかをテストします。したがって、結果はTrue、False、Trueとなるはずです。新しい浮動小数点オブジェクトを作成しているときに浮動小数点演算を行うためです。

a = (0, pynan) 
print a, a[1] is pynan, any([aa is pynan for aa in a]) 

これで驚くべきことは何か分かりません。

a = array((0, NaN)) 
print a, a[1] is NaN, isnan(a[1]) 

これは私が実行しなければならなかった。 :-) NaNを配列に貼り付けるとnumpy.float64オブジェクトに変換されます。なぜならa [1]がNaNに失敗するからです。

これはすべて私にとってかなり驚くようです。しかし、私は本当にNumPyについて何も知らない。 :-)

12

NaNNoneのようなシングルトンではないので、実際にはそれをチェックすることはできません。少し難しいのは、NaN == NaNがIEEE-754のようにFalseであるということです。そのため、numpy.isnan()関数を使用して浮動小数点数が数値でないかどうかを確認する必要があります。 Python 2.6以降を使用している場合は、標準ライブラリmath.isnan()を使用してください。

+3

これはNaNの定義にあります。 def isnan(x):return(x!= x) – u0b34a0f6ae

21

私はこの1つが面白いだと思う:Pythonのリストについては

>>> import numpy as n 
>>> a = n.array([[1,2],[3,4]]) 
>>> a[1], a[0] = a[0], a[1] 
>>> a 
array([[1, 2], 
     [1, 2]]) 

一方、意図したとおり、この作品:

>>> b = [[1,2],[3,4]] 
>>> b[1], b[0] = b[0], b[1] 
>>> b 
[[3, 4], [1, 2]] 

おかしいサイドノート:numpyの自体はshuffle機能にバグがありましたなぜならそれはその表記を使用したからです:-)(here参照)。

最初のケースでは、配列のビューを扱っているため、その値はインプレースで上書きされます。

+2

numpy配列がどのように終わるか説明できますか? – sundar

2

ニールMartinsen、バレルからnumpy-discussion 9月7日に -

numpyのに利用できるndarrayタイプは概念的 Pythonのイテレート可能オブジェクトの拡張ではありません。あなたはこの 問題で、他のnumpyのユーザーを助ける したい場合は、numpyの配列の真理値はPythonのシーケンスとは異なる numpy-docs

6

でオンラインドキュメントエディタでドキュメント を編集することができますタイプでは、空でないシーケンスがすべてtrueです。

>>> import numpy as np 
>>> l = [0,1,2,3] 
>>> a = np.arange(4) 
>>> if l: print "Im true" 
... 
Im true 
>>> if a: print "Im true" 
... 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: The truth value of an array with more than one element is ambiguous. Use 
a.any() or a.all() 
>>> 

数値タイプは、ゼロでない数値の集合である場合にtrueです.Nupy配列はこの定義を継承します。しかし、数字の集合では、真理は「すべての要素が非ゼロ」であること、または「少なくとも1つの要素が非ゼロである」ことを合理的に意味する可能性があります。 Numpyは、どの定義が意味されているかを推測することを拒否し、上記の例外を発生させます。 .any()および.all()メソッドを使用すると、trueの意味を指定できます。

>>> if a.any(): print "Im true" 
... 
Im true 
>>> if a.all(): print "Im true" 
... 
>>> 
7

スライシングはビューを作成し、コピーは作成しません。

>>> l = [1, 2, 3, 4] 
>>> s = l[2:3] 
>>> s[0] = 5 
>>> l 
[1, 2, 3, 4] 

>>> a = array([1, 2, 3, 4]) 
>>> s = a[2:3] 
>>> s[0] = 5 
>>> a 
array([1, 2, 5, 4]) 
+3

常にではありません: "numpyには2種類のファンシーインデックスがあり、同様に動作します http://mail.scipy.org/pipermail/numpy-discussion/2008-January/031101.html – denis

2

私は、要素のリストを掛け合わせるだけで、要素が私を捕まえたという事実を発見しました。

あなたはこのような要素のリストを作成し、それらに異なる操作を行うつもりのであれば、あなたがscupperedさ
>>> a=[0]*5 
>>>a 
[0,0,0,0,0] 
>>>a[2] = 1 
>>>a 
[0,0,1,0,0] 
>>>b = [np.ones(3)]*5 
>>>b 
[array([ 1., 1., 1.]), array([ 1., 1., 1.]), array([ 1., 1., 1.]), array([ 1., 1., 1.]), array([ 1., 1., 1.])] 
>>>b[2][1] = 2 
>>>b 
[array([ 1., 2., 1.]), array([ 1., 2., 1.]), array([ 1., 2., 1.]), array([ 1., 2., 1.]), array([ 1., 2., 1.])] 

...

簡単な解決策は、反復的に( 'を使用してアレイの各々を作成することですforループやリストの理解)、より高次元の配列を使用することができます(たとえば、これらの1D配列のそれぞれは、2D配列の行です)。

+0

これは'numpy'とはまったく無関係な純粋なpythonのようなものです。 – jolvi

+0

jolvi ...もう少し見ると... np.ones(3)の代わりにrange(3)でこれを試してみてください...それはnumpy gotchaです。それは一般的にコードを高速化し、回避することができる故意の動作です。 – sillyMunky

+0

'[range(3)] * 5'は' [range(0,3)、range(0,3)、range(0,3)、range(0,3)、range '。私が 'a = [list(range(3))] * 5を実行すると、最初の要素が '33'に設定された1つの単一の 'list'インスタンスへの5つの参照、つまり1つの' numpy.array'と同じです。a [0] [0] = 33'あなたがしたようにインスタンス。 – jolvi

23

__eq__はboolを返さないため、あらゆる種類のコンテナでnumpy配列を使用すると、コンテナ固有の回避策を使用しなくても同等のテストができなくなります。

例:

>>> import numpy 
>>> a = numpy.array(range(3)) 
>>> b = numpy.array(range(3)) 
>>> a == b 
array([ True, True, True], dtype=bool) 
>>> x = (a, 'banana') 
>>> y = (b, 'banana') 
>>> x == y 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() 

これは恐ろしい問題です。たとえば、TestCase.assertEqual()を使用するコンテナの単体テストを記述することはできず、代わりにカスタム比較関数を記述する必要があります。回避策special_eq_for_numpy_and_tuplesを書くとします。今、私たちは、unittestの中でこれを行うことができます:

x = (array1, 'deserialized') 
y = (array2, 'deserialized') 
self.failUnless(special_eq_for_numpy_and_tuples(x, y)) 

今、私たちは私たちがnumpyの配列を格納するために使用する可能性があるすべてのコンテナ型のためにこれを行う必要があります。また、その特殊なケースを処理しなければならない今、私たちのコンテナ固有の等価比較の各機能を

>>> a = numpy.array(range(3)) 
>>> b = numpy.array(range(5)) 
>>> a == b 
False 

:さらに、__eq__はブール値ではなく、boolsの配列を返す可能性があります。

おそらく、この疣贅をサブクラスでパッチすることができますか?

>>> class SaneEqualityArray (numpy.ndarray): 
... def __eq__(self, other): 
...  return isinstance(other, SaneEqualityArray) and self.shape == other.shape and (numpy.ndarray.__eq__(self, other)).all() 
... 
>>> a = SaneEqualityArray((2, 3)) 
>>> a.fill(7) 
>>> b = SaneEqualityArray((2, 3)) 
>>> b.fill(7) 
>>> a == b 
True 
>>> x = (a, 'banana') 
>>> y = (b, 'banana') 
>>> x == y 
True 
>>> c = SaneEqualityArray((7, 7)) 
>>> c.fill(7) 
>>> a == c 
False 

これは正しいことをしているようです。クラスはまた、それがしばしば有用であるため、要素間比較を明示的にエクスポートする必要があります。

5

(関連ではなく、Pythonの対numpyのscipyのダウンロードよりも対numpyの落とし穴、)配列の実際のサイズを超えた


スライスは動作が異なります:

>>> import numpy, scipy.sparse 

>>> m = numpy.random.rand(2, 5) # create a 2x5 dense matrix 
>>> print m[:3, :] # works like list slicing in Python: clips to real size 
[[ 0.12245393 0.20642799 0.98128601 0.06102106 0.74091038] 
[ 0.0527411 0.9131837 0.6475907 0.27900378 0.22396443]] 

>>> s = scipy.sparse.lil_matrix(m) # same for csr_matrix and other sparse formats 
>>> print s[:3, :] # doesn't clip! 
IndexError: row index out of bounds 

のでscipy.sparse配列をスライスし、スライス範囲が範囲内にあることを手動で確認する必要があります。これは、NumPyとプレーンなPythonの両方の仕組みとは異なります。

2

ないような大きな落とし穴:ブールスライスで、私は時々私はpythonの二重の比較のように

​​

を行うことがしたいです。代わりに、私が持っている(あなたがより良いものを知っていない限り?)も

x[ np.logical_and(3<=y, y<7) ] 

を書き、np.logical_andとnp.logical_or 2つのだけの引数それぞれを取るために、私は、彼らが可変数を利用したいと思いますまたはリストのように、私は2つ以上の論理節を提供することができます。

(1.3 numpyの、多分これは、すべてのそれ以降のバージョンで変更されました。)

+0

約 x [(3≦y)&(y <7)] ? – mdaoust

6
In [1]: bool([]) 
Out[1]: False 

In [2]: bool(array([])) 
Out[2]: False 

In [3]: bool([0]) 
Out[3]: True 

In [4]: bool(array([0])) 
Out[4]: False 

だから、その真理値をチェックすることで、アレイの空虚をテストしていません。 size(array())を使用してください。

のいずれか、len(array())を使用しないでください:

>>> all(False for i in range(3)) 
False 
>>> from numpy import all 
>>> all(False for i in range(3)) 
True 
>>> any(False for i in range(3)) 
False 
>>> from numpy import any 
>>> any(False for i in range(3)) 
True 

numpyののanyallは、発電機とうまく再生されない、と:誰がこれまでに述べてきたように思わない

In [1]: size(array([])) 
Out[1]: 0 

In [2]: len(array([])) 
Out[2]: 0 

In [3]: size(array([0])) 
Out[3]: 1 

In [4]: len(array([0])) 
Out[4]: 1 

In [5]: size(array(0)) 
Out[5]: 1 

In [6]: len(array(0)) 
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-6-5b2872696128> in <module>() 
----> 1 len(array(0)) 

TypeError: len() of unsized object 
+0

'size(array(。)) 'を使うことをお勧めします。' len(array(。))'の使い方はどうですか? – jolvi

+1

いいえ、 'len'は' size'とは異なります。 'len(array(0))'は 'unsizeされたオブジェクトのlen() 'を発生させるのに対し、' size(array(0)) '→1は0ランク配列に1つの値を持つので、1 – endolith

+0

。 'array(0)'が有効な構造体でなければならない理由は何ですか? – jolvi

3

彼らがしないことを警告するエラーは起こさないでください。

1

なしの0-D配列なしのように見えるが、それは同じではありません。

In [1]: print None 
None 

In [2]: import numpy 

In [3]: print numpy.array(None) 
None 

In [4]: numpy.array(None) is None 
Out[4]: False 

In [5]: numpy.array(None) == None 
Out[5]: False 

In [6]: print repr(numpy.array(None)) 
array(None, dtype=object) 
2

numpy.arrayとの組み合わせで*=割り当てと驚き:

>>> from numpy import array 

>>> a = array([1, 2, 3]) 
>>> a *= 1.1 
>>> print(a) 
[1 2 3] # not quite what we expect or would like to see 

>>> print(a.dtype) 
int64 # and this is why 

>>> a = 1.1 * a # here, a new array is created 
>>> print(a, a.dtype) 
[ 1.1 2.2 3.3] float64 # with the expected outcome 

、驚くべきことで迷惑理解できる。 *=演算子はarrayデータのタイプを変更しないので、intarrayの乗算はfloatであり、この乗算の従来の意味では失敗します。一方、Pythonバージョンa = 1; a *= 1.1は期待どおりに動作します。