在scipy中的稀疏矩阵上的Log-sum-exp技巧

时间:2014-06-06 14:54:08

标签: python numpy scipy sparse-matrix logarithm

scipy.misc.logsumexp之类的内容应用于稀疏矩阵(例如scipy.sparse.csr_matrix),指定一个轴的最佳方式是什么?

重点是从计算中删除零。

更新

最好指定我正在寻找执行log-sum-exp trick的内容,执行exp elem-wise的简单连续,对行进行求和并且在{elem-wise}中执行对数是微不足道的{ {1}}。不太重要的是以干净的方式计算沿着行的最大值并减去它,因为稀疏矩阵行中的每个元素被减去相应的最大向量elem(最后保留稀疏矩阵)。

1 个答案:

答案 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].datak = 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并应用上述内容。