Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么np.array_equal对于这两个视觉上相等的稀疏数组返回False?_Python_Numpy_Sparse Matrix - Fatal编程技术网

Python 为什么np.array_equal对于这两个视觉上相等的稀疏数组返回False?

Python 为什么np.array_equal对于这两个视觉上相等的稀疏数组返回False?,python,numpy,sparse-matrix,Python,Numpy,Sparse Matrix,我有两种方法来计算数组的单位向量,这两种方法都可以处理稀疏数组。其中一个非常“手动”计算,而另一个更“正式”(来自gensim.matutils源代码) 这是手动方法: def manual_unitvec(vec): vec = vec.tocsr() if sparse.issparse(vec): vec_sum_of_squares = vec.multiply(vec) unit = 1. / np.sqr

我有两种方法来计算数组的单位向量,这两种方法都可以处理稀疏数组。其中一个非常“手动”计算,而另一个更“正式”(来自gensim.matutils源代码)

这是手动方法:

def manual_unitvec(vec):
        vec = vec.tocsr()
        if sparse.issparse(vec):
            vec_sum_of_squares = vec.multiply(vec)
            unit = 1. / np.sqrt(vec_sum_of_squares.sum())
            return vec.multiply(unit)
        elif not sparse.issparse(vec):
            sum_vec_squared = np.sum(vec ** 2)
            vec /= np.sqrt(sum_vec_squared)
            return vec
这是改进的gensim方法,其中显式计算单位向量的方法是
unitvec

import numpy as np
from scipy import sparse
from gensim.matutils import ret_normalized_vec, blas
import scipy.sparse

blas_nrm2 = blas('nrm2', np.array([], dtype=float))
blas_scal = blas('scal', np.array([], dtype=float))


def unitvec(vec, norm='l2'):
    """Scale a vector to unit length.
    Parameters
    ----------
    vec : {numpy.ndarray, scipy.sparse, list of (int, float)}
        Input vector in any format
    norm : {'l1', 'l2'}, optional
        Normalization that will be used.
    Returns
    -------
    {numpy.ndarray, scipy.sparse, list of (int, float)}
        Normalized vector in same format as `vec`.
    Notes
    -----
    Zero-vector will be unchanged.
    """
    if norm not in ('l1', 'l2'):
        raise ValueError("'%s' is not a supported norm. Currently supported norms are 'l1' and 'l2'." % norm)

    if scipy.sparse.issparse(vec):
        print("INSIDE SPARSE HANDLING")
        vec = vec.tocsr()
        if norm == 'l1':
            veclen = np.sum(np.abs(vec.data))
        if norm == 'l2':
            veclen = np.sqrt(np.sum(vec.data ** 2))
        if veclen > 0.0:
            if np.issubdtype(vec.dtype, np.int) == True:
                vec = vec.astype(np.float)
                return vec / veclen
            else:
                vec /= veclen
                return vec.astype(vec.dtype)
        else:
            return vec

    if isinstance(vec, np.ndarray):
        print("INSIDE NORMAL VEC HANDLING")
        vec = np.asarray(vec, dtype=vec.dtype)
        if norm == 'l1':
            veclen = np.sum(np.abs(vec))
        if norm == 'l2':
            veclen = blas_nrm2(vec)
        if veclen > 0.0:
            if np.issubdtype(vec.dtype, np.int) == True:
                vec = vec.astype(np.float)
                return blas_scal(1.0 / veclen, vec).astype(vec.dtype)
            else:
                return blas_scal(1.0 / veclen, vec).astype(vec.dtype)
        else:
            return vec

    try:
        first = next(iter(vec))  # is there at least one element?
    except StopIteration:
        return vec

    if isinstance(first, (tuple, list)) and len(first) == 2:  # gensim sparse format
        print("INSIDE GENSIM SPARSE FORMAT HANDLING")
        if norm == 'l1':
            length = float(sum(abs(val) for _, val in vec))
        if norm == 'l2':
            length = 1.0 * math.sqrt(sum(val ** 2 for _, val in vec))
        assert length > 0.0, "sparse documents must not contain any explicit zero entries"
        return ret_normalized_vec(vec, length)
    else:
        raise ValueError("unknown input type")
在运行测试时,我想检查这些方法的输出是否相同。下面是一段示例代码:

vec = sparse.csr_matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).astype(np.float32)
output1 = manual_unitvec(vec)
output2 = unitvec(vec)
print(output1)
print(' ')
print(output2) 
print(np.array_equal(output1, output2))
print(type(output1) == type(output2))
所以我要检查的是assertTrue(output1,output2)。您不能这样做,因为数组的真值不明确,所以我使用
assertTrue(np.array_equal(output1,output2))

现在的问题是array_equal并不认为output1和output2是相同的,尽管我可以从打印出来的结果中看出它们是相同的

运行上面的所有代码会得到以下输出:

MacBook-Air:matutils.unitvec Olly$ python try.py
INSIDE SPARSE HANDLING
try.py:80: FutureWarning: Conversion of the second argument of issubdtype from `int` to `np.signedinteger` is deprecated. In future, it will be treated as `np.int64 == np.dtype(int).type`.
  if np.issubdtype(vec.dtype, np.int) == True:
  (0, 0)    0.059234887
  (0, 1)    0.118469775
  (0, 2)    0.17770466
  (1, 0)    0.23693955
  (1, 1)    0.29617444
  (1, 2)    0.35540932
  (2, 0)    0.4146442
  (2, 1)    0.4738791
  (2, 2)    0.53311396

  (0, 0)    0.059234887
  (0, 1)    0.118469775
  (0, 2)    0.17770466
  (1, 0)    0.23693955
  (1, 1)    0.29617444
  (1, 2)    0.35540932
  (2, 0)    0.4146442
  (2, 1)    0.4738791
  (2, 2)    0.53311396
/Users/Olly/anaconda2/lib/python2.7/site-packages/scipy/sparse/compressed.py:226: SparseEfficiencyWarning: Comparing sparse matrices using == is inefficient, try using != instead.
  " != instead.", SparseEfficiencyWarning)
False
True
我认为问题可能来自稀疏数组类型,但正如您所看到的,它们是相等的。您还可以直观地看到这些元素完全相同


那么为什么数组_等于返回false呢?如何更改它?

在您的第一个函数中,您可以执行以下操作:

    vec = vec.tocsr()
    if sparse.issparse(vec):
我认为
issparse
测试对您没有任何帮助。如果输入参数是稀疏矩阵,它有一个
tocsr
方法,结果是稀疏矩阵。如果
vec
ndarray
is没有
tocsr
方法,第一行将抛出错误

在该函数的其余部分中,稀疏矩阵具有
乘法
方法和
求和
方法。
sum
的结果很密集,因此
np.sqrt
可以很好地处理它。实际上
np.sqrt(M)
也适用于稀疏矩阵,因为
M.sqrt
存在

在第二个函数中,使用
data
属性,该属性是1d
ndarray

np.sum(np.abs(vec.data))
那很好。但是请注意,稀疏矩阵的
M.\uuuu abs\uuuu

self._with_data(abs(self._deduped_data()))
以更为全面的方式,函数/方法,如
abs
sqrt
也可以使用
.data
属性。只有它们返回一个新的稀疏矩阵

至于测试,请看
np.array_equal

return bool(asarray(a1 == a2).all())
如果我尝试在
output1
上使用它(我不会尝试您的
gensim
解决方案)

In [106]: np.array_equal(output1, output1)
/usr/local/lib/python3.5/dist-packages/scipy/sparse/compressed.py:226: SparseEfficiencyWarning: Comparing sparse matrices using == is inefficient, try using != instead.
  " != instead.", SparseEfficiencyWarning)
Out[106]: False
它不喜欢在稀疏矩阵上取
=
。通常这些矩阵很大,有许多0。这意味着所有这些矩阵的结果都是
真的
,因此不再稀疏

您的
output1
是一个稀疏矩阵,但至少对于这些输入而言,不是稀疏矩阵:

In [107]: output1.A
Out[107]: 
array([[0.05923489, 0.11846977, 0.17770466],
       [0.23693955, 0.29617444, 0.35540932],
       [0.4146442 , 0.4738791 , 0.53311396]], dtype=float32)
但是,即使您绕过稀疏位,
np.array_equal(output1.A,output2.A)
也可能由于浮点比较而失败

密集版本上的
allclose
可能是最简单的测试:

In [113]: np.allclose(output1.A, output1.A)
Out[113]: True
您还可以比较
数据
(假设稀疏度相同):

更全面的稀疏测试需要检查
形状
nnz
、和
索引
属性


实际上,我不确定
np.array_equal
在哪里失败。请注意,它以
a1=asarray(a1)开始
,它生成0d对象数据类型数组。这是坚持将其输入作为数组处理的
numpy
函数之一。它不是稀疏感知的。

您可能需要注意一些警告。另外,请尝试
np.allclose(output1,output2)
相反。似乎
np.array_equal
不是为处理稀疏数组而设计的。它可以完成您试图做的事情吗?
np.allclose(output1,output2)
作为一般规则
np。
函数不处理稀疏矩阵。您必须使用稀疏函数或方法(或委托给稀疏方法的numpy函数)。稀疏矩阵不是
ndarray
的子类。
In [114]: np.allclose(output1.data, output1.data)
Out[114]: True