Skip to content

Commit b80745e

Browse files
Copilotviallww
andcommitted
Fix workflow permissions and cleanup import aliases
Co-authored-by: viallww <94695104+viallww@users.noreply.github.com>
1 parent 297157a commit b80745e

3 files changed

Lines changed: 34 additions & 19 deletions

File tree

.github/workflows/CI.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ jobs:
1717
name: Julia ${{ matrix.julia-version }} – ${{ matrix.os }}
1818
runs-on: ${{ matrix.os }}
1919
timeout-minutes: 60
20+
permissions:
21+
contents: read
2022
strategy:
2123
fail-fast: false
2224
matrix:

src/outliers.jl

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module Outliers
22

33
using Statistics
4-
using StatsBase: zscore, mad, winsor, quantile as sb_quantile
4+
using StatsBase: zscore, mad, winsor
55

66
export detect_outliers, remove_outliers, winsorize
77

@@ -96,12 +96,10 @@ end
9696
"""
9797
winsorize(data; limits=(0.05, 0.95)) -> Vector
9898
99-
Clip extreme values so that `limits[1]` fraction of the lowest and
100-
`1 - limits[2]` fraction of the highest observations are replaced by the
101-
boundary quantile values.
102-
103-
Delegates to `StatsBase.winsor` for symmetric limits and falls back to
104-
quantile-clamping for asymmetric limits.
99+
Clip extreme values so that observations below the `limits[1]` quantile are
100+
raised to that boundary, and observations above `limits[2]` are lowered to it.
101+
This delegates to `StatsBase.winsor` for symmetric limits and uses
102+
quantile-clamping directly for asymmetric limits.
105103
"""
106104
function winsorize(
107105
data::AbstractVector{T};

src/upsample.jl

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ function upsample_linear(
6565
end
6666

6767
# ---------------------------------------------------------------------------
68-
# Nearest-neighbour upsampling
69-
# (Interpolations.jl Gridded(Constant()) for non-uniform knots)
68+
# Nearest-neighbour upsampling (pure Julia – avoids Interpolations.jl API
69+
# version uncertainty for Gridded(Constant) boundary modes)
7070
# ---------------------------------------------------------------------------
7171

7272
"""
@@ -81,7 +81,7 @@ function upsample_nearest(
8181
)::Vector{T} where {T<:Real}
8282
x = collect(1.0:Float64(length(y)))
8383
_, y_new = upsample_nearest(x, y, factor; plot = plot)
84-
return y_new
84+
return collect(T, y_new)
8585
end
8686

8787
function upsample_nearest(
@@ -96,10 +96,8 @@ function upsample_nearest(
9696
n >= 2 || throw(ArgumentError("Need at least 2 points"))
9797

9898
xf = float.(x)
99-
itp = interpolate((xf,), float.(y), Gridded(Constant{Nearest}()))
100-
etp = extrapolate(itp, Flat())
10199
x_new = range(xf[1], xf[end]; length = (n - 1) * factor + 1)
102-
y_new = etp.(x_new)
100+
y_new = _nearest(xf, float.(y), x_new)
103101

104102
if plot; _show_upsample_plot(x, y, x_new, y_new, "Nearest") end
105103
return collect(float(Tx), x_new), y_new
@@ -113,18 +111,35 @@ function upsample_nearest(
113111
) where {Tx<:Real,Ty<:Real}
114112
length(x) == length(y) || throw(DimensionMismatch("x and y must have same length"))
115113

116-
xf = float.(x)
117-
itp = interpolate((xf,), float.(y), Gridded(Constant{Nearest}()))
118-
etp = extrapolate(itp, Flat())
119-
y_new = etp.(x_new)
120-
114+
y_new = _nearest(float.(x), float.(y), x_new)
121115
if plot; _show_upsample_plot(x, y, x_new, y_new, "Nearest") end
122116
return collect(float(Tx), x_new), y_new
123117
end
124118

125119
# ---------------------------------------------------------------------------
126-
# Internal plot helper
120+
# Internal helpers
127121
# ---------------------------------------------------------------------------
122+
123+
function _nearest(
124+
x::AbstractVector{F},
125+
y::AbstractVector{F},
126+
x_new,
127+
)::Vector{F} where {F<:AbstractFloat}
128+
n = length(x)
129+
result = Vector{F}(undef, length(x_new))
130+
for (k, xk) in enumerate(x_new)
131+
if xk <= x[1]; result[k] = y[1]; continue end
132+
if xk >= x[n]; result[k] = y[n]; continue end
133+
lo, hi = 1, n
134+
while hi - lo > 1
135+
mid = (lo + hi) >>> 1
136+
x[mid] <= xk ? lo = mid : hi = mid
137+
end
138+
result[k] = abs(xk - x[lo]) <= abs(xk - x[hi]) ? y[lo] : y[hi]
139+
end
140+
return result
141+
end
142+
128143
function _show_upsample_plot(x_orig, y_orig, x_new, y_new, method_name::String)
129144
buff_mod = Base.moduleroot(parentmodule(Upsample))
130145
plots_mod = getfield(buff_mod, :Plots)

0 commit comments

Comments
 (0)