如何在Python中有效地计算巨大的矩阵乘法(tfidf特征)?

fso*_*ety 4 python numpy matrix scipy scikit-learn

我目前想要使用余弦相似度和python中的Tfidf功能来计算所有对文档的相似度.我的基本方法如下:

from sklearn.feature_extraction.text import TfidfVectorizer
#c = [doc1, doc2, ..., docn]
vec = TfidfVectorizer()
X = vec.fit_transform(c)
del vec
Y = X * X.T
Run Code Online (Sandbox Code Playgroud)

工作得很好,但不幸的是,不是我的大数据集.X具有维度,(350363, 2526183)因此输出矩阵Y应该具有(350363, 350363).由于tfidf功能,X非常稀疏,因此很容易适合内存(仅约2GB).然而,在运行一段时间后,乘法会给我一个内存错误(即使内存不满但我想scipy是如此聪明以至于期望内存使用).

我已经尝试过使用dtypes而没有任何成功.我还确保numpy和scipy将他们的BLAS库链接起来 - 虽然这对csr_matrix点功能没有影响,因为它在C中实现.我想可能使用像memmap这样的东西,但我不确定那.

有没有人知道如何最好地接近这个?

lej*_*lot 6

尽管X稀疏,但X * X.T可能不会注意到它在给定的行对中只需要一个非零公共元素.你正在使用NLP任务,所以我很确定在几乎所有文档中都会出现大量的单词(如前所述 - 它不一定是所有对的一个单词,而是一个(可能是不同的)结果你获得了一个元素矩阵,它有大约122,000,000,000个元素,如果你没有200GB的ram,它看起来不可计算.尝试对单词进行更多的积极过滤以强制稀疏(删除许多常用词)350363^2X * X.T

通常,您将无法计算大数据的Gram矩阵,除非您强制执行稀疏性X * X.T,因此大多数向量的对(文档)都具有0"相似性".它可以通过多种方式来实现,最简单的方法是设置一些门槛T下,你把<a,b>作为0和自己计算的点积,并创造所产生的稀疏矩阵当且仅当一个条目<a,b> > T


Kyl*_*ner 5

您可能需要查看random_projectionscikit-learn 中的模块。在约翰逊Lindenstrauss引理说,随机投影矩阵是保证维持成对距离高达一些宽容eta,这是一个超参数,当你计算出所需的随机投影的数量。

长话短说,SparseRandomProjection 这里看到的scikit-learn类是为您执行此操作的转换器。如果在X上运行它,vec.fit_transform您应该会看到功能尺寸的相当大的减少。

的公式sklearn.random_projection.johnson_lindenstrauss_min_dim表明,要保留高达10%的公差,您只需johnson_lindenstrauss_min_dim(350363, .1)10942个特征。这是一个上限,因此您可以花更少的钱就可以逃脱。即使是1%的公差,也只需要johnson_lindenstrauss_min_dim(350363, .01)1028192个功能,这仍然比您现在拥有的功能要少得多。

编辑:尝试简单-如果您的数据是dtype ='float64',请尝试使用'float32'。仅此一项就可以节省大量空间,尤其是在您不需要双精度的情况下。

如果问题是您也不能在内存中存储“最终矩阵”,我建议您在HDF5Store中使用数据(如在使用pytables的熊猫中所见)。该链接具有一些不错的入门代码,您可以迭代地计算点乘积的大块并写入磁盘。我最近在一个45GB数据集的项目中广泛使用了此方法,如果您决定采用这种方法,可以提供更多帮助。