Julia 确定稀疏矩阵中哪些行(或列)具有值
我需要识别在大型稀疏布尔矩阵中定义了值的行(/列)。我想用这个来代替1。按这些行/列对矩阵进行切片(实际上是查看);二,。切片(/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和行)。这是
查看
)与矩阵边距尺寸相同的向量和矩阵。即,结果可能是索引/布尔向量或(最好)迭代器
我试过显而易见的方法:
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.Borregaardnzcols
和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