我会术语和情境(根据条款而─矩阵之间认为R
包之间text2vec
,tm
,quanteda
,svs
,qlcMatrix
和wordspace
会有一个函数来计算PPMI(正逐点互信息)长期(背景)共同发生) - 但显然不是,所以我继续前进,自己写了一个。问题是,糖蜜很慢,可能是因为我对稀疏矩阵不太好 - 而且我的tcms大约是10k * 20k,所以它们确实需要稀疏。如何高效地计算R中稀疏矩阵的PPMI?
据我了解,PMI = log(p(word, context)/(p(word)*p(context)))
,因此我有理由相信:
count(word_context_co-occurrence)/N
PMI = log(------------------------------------- )
count(word)/N * count(context)/N
哪里N
是所有共同出现在共生矩阵的总和。而PPMI简直是强迫所有< 0值是0(?这是迄今为止正确,右)
考虑到这一点,这里是在执行的尝试:
library(Matrix)
set.seed(1)
pmat = matrix(sample(c(0,0,0,0,0,0,1,10),5*10,T), 5,10, byrow=T) # tiny example matrix;
# rows are words, columns are contexts (words the row-words co-occur with, in a certain window in the text)
pmat = Matrix(pmat, sparse=T) # make it sparse
# calculate some things beforehand to make it faster
N = sum(pmat)
contextp = Matrix::colSums(pmat)/N # probabilities of contexts
wordp = Matrix::rowSums(pmat)/N # probabilities of terms
# here goes nothing...
pmat2 = pmat
for(r in 1:nrow(pmat)){ # go term by term, calculate PPMI association with each of its contexts
not0 = which(pmat[r, ] > 0) # no need to consider 0 values (no co-occurrence)
tmp = log((pmat[r,not0]/N)/(wordp[r] * contextp[not0])) # PMI
tmp = ifelse(tmp < 0, 0, tmp) # PPMI
pmat2[r, not0] = tmp # <-- THIS here is the slow part, replacing the old frequency values with the new PPMI weighted ones.
}
# take a look:
round(pmat2,2)
出现什么是慢不是计算本身,而是将新计算的值放入稀疏矩阵中(在这个微小的例子中,它并不坏,但是如果你使它成千上万行成千上万的行,即使这个循环的一次迭代也将永远存在;构造一个新的与rBind
矩阵似乎是一个坏主意)。
什么是更有效的方法来替换这种稀疏矩阵中的旧值与新的PPMI加权值?无论是建议更改此代码,还是使用某些包中的某些现有功能,我总是错过了 - 都很好。
看看dev版本的text2vec。这里是我如何计算短语(搭配)提取的PMI - https://github.com/dselivanov/text2vec/blob/master/R/collocations.R#L57-L76。 关于你的问题 - 通常尽量避免在稀疏矩阵中逐元素访问,它效率非常低。 –