28

皆さん、

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] )

(私はナンピーをノックしているわけではありません。そこにはたくさんの良い仕事があります。よくある質問や落とし穴の Wiki が役立つと思います。)

編集: 私は半ダースの落とし穴を集めたいと思っていました (Numpy を学んでいる人々へのサプライズ)。
次に、一般的な落とし穴や、より適切な一般的な説明がある場合は、それらをコミュニティ Wiki に追加することについて話し合うことができます (どこに?) 今のところ十分ではないようです。

4

15 に答える 15

25

__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。これで、単体テストでこれを実行できます。

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

ここで、numpy 配列を格納するために使用するすべてのコンテナー タイプに対してこれを行う必要があります。さらに、__eq__bool の配列ではなく bool を返す場合があります。

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

ここで、コンテナー固有の各等値比較関数も、その特殊なケースを処理する必要があります。

サブクラスでこのいぼにパッチを当てることができるでしょうか?

>>> 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

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

于 2011-05-19T21:43:35.123 に答える
22

これは面白いと思います:

>>> 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]])

一方、Pythonリストの場合、これは意図したとおりに機能します。

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

面白い補足:numpy自体は、shuffleその表記を使用していたため、関数にバグがありました:-)(ここを参照)。

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

于 2009-08-24T15:58:42.603 に答える
22

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

リストと配列を定義する

>>> 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 リストを複製しますが、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])

足し算と割り算は python リストでは定義されていません

>>> 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])
于 2009-08-24T21:44:02.520 に答える
12

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

于 2009-08-24T13:36:41.230 に答える
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])
于 2009-09-12T02:19:46.187 に答える
6

Numpy 配列の真偽値は、空でないシーケンスが真である Python シーケンス タイプの真偽値とは異なります。

>>> 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 であり、数値のコレクションとして、numpy 配列はこの定義を継承します。しかし、数値のコレクションでは、真実は「すべての要素がゼロではない」または「少なくとも 1 つの要素がゼロではない」ことを合理的に意味する可能性があります。Numpy は、どの定義が意図されているかを推測することを拒否し、上記の例外を発生させます。.any()メソッドとメソッドを使用すると.all()、 true の意味を指定できます。

>>> if a.any(): print "Im true"
... 
Im true
>>> if a.all(): print "Im true"
... 
>>>
于 2009-09-12T01:45:23.343 に答える
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())

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
于 2013-02-20T17:35:11.563 に答える
5

(関連しますが、NumPy vs Pythonではなく、NumPy vs. SciPyの落とし穴)


配列の実際のサイズを超えてスライスすると、動作が異なります。

>>> 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の両方がどのように機能するかとは異なります。

于 2011-07-29T16:21:20.147 に答える
3

これまで誰も言及していないようです:

>>> 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

numpyanyallはジェネレーターとうまく連携せず、そうでないことを警告するエラーを発生させません。

于 2013-02-20T17:39:45.457 に答える
3
print pynan is pynan, pynan is NaN, NaN is NaN

これは同一性、つまり同じオブジェクトであるかどうかをテストします。したがって、結果は明らかにTrue、False、Trueになるはずです.float(何でも)を実行すると、新しいfloatオブジェクトが作成されるためです。

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] is NaN が失敗する理由です。

これはすべて、私にはまったく驚くべきことではないように思えます。しかし、NumPy についてはあまり詳しくありません。:-)

于 2009-08-24T13:31:25.247 に答える
2

numpy-discussion 9 月 7 日の Neil Martinsen-Burrell から--

Numpy で利用可能な ndarray 型は、概念的には Python の iterable の拡張ではありません。この問題について他の Numpy ユーザーを支援したい場合は、 numpy-docsのオンライン ドキュメント エディターでドキュメントを編集できます。

于 2009-09-11T15:30:19.127 に答える
2

要素のリストを掛け合わせると、要素のビューが作成されるだけであるという事実に気付きました。

>>> 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 配列の行であり、一般に高速です)。

于 2010-09-24T22:39:20.223 に答える
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データの型を変更しないため、a による an の乗算は、このint array乗算floatの従来の意味では失敗します。一方、 Python バージョンa = 1; a *= 1.1は期待どおりに動作します。

于 2015-01-28T01:43:25.937 に答える
2

それほど大きな落とし穴ではありません: ブールスライシングを使用すると、できることがあると思うことがあります

  x[ 3 <= y < 7 ]

Python の二重比較のように。代わりに、私は書く必要があります

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

(もっと良いことを知らない限り?)

また、np.logical_and と np.logical_or はそれぞれ 2 つの引数しか取りません。変数またはリストを取りたいので、2 つ以上の論理句をフィードできます。

(numpy 1.3、おそらくこれは後のバージョンですべて変更されています。)

于 2011-09-12T06:26:24.217 に答える