【发布时间】:2018-03-10 07:13:39
【问题描述】:
我有两种计算数组单位向量的方法,这两种方法都处理稀疏数组。其中一个非常“手动”计算,而另一个更“正式”(来自 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")
在运行测试时,我想检查每个方法的输出是否相同。以下是示例代码的 sn-p:
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
我认为问题可能来自稀疏数组类型,但正如您所见,它们是相等的。您还可以直观地看到元素完全相同。
那么为什么 array_equal 返回 false?怎么改?
【问题讨论】:
-
您可能需要注意一些警告。另外,请改用
np.allclose(output1, output2)。 -
看来
np.array_equal不是为处理稀疏数组而设计的。 this answer 会完成你想做的事情吗?np.allclose(output1, output2) -
作为一般规则
np.函数不适用于稀疏矩阵。您必须使用稀疏函数或方法(或委托给稀疏方法的 numpy 函数)。稀疏矩阵不是ndarray的子类。
标签: python numpy sparse-matrix