将scipy.misc.logsumexp
之类的内容应用于稀疏矩阵(例如scipy.sparse.csr_matrix
),指定一个轴的最佳方式是什么?
重点是从计算中删除零。
更新
最好指定我正在寻找执行log-sum-exp trick的内容,执行exp elem-wise的简单连续,对行进行求和并且在{elem-wise}中执行对数是微不足道的{ {1}}。不太重要的是以干净的方式计算沿着行的最大值并减去它,因为稀疏矩阵行中的每个元素被减去相应的最大向量elem(最后保留稀疏矩阵)。
答案 0 :(得分:3)
CSR矩阵X
的非零条目由
X[i].data
和(一个排列)实际行的值将通过附加X.shape[1] - len(X[i].data)
零来获得。
logsumexp(a) = max(a) + log(∑ exp[a - max(a)])
表示向量a
。我们设置b = X[i].data
和k = X.shape[1] - len(X[i].data)
,并将我们之前的置换行X
表示为
(b, 0ₖ)
使用0ₖ表示长度为k
和(⋅,⋅)的零向量,用于连接。然后
logsumexp((b, 0ₖ))
= max((b, 0ₖ)) + log(∑ exp[(b, 0ₖ) - max((b, 0ₖ))])
= max(max(b), 0) + log(∑ exp[(b, 0ₖ) - max(max(b), 0)])
= max(max(b), 0) + log(∑ exp[b - max(max(b), 0)] + ∑ exp[0ₖ - max(max(b), 0)])
= max(max(b), 0) + log(∑ exp[b - max(max(b), 0)] + k × exp[-max(max(b), 0)])
所以我们得到算法
def logsumexp_csr_row(x):
data = x.data
mx = max(np.max(data), 0)
tmp = data - mx
r = np.exp(tmp, out=tmp).sum()
k = X.shape[1] - len(data)
return mx + np.log(r + k * np.exp(-mx))
表示CSR行向量。通过列表推导可以轻松地将此算法扩展到完整矩阵,尽管更高效的表单将使用indptr
循环遍历行:
def logsumexp_csr_rows(X):
result = np.empty(X.shape[0])
for i in range(X.shape[0]):
data = X.data[X.indptr[i]:X.indptr[i+1]]
# fill in from logsumexp_csr_row
result[i] = mx + np.log(r + k * np.exp(-mx))
return result
列式版本更棘手;转换矩阵并转换回CSR可能最容易。
UPDATE 好的,我误解了这个问题:OP根本不感兴趣处理零,所以上面的推导是没用的,算法应该是
def logsumexp_row_nonzeros(X):
result = np.empty(X.shape[0])
for i in range(X.shape[0]):
result[i] = logsumexp(X.data[X.indptr[i]:X.indptr[i+1]])
return result
这只是在CSR矩阵上填写行方式操作的一般方案。对于逐列,转置,转换回CSR并应用上述内容。