如何计算大型稀疏概率矩阵的列信息熵

How do I calculate the column-wise information entropy of a large sparse probability matrix

我已经使用 sklearn 的 CountVectorizer 将我的语料库(200 万个文档)转换为词袋稀疏矩阵。稀疏矩阵的形状约为 2000000 x 170000(即:语料库词汇表中的 170k 个词)。

我对处理稀疏矩阵没有经验,但已经设法对其执行简单的计算,比如计算整个语料库中每个单词的方差,因为它涉及简单的均值和平方运算矩阵。

我现在遇到的问题是我不知道如何有效地计算稀疏矩阵的列方向熵。目前,我正在遍历每一列并将单词出现概率作为列表提供给 scipy.stats.entropy,由于稀疏矩阵的大小,这需要很长时间。

为了清楚起见,举个例子:

# P: Column-wise word probability sparse matrix
P = [[0.2, 0.0, 0.5, 0.3, 0.0, 0.0],
     [0.5, 0.5, 0.5, 0.6, 1.0, 0.0],
     [0.0, 0.0, 0.0, 0.1, 0.0, 0.5],
     [0.3, 0.5, 0.0, 0.0, 0.0, 0.5]]

from scipy.stats import entropy
entropy_list = []
for index in range(P.shape[1]):
    entropy_list.append(entropy(P[:,index].todense()))

我希望获得一个长度为 170000 的数组,因为我正在计算语料库词汇表中每个单词的熵。到目前为止,对我当前的代码进行计时,计算 10000 个单词的熵大约需要 25 分钟。按照这个速度,我需要 7 个小时才能完成计算。谁能帮我找到更有效的方法?

使用axis参数,可以计算整个数组的列方向熵:

In [9]: x=np.random.rand(80,100)
In [13]: e1=entropy(x, axis=0)
In [14]: e2=np.array([entropy(x[:,i]) for i in range(100)])
In [15]: np.allclose(e1,e2)

次:

In [16]: timeit e1=entropy(x, axis=0)
240 µs ± 13.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [17]: timeit e2=np.array([entropy(x[:,i]) for i in range(100)])
3.42 ms ± 7.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

您的稀疏 P 可能太大而无法执行 P.A (toarray),但您可以使用卡盘、柱块而不是一个一次。

对于 (2000000,170000) 形状,该矩阵的 csc 格式应该消耗更少的内存(小 indptr 数组),并且按列(或一组列)迭代可能会更快.一般来说,稀疏矩阵索引涉及提取矩阵和矩阵乘法,尽管 csc (.getcol) 或切片的列索引可能会有一些增强。

熵 H(X) = - sum(p(X) * log(p(X)))

logP = np.ma.log(P).filled(0)
entropy_list = -np.sum(np.multiply(P, logP), axis=0)

注意:在列总和不为 1 的情况下,scipy.stats.entropy 对其进行归一化。

编辑:scipy.sparse.csr_matrix

log_result = np.log(P.data)
logP = P._with_data(log_result, copy=True)
mult_P = P.multiply(logP)
entropy_list = -(mult_P.sum(axis=0))