3

期待どおりに実行されない単純なコードがあります。

from numpy import *
from numpy.linalg import *
from sets import Set

W = matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')
E = matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')

matrices = Set([])
matrices.add(W)
matrices.add(E)
matrices

マトリックスは同じですが、セットの内容を印刷すると、両方とも別々に表示されます。ただし、以下のように割り当てると、重複は表示されません。

W = matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')
E = W

何が起こっているのですか?大量の行列を生成する、作成中のプログラムで行列の重複を回避する方法が必要です。

編集:次の出力が必要です

set([matrix([[ 1,  1,  1,  1],
        [ 1,  1, -1, -1],
        [ 1, -1,  2, -2],
        [ 1, -1, -2,  2]])])

ただし、代わりに次を取得します。

set([matrix([[ 1,  1,  1,  1],
        [ 1,  1, -1, -1],
        [ 1, -1,  2, -2],
        [ 1, -1, -2,  2]]), matrix([[ 1,  1,  1,  1],
        [ 1,  1, -1, -1],
        [ 1, -1,  2, -2],
        [ 1, -1, -2,  2]])])
4

4 に答える 4

3

これは、セットが__ eq __および__ hash __特別なメソッドを使用して項目の等価性を検出するために発生します ( http://docs.python.org/2/library/sets.htmlを参照)。しかし、行列オブジェクトには異なるハッシュがあり、これらの__ eq __メソッドは true/false を返さず、代わりに行列を返します。

>>> W == E
matrix([[ True,  True,  True,  True],
        [ True,  True,  True,  True],
        [ True,  True,  True,  True],
        [ True,  True,  True,  True]], dtype=bool)
>>> W > E
matrix([[False, False, False, False],
        [False, False, False, False],
        [False, False, False, False],
        [False, False, False, False]], dtype=bool)
于 2013-01-08T21:18:48.340 に答える
3

Python がオブジェクト間の類似性のチェックを内部的に実装する方法に問題が発生しています。具体的には、「ハッシュ可能」と見なされるオブジェクトを比較する方法です。

Pythonコンストラクターが 2 つのオブジェクトが同じかどうかを判断する方法は、 (および別の と呼ばれる)setというマジック メソッドの呼び出しに基づいています。2 つのオブジェクトを呼び出した結果が同じ値を返した場合 (およびそれらを呼び出した場合は が返された場合)、それらのオブジェクトは同じであると見なされます。2 つのオブジェクトを呼び出すと異なる値が返される場合、同じとは見なされないと見なされます。__hash____eq____hash____eq__True__hash__set

セットには、「ハッシュ可能」と見なされるオブジェクト、つまりメソッドを実装するオブジェクトのみを含めることができることにも注意してください__hash__

これがどのように機能するか見てみましょう:

In [73]: a = "one"
In [74]: b = "one"
In [75]: c = "two"

In [76]: a.__hash__()
Out[76]: -261223665

In [77]: b.__hash__()
Out[77]: -261223665

In [78]: c.__hash__()
Out[78]: 323309869

In [79]: set([a,b,c])
Out[79]: set(['two', 'one'])

次に、numpy をインポートして、マトリックスのハッシュ値を確認します。

In [81]: import numpy as np
In [82]: W = np.matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')
In [83]: E = np.matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')

In [84]: W.__hash__()
Out[84]: 4879307

In [85]: E.__hash__()
Out[85]: 4879135

同じものが含まれているように見えますが、Eとのハッシュが異なることに注意してください。Wそれらのハッシュは異なるため、セット内の異なるオブジェクトとして表示されます。のような割り当てを行うとW = E、名前WEは実際には同じオブジェクトを参照しています。

これに対する回避策が必要な場合は、マトリックスの作成に使用している文字列を保存できます。

In [86]: set(['1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2',
              '1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2'])
Out[86]: set(['1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2'])
于 2013-01-08T21:22:36.917 に答える
2

matrix__eq__でそれらを使用する場合、非常に適切に動作すると__hash__メソッドがありませんset。a を使用しsetて一意にする場合は、マトリックスをヘルパー クラスでラップする必要があります。このような単純なことを行う必要があります。

import hashlib

class MatrixWrap:
     def __init__(self, matrix):
         self.matrix = matrix
     def __hash__(self):
         return int(hashlib.sha1(self.matrix).hexdigest(), 16)
     def __eq__(self, x):
         return self.__hash__() == x.__hash__()

その後、あなたはただ行うことができます。

from numpy import *
from numpy.linalg import *

W = matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')
E = matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')
X = matrix('2, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')

matrices = set()
matrices.add(MatrixWrap(W))
matrices.add(MatrixWrap(E))
matrices.add(MatrixWrap(X))

for a in matrices:
    print a.matrix

...独自の行列を一覧表示します。

于 2013-01-08T21:48:19.500 に答える
0

すべての回答とコメントは良好で、問題を特定し、@Joachim Isaksson が適切な解決策を特定しました。次のように、通常の配列をシリアル化し、データをセットにダンプ/ロードすることもできることを指摘したいと思います。

import numpy as np

def arrayToTuple(arr):
    arrType = arr.dtype.str
    arrShape = arr.shape
    arrData = arr.tostring()

    return (arrType,arrShape,arrData)

def tupleToArray(tupl):
    arrType, arrShape, arrData = tupl

    return np.matrix( np.fromstring(arrData, dtype=arrType).reshape(arrShape) )
        # remove the matrix( ) wrap to return arrays instead of matrices

次に、コードは次のようになります。

W = matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')
E = matrix('1, 1, 1, 1; 1, 1, -1, -1; 1, -1, 2, -2; 1, -1, -2, 2')

matrixTuples = set()

matrixTuples.add(arrayToTuple(W))
matrixTuples.add(arrayToTuple(E))

for mTupl in matrixTuples:
    print tupleToArray(mTupl)

これは、通常の bool、integer、float 配列でも機能します (ただし、オブジェクト配列や文字列配列では機能しません)。arrayFromTuple の戻り値で matrix( ) ラッパーを削除するだけです。これらの関数は、matrixToTuple と tupleToMatrix という名前の方が適切であると思いますが、行列または配列のどちらを操作しているかに関係なく、これらは非常に近いものです。

于 2013-01-08T22:57:24.120 に答える