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 __方法不返回真/假,而是矩阵:

>>> 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 如何在内部检查对象之间的相似性的问题。具体来说,如何比较被认为是“可散列”的对象。

pythonset构造函数决定两个对象是否相同的方式是基于调用一个名为__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

请注意,散列是不同的EW即使它们似乎包含相同的东西。由于它们的哈希值不同,它们将在集合中显示为不同的对象。当您像 一样进行赋值时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___ 如果要使用 a使它们独一无二,则需要将矩阵包装在辅助类中。像这样简单的事情应该做;__hash__setset

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、整数和浮点数组(但不是对象或字符串数​​组)——只需删除 arrayFromTuple 返回的 matrix( ) 包装器。我想这些函数可能更好地命名为 matrixToTuple 和 tupleToMatrix 但无论您使用的是矩阵还是数组,它们都非常接近。

于 2013-01-08T22:57:24.120 回答