|
498 | 498 |
|
499 | 499 | ## -- Moving average, ignoring NaNs |
500 | 500 |
|
| 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 | + |
501 | 512 | """ |
502 | 513 | ```julia |
503 | 514 | movmean(x::AbstractVecOrMat, n::Number) |
|
509 | 520 | if `n` is not an odd integer, the first odd integer greater than `n` will be |
510 | 521 | used instead. |
511 | 522 | """ |
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 |
515 | 532 | δ = ceil(Int, (n-1)/2) |
516 | 533 | @inbounds for i ∈ eachindex(x) |
517 | 534 | iₗ = max(i-δ, firstindex(x)) |
518 | 535 | iᵤ = min(i+δ, lastindex(x)) |
519 | | - m[i] = nanmean(view(x, iₗ:iᵤ)) |
| 536 | + out[i] = nanmean(view(x, iₗ:iᵤ)) |
520 | 537 | end |
521 | | - return m |
| 538 | + return out |
522 | 539 | end |
523 | 540 |
|
524 | | - |
525 | 541 | """ |
526 | 542 | movmean(x::AbstractVector{T}, win::Tuple{Int, Int}=(1, 1); skip_centre=false) where {T<:Real} |
527 | 543 | |
|
542 | 558 | movmean(x, win) # returns [1.5, 2.0, 3.0, 4.0, 4.5] |
543 | 559 | ``` |
544 | 560 | """ |
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); |
546 | 564 | skip_centre=false) where {T<:Real} |
547 | 565 | win_left, win_right = win |
548 | 566 |
|
549 | | - FT = Base.promote_op(/, T, Int64) |
550 | | - z = similar(x, FT) |
551 | | - ∑ = ∅ = FT(0) |
| 567 | + ∑ = ∅ = zero(eltype(out)) |
552 | 568 | ∑w = ∅w = 0 |
553 | 569 |
|
554 | 570 | @inbounds @simd for i ∈ eachindex(x) |
|
563 | 579 | ∑ += ifelse(notnan, xᵢ, ∅) |
564 | 580 | ∑w += ifelse(notnan, 1, 0) |
565 | 581 | end |
566 | | - z[i] = ∑ / ∑w |
| 582 | + out[i] = ∑ / ∑w |
567 | 583 | end |
568 | | - z |
| 584 | + return out |
569 | 585 | end |
570 | 586 |
|
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 |
574 | 590 | δ = ceil(Int, (n-1)/2) |
575 | 591 | 𝐼 = repeat((firstindex(x,1):lastindex(x,1)), 1, size(x,2)) |
576 | 592 | 𝐽 = repeat((firstindex(x,2):lastindex(x,2))', size(x,1), 1) |
|
581 | 597 | j = 𝐽[k] |
582 | 598 | jₗ = max(j-δ, firstindex(x,2)) |
583 | 599 | 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ᵤ)) |
585 | 601 | end |
586 | | - return m |
| 602 | + return out |
587 | 603 | end |
588 | | - export movmean |
| 604 | + export movmean, movmean! |
589 | 605 |
|
590 | 606 | ## --- Internal helpers |
591 | 607 |
|
|
0 commit comments