Skip to content

Commit 7128ef7

Browse files
committed
reduce allocations in lts
1 parent f332613 commit 7128ef7

1 file changed

Lines changed: 67 additions & 19 deletions

File tree

src/lts.jl

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ export iterateCSteps
66
import ..Basis: RegressionSetting, @extractRegressionSetting, designMatrix, responseVector
77
import ..OrdinaryLeastSquares: residuals, coef, olsf!, olsf
88

9-
import Distributions: sample!, mean
9+
import Distributions: sample!
10+
import LinearAlgebra: mul!
1011

1112
"""
1213
@@ -42,29 +43,45 @@ end
4243
function iterateCSteps(
4344
X::AbstractMatrix{Float64},
4445
y::AbstractVector{Float64},
45-
subsetindices::Array{Int,1},
46+
subsetindices::AbstractVector{Int},
4647
h::Int; eps::Float64 = 0.01, maxiter::Int = 10000
4748
)
48-
n = length(y)
49+
n, p = size(X)
4950
oldobjective::Float64 = Inf64
5051
objective::Float64 = Inf64
5152
iter::Int = 0
5253
sortedresindices = Array{Int}(undef, n)
53-
tempbetas = zeros(size(X, 2))
54-
absres = zeros(n)
54+
tempbetas = Vector{Float64}(undef, p)
55+
fitted = Vector{Float64}(undef, n)
56+
absres = Vector{Float64}(undef, n)
57+
workingsubset = copy(subsetindices)
58+
if h > length(workingsubset)
59+
resize!(workingsubset, h)
60+
end
61+
workingsubsetlen = length(subsetindices)
5562
while iter < maxiter
56-
olsf!(view(X, subsetindices, :), view(y, subsetindices), tempbetas)
57-
absres .= abs.(y - X * tempbetas)
63+
activeindices = view(workingsubset, 1:workingsubsetlen)
64+
olsf!(view(X, activeindices, :), view(y, activeindices), tempbetas)
65+
mul!(fitted, X, tempbetas)
66+
@inbounds for i in eachindex(y)
67+
absres[i] = abs(y[i] - fitted[i])
68+
end
5869
sortperm!(sortedresindices, absres)
59-
subsetindices = view(sortedresindices, 1:h)
60-
objective = sum(view(sort!(absres .^ 2.0), 1:h))
70+
objective = 0.0
71+
@inbounds for i = 1:h
72+
idx = sortedresindices[i]
73+
workingsubset[i] = idx
74+
objective += abs2(absres[idx])
75+
end
76+
workingsubsetlen = h
6177
if abs(oldobjective - objective) < eps
6278
break
6379
end
6480
oldobjective = objective
6581
iter += 1
6682
end
67-
return (objective, subsetindices)
83+
resize!(workingsubset, workingsubsetlen)
84+
return (objective, workingsubset)
6885
end
6986

7087

@@ -83,9 +100,15 @@ function iterateCSteps(
83100
h::Int; eps::Float64 = 0.01, maxiter::Int = 10000
84101
)
85102
p = size(X, 2)
86-
res = y - X * initialBetas
87-
sortedresindices = sortperm(abs.(res))
88-
subsetindices = sortedresindices[1:p]
103+
res = Vector{Float64}(undef, length(y))
104+
mul!(res, X, initialBetas)
105+
@inbounds for i in eachindex(y)
106+
res[i] = abs(y[i] - res[i])
107+
end
108+
sortedresindices = Array{Int}(undef, length(y))
109+
sortperm!(sortedresindices, res)
110+
subsetindices = Vector{Int}(undef, p)
111+
copyto!(subsetindices, 1, sortedresindices, 1, p)
89112
return iterateCSteps(X, y, subsetindices, h, eps = eps, maxiter = maxiter)
90113
end
91114

@@ -149,7 +172,7 @@ function lts(X::AbstractMatrix{Float64}, y::AbstractVector{Float64}; iters=nothi
149172
h = Int(floor((n + p + 1.0) / 2.0))
150173

151174
if isnothing(iters)
152-
iters = minimum([5 * p, 3000])
175+
iters = min(5 * p, 3000)
153176
end
154177

155178
allindices = collect(1:n)
@@ -175,11 +198,36 @@ function lts(X::AbstractMatrix{Float64}, y::AbstractVector{Float64}; iters=nothi
175198
end
176199

177200
ltsbetas = olsf(view(X, besthsubset, :), view(y, besthsubset))
178-
ltsres = y - X * ltsbetas
179-
ltsS = sqrt(sum((ltsres .^ 2.0)[1:h]) / (h - p))
180-
ltsresmean = mean(ltsres[besthsubset])
181-
ltsScaledRes = (ltsres .- ltsresmean) / ltsS
182-
outlierindices = filter(i -> abs(ltsScaledRes[i]) > crit, 1:n)
201+
ltsres = Vector{Float64}(undef, n)
202+
mul!(ltsres, X, ltsbetas)
203+
@inbounds for i in eachindex(y)
204+
ltsres[i] = y[i] - ltsres[i]
205+
end
206+
207+
ltsSsum = 0.0
208+
@inbounds for i = 1:h
209+
ltsSsum += abs2(ltsres[i])
210+
end
211+
ltsS = sqrt(ltsSsum / (h - p))
212+
213+
ltsresmean = 0.0
214+
@inbounds for idx in besthsubset
215+
ltsresmean += ltsres[idx]
216+
end
217+
ltsresmean /= h
218+
219+
ltsScaledRes = Vector{Float64}(undef, n)
220+
@inbounds for i in eachindex(ltsres)
221+
ltsScaledRes[i] = (ltsres[i] - ltsresmean) / ltsS
222+
end
223+
224+
outlierindices = Int[]
225+
sizehint!(outlierindices, n)
226+
@inbounds for i = 1:n
227+
if abs(ltsScaledRes[i]) > crit
228+
push!(outlierindices, i)
229+
end
230+
end
183231

184232
result = Dict(
185233
"objective" => bestobjective,

0 commit comments

Comments
 (0)