Skip to content

Commit 005c0c5

Browse files
committed
Implement movmean!() and allocate_movmean()
1 parent cc787d7 commit 005c0c5

File tree

4 files changed

+42
-19
lines changed

4 files changed

+42
-19
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ julia> @btime nanbinmean($x,$y,xmin,xmax,nbins)
129129
90.30275863080671
130130
```
131131
### Other functions
132-
* `movmean`
132+
* `movmean` / `movmean!`
133133
A simple moving average function, which can operate in 1D or 2D, ignoring NaNs.
134134
```
135135
julia> A = rand(1:10, 4,4)
@@ -157,6 +157,7 @@ argument.
157157

158158
* `allocate_nanmean`
159159
* `allocate_nansum`
160+
* `allocate_movmean`
160161

161162
### DimensionalData support
162163
Almost all functions support

src/ArrayStats/ArrayStats.jl

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,17 @@
498498

499499
## -- Moving average, ignoring NaNs
500500

501+
"""
502+
allocate_movmean(x::AbstractVecOrMat)
503+
504+
Allocate an array of the right type and shape to pass as the output parameter to
505+
`movmean!()` for the given `x`.
506+
"""
507+
function allocate_movmean(x::AbstractVecOrMat{T}) where T
508+
mean_type = Base.promote_op(/, T, Int64)
509+
similar(x, mean_type)
510+
end
511+
501512
"""
502513
```julia
503514
movmean(x::AbstractVecOrMat, n::Number)
@@ -509,19 +520,24 @@
509520
if `n` is not an odd integer, the first odd integer greater than `n` will be
510521
used instead.
511522
"""
512-
function movmean(x::AbstractVector{T}, n::Number) where T
513-
mean_type = Base.promote_op(/, T, Int64)
514-
m = Array{mean_type}(undef, size(x))
523+
movmean(x::AbstractVector, n::Number) = movmean!(allocate_movmean(x), x, n)
524+
525+
"""
526+
movmean!(out, x, win_or_n::Union{Number, Tuple})
527+
528+
Non-allocating version of `movmean()`. Generate the `out` parameter with
529+
`allocate_movmean(x)`.
530+
"""
531+
function movmean!(out::AbstractVector, x::AbstractVector{T}, n::Number) where T
515532
δ = ceil(Int, (n-1)/2)
516533
@inbounds for i eachindex(x)
517534
iₗ = max(i-δ, firstindex(x))
518535
iᵤ = min(i+δ, lastindex(x))
519-
m[i] = nanmean(view(x, iₗ:iᵤ))
536+
out[i] = nanmean(view(x, iₗ:iᵤ))
520537
end
521-
return m
538+
return out
522539
end
523540

524-
525541
"""
526542
movmean(x::AbstractVector{T}, win::Tuple{Int, Int}=(1, 1); skip_centre=false) where {T<:Real}
527543
@@ -542,13 +558,13 @@
542558
movmean(x, win) # returns [1.5, 2.0, 3.0, 4.0, 4.5]
543559
```
544560
"""
545-
function movmean(x::AbstractVector{T}, win::Tuple{Int, Int}=(1, 1);
561+
movmean(x::AbstractVector, win::Tuple{Int, Int}=(1, 1); skip_centre=false) = movmean!(allocate_movmean(x), x, win; skip_centre)
562+
563+
function movmean!(out::AbstractVector, x::AbstractVector{T}, win::Tuple{Int, Int}=(1, 1);
546564
skip_centre=false) where {T<:Real}
547565
win_left, win_right = win
548566

549-
FT = Base.promote_op(/, T, Int64)
550-
z = similar(x, FT)
551-
== FT(0)
567+
== zero(eltype(out))
552568
∑w = ∅w = 0
553569

554570
@inbounds @simd for i eachindex(x)
@@ -563,14 +579,14 @@
563579
+= ifelse(notnan, xᵢ, ∅)
564580
∑w += ifelse(notnan, 1, 0)
565581
end
566-
z[i] =/ ∑w
582+
out[i] =/ ∑w
567583
end
568-
z
584+
return out
569585
end
570586

571-
function movmean(x::AbstractMatrix{T}, n::Number) where T
572-
mean_type = Base.promote_op(/, T, Int64)
573-
m = Array{mean_type}(undef, size(x))
587+
movmean(x::AbstractMatrix, n::Number) = movmean!(allocate_movmean(x), x, n)
588+
589+
function movmean!(out::AbstractMatrix, x::AbstractMatrix{T}, n::Number) where T
574590
δ = ceil(Int, (n-1)/2)
575591
𝐼 = repeat((firstindex(x,1):lastindex(x,1)), 1, size(x,2))
576592
𝐽 = repeat((firstindex(x,2):lastindex(x,2))', size(x,1), 1)
@@ -581,11 +597,11 @@
581597
j = 𝐽[k]
582598
jₗ = max(j-δ, firstindex(x,2))
583599
jᵤ = min(j+δ, lastindex(x,2))
584-
m[i,j] = nanmean(view(x, iₗ:iᵤ, jₗ:jᵤ))
600+
out[i,j] = nanmean(view(x, iₗ:iᵤ, jₗ:jᵤ))
585601
end
586-
return m
602+
return out
587603
end
588-
export movmean
604+
export movmean, movmean!
589605

590606
## --- Internal helpers
591607

test/testArrayStats.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,5 +576,6 @@
576576
@test NaNStatistics.allocate_nanmean(rand(Float32, 10, 10), 1) isa Matrix{Float32}
577577
@test NaNStatistics.allocate_nansum(rand(10, 10), 1) isa Matrix{Float64}
578578
@test NaNStatistics.allocate_nansum(rand(Int, 10, 10), 1) isa Matrix{Int}
579+
@test NaNStatistics.allocate_movmean(rand(10)) isa Vector{Float64}
579580

580581
## --- End of File

test/testDimensionalDataExt.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,9 @@ end
9999
@test size(out) == (1, 5)
100100
@test out isa DimMatrix{Float64}
101101
@test lookup(out, Y) == lookup(data, Y)
102+
103+
# Test allocate_movmean() explicitly since it doesn't go through _allocate_reduce()
104+
out = NaNStatistics.allocate_movmean(data)
105+
@test size(out) == size(data)
106+
@test out isa DimMatrix{Float64}
102107
end

0 commit comments

Comments
 (0)