Julia 确定稀疏矩阵中哪些行(或列)具有值

Julia 确定稀疏矩阵中哪些行(或列)具有值,julia,sparse-matrix,Julia,Sparse Matrix,我需要识别在大型稀疏布尔矩阵中定义了值的行(/列)。我想用这个来代替1。按这些行/列对矩阵进行切片(实际上是查看);二,。切片(/查看)与矩阵边距尺寸相同的向量和矩阵。即,结果可能是索引/布尔向量或(最好)迭代器 我试过显而易见的方法: a = sprand(10000, 10000, 0.01) cols = unique(a.colptr) rows = unique(a.rowvals) 但在我的机器上,每一个都需要20毫秒,可能是因为它们分配了大约1MB(至少分配了cols和行)。这是

我需要识别在大型稀疏布尔矩阵中定义了值的行(/列)。我想用这个来代替1。按这些行/列对矩阵进行切片(实际上是查看);二,。切片(/
查看
)与矩阵边距尺寸相同的向量和矩阵。即,结果可能是索引/布尔向量或(最好)迭代器

我试过显而易见的方法:

a = sprand(10000, 10000, 0.01)
cols = unique(a.colptr)
rows = unique(a.rowvals)
但在我的机器上,每一个都需要20毫秒,可能是因为它们分配了大约1MB(至少分配了
cols
)。这是一个性能关键的函数,因此我希望对代码进行优化。基本代码似乎有一个用于稀疏矩阵的
nzrange
迭代器,但我不容易看到如何将其应用到我的案例中

有没有一种建议的方法

第二个问题:我还需要在稀疏矩阵的视图上执行此操作-这是否类似于
x=view(a,:,:);cols=unique(x.parent.colptr[x.index[:,2]])
或者有专门的功能吗?稀疏矩阵的视图看起来很棘手(cf–不是交叉柱)


非常感谢

关于获取稀疏矩阵的非零行和列,以下函数应该非常有效:

nzcols(a::SparseMatrixCSC) = collect(i 
  for i in 1:a.n if a.colptr[i]<a.colptr[i+1])

function nzrows(a::SparseMatrixCSC)
    active = falses(a.m)
    for r in a.rowval
        active[r] = true
    end
    return find(active)
end
更好的解决方案是根据视图定制函数。例如,当视图对行和列同时使用UnitRanges时:

# utility predicate returning true if element of sorted v in range r
inrange(v,r) = searchsortedlast(v,last(r))>=searchsortedfirst(v,first(r))

function nzcols(b::SubArray{T,2,P,Tuple{UnitRange{Int64},UnitRange{Int64}}}
  ) where {T,P<:SparseMatrixCSC}
    return collect(i+1-start(b.indexes[2]) 
      for i in b.indexes[2]
      if b.parent.colptr[i]<b.parent.colptr[i+1] && 
        inrange(b.parent.rowval[nzrange(b.parent,i)],b.indexes[1]))
end

function nzrows(b::SubArray{T,2,P,Tuple{UnitRange{Int64},UnitRange{Int64}}}
  ) where {T,P<:SparseMatrixCSC}
    active = falses(length(b.indexes[1]))
    for c in b.indexes[2]
        for r in nzrange(b.parent,c)
            if b.parent.rowval[r] in b.indexes[1]
                active[b.parent.rowval[r]+1-start(b.indexes[1])] = true
            end
        end
    end
    return find(active)
end
#如果范围r中排序的v的元素为true,则实用程序谓词返回true
inrange(v,r)=searchsortedlast(v,last(r))>=searchsortedfirst(v,first(r))
函数nzcols(b::子数组{T,2,P,元组{UnitRange{Int64},UnitRange{Int64}}

)在哪里{T,P

如果索引不是范围,转换为稀疏矩阵的回退是可行的,但是这里有一些版本的索引是向量。如果索引是混合的,还需要另一组版本。非常重复,但这是Julia的优点,当版本完成时,代码将选择优化的方法在调用者中不费吹灰之力地使用类型

function sortedintersecting(v1, v2)
    i,j = start(v1), start(v2)
    while i <= length(v1) && j <= length(v2)
        if v1[i] == v2[j] return true
        elseif v1[i] > v2[j] j += 1
        else i += 1
        end
    end
    return false
end

function nzcols(b::SubArray{T,2,P,Tuple{Vector{Int64},Vector{Int64}}}
  ) where {T,P<:SparseMatrixCSC}
    brows = sort(unique(b.indexes[1]))
    return [k 
      for (k,i) in enumerate(b.indexes[2])
      if b.parent.colptr[i]<b.parent.colptr[i+1] && 
        sortedintersecting(brows,b.parent.rowval[nzrange(b.parent,i)])]
end

function nzrows(b::SubArray{T,2,P,Tuple{Vector{Int64},Vector{Int64}}}
  ) where {T,P<:SparseMatrixCSC}
    active = falses(length(b.indexes[1]))
    for c in b.indexes[2]
      active[findin(b.indexes[1],b.parent.rowval[nzrange(b.parent,c)])] = true
    end
    return find(active)
end

cols
实现有一个bug,例如
unique(speye(2).colptr)
是一个3元素向量。有关更多信息,请参阅完整答案。谢谢,它们的速度要快得多!我有点惊讶于需要
收集
nzcols
中的生成器来使用它进行索引,从直觉上看这似乎是可能的。我有
b.indexes[2]
(和1)有值
冒号()
在这种情况下,函数将失败,但我应该能够自己解决该问题:-)(可能是通过为
start
inrange
定义包装函数。不需要
collect
,但是对于
nzrows
,生成器不太明显,所以我想让rows和col的返回类型保持相同。另外,更快(但可读性较差)的
nzcols
nzcols(a::sparsematricxcsc)=(res=Vector){Int}();foldl((x,y)->(如果(x和
nzrows
在一行:
nzrows(a::sparsematricxcsc)=查找(setindex!(false(a.m),true,a.rowval))
@MichaelK.Borregaard
nzcols
nzrows
视图是为范围视图设计的。行/列的任意子集需要不同的版本。我将看看是否可以解决此问题。结果是
排序Intersecting
非常有用:)。从注释中复制版本并将其隔开一点。该
处于活动状态[…]
nzrows中的行非常神奇-我有点惊讶它的结果如此简洁。非常感谢!如果我能把这两个都标记为答案就好了!:-)是的!马上就完成了。事实上,它只比UnitRange版本慢9倍,这可能是你能得到的最快的版本。有趣的是,我昨天也做了同样的尝试(我制作了一个与你的findin2完全相同的函数),但由于nzrows调用函数中的一个遗漏错误,我没有注意到它的基准测试非常糟糕。很高兴看到我走上了正确的轨道!
function sortedintersecting(v1, v2)
    i,j = start(v1), start(v2)
    while i <= length(v1) && j <= length(v2)
        if v1[i] == v2[j] return true
        elseif v1[i] > v2[j] j += 1
        else i += 1
        end
    end
    return false
end

function nzcols(b::SubArray{T,2,P,Tuple{Vector{Int64},Vector{Int64}}}
  ) where {T,P<:SparseMatrixCSC}
    brows = sort(unique(b.indexes[1]))
    return [k 
      for (k,i) in enumerate(b.indexes[2])
      if b.parent.colptr[i]<b.parent.colptr[i+1] && 
        sortedintersecting(brows,b.parent.rowval[nzrange(b.parent,i)])]
end

function nzrows(b::SubArray{T,2,P,Tuple{Vector{Int64},Vector{Int64}}}
  ) where {T,P<:SparseMatrixCSC}
    active = falses(length(b.indexes[1]))
    for c in b.indexes[2]
      active[findin(b.indexes[1],b.parent.rowval[nzrange(b.parent,c)])] = true
    end
    return find(active)
end
function findin2(inds,v,w)
    i,j = start(v),start(w)
    res = Vector{Int}()
    while i<=length(v) && j<=length(w)
        if v[i]==w[j]
            push!(res,inds[i])
            i += 1
        elseif (v[i]<w[j]) i += 1
        else j += 1
        end
    end
    return res
end

function nzrows(b::SubArray{T,2,P,Tuple{Vector{Int64},Vector{Int64}}}
  ) where {T,P<:SparseMatrixCSC}
    active = falses(length(b.indexes[1]))
    inds = sortperm(b.indexes[1])
    brows = (b.indexes[1])[inds] 
    for c in b.indexes[2]
      active[findin2(inds,brows,b.parent.rowval[nzrange(b.parent,c)])] = true
    end
    return find(active)
end