1

我有一个稀疏数组:term_doc

  • 它的大小是 Float64 的 622256x715。它非常稀疏:

    • 在其约 444,913,040 个单元中,通常只有大约 22,215 个是非空的。
    • 在 622256 行中,只有 4,699 行被占用
    • 尽管 715 列中的所有列都已被占用。

我想要执行的运算符可以描述为返回该矩阵的行规范化和列规范化版本。

我写的朴素非稀疏版本是:

function doUnsparseWay()
    gc() #Force Garbage collect before I start (and periodically during). This uses alot of memory
    term_doc

    N = term_doc./sum(term_doc,1)
    println("N done")  

    gc()
    P = term_doc./sum(term_doc,2)    
    println("P done")
    gc()

    N[isnan(N)] = 0.0
    P[isnan(P)] = 0.0

    N,P,term_doc
end

运行这个:

> @time N,P,term_doc= doUnsparseWay()
outputs:
N done
P done
elapsed time: 30.97332475 seconds (14466 MB allocated, 5.15% gc time in 13 pauses with 3 full sweep)

这相当简单。它会咀嚼内存,如果垃圾收集没有在正确的时间发生(因此我手动调用它),它会崩溃。但它相当快


我想让它在稀疏矩阵上工作。为了不破坏我的记忆,因为从逻辑上讲它是一个更快的操作——更少的单元需要操作。

我遵循了这篇文章文档性能页面的建议。

function doSparseWay()
    term_doc::SparseMatrixCSC{Float64,Int64}

    N= spzeros(size(term_doc)...)
    N::SparseMatrixCSC{Float64,Int64}

    for (doc,total_terms::Float64) in enumerate(sum(term_doc,1))
        if total_terms == 0
            continue
        end
        @fastmath @inbounds N[:,doc] = term_doc[:,doc]./total_terms
    end
    println("N done")  

    P = spzeros(size(term_doc)...)'
    P::SparseMatrixCSC{Float64,Int64}

    gfs = sum(term_doc,2)[:]
    gfs::Array{Float64,1} 


    nterms = size(term_doc,1)
    nterms::Int64 
    term_doc = term_doc'

    @inbounds @simd for term in 1:nterms
        @fastmath @inbounds P[:,term] = term_doc[:,term]/gfs[term]
    end
    println("P done")
    P=P'


    N[isnan(N)] = 0.0
    P[isnan(P)] = 0.0

    N,P,term_doc
end

它永远不会完成。它最多输出“N Done”,但从不输出“P Done”。我已经让它运行了几个小时。

  • 我怎样才能优化它,以便它可以在合理的时间内完成?
  • 或者如果这不可能,请解释原因。
4

1 回答 1

1

首先,您正在创建term_doc一个全局变量,这对性能来说是一个大问题。将其作为参数传递,doSparseWay(term_doc::SparseMatrixCSC). (函数开头的类型注释没有任何用处。)

您想使用类似于 walnuss 的答案的方法

function doSparseWay(term_doc::SparseMatrixCSC)
    I, J, V = findnz(term_doc)
    normI = sum(term_doc, 1)
    normJ = sum(term_doc, 2)
    NV = similar(V)
    PV = similar(V)
    for idx = 1:length(V)
        NV[idx] = V[idx]/normI[J[idx]]
        PV[idx] = V[idx]/normJ[I[idx]]
    end
    m, n = size(term_doc)
    sparse(I, J, NV, m, n), sparse(I, J, PV, m, n), term_doc
end

这是一种通用模式:当您想要优化稀疏矩阵的某些内容时,提取,I并在.JVV

于 2015-02-24T11:31:15.907 回答