Skip to content

Commit

Permalink
Improve documentation of Results types (#50)
Browse files Browse the repository at this point in the history
* rename WindowResults to IndocatorChangesResults

* Document the API function for esults

* correct location for defininition of segmented

* finish erverything

* corrct name SegmentedWindowResults
  • Loading branch information
Datseris authored Oct 14, 2023
1 parent 62f14cd commit 72e5cbc
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 93 deletions.
4 changes: 2 additions & 2 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ IndicatorsChangesConfig
SlidingWindowConfig
SegmentedWindowConfig
estimate_indicator_changes
WindowResults
IndicatorsChangesResults
SlidingWindowResults
SegmentWindowResults
SegmentedWindowResults
```

## Significance testing
Expand Down
4 changes: 2 additions & 2 deletions src/TransitionsInTimeseries.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ export difference_of_means

# analysis
export IndicatorsChangesConfig, SlidingWindowConfig, SegmentedWindowConfig
export SlidingWindowResults, SegmentWindowResults
export estimate_indicator_changes, WindowResults
export SlidingWindowResults, SegmentedWindowResults
export estimate_indicator_changes, IndicatorsChangesResults
export TransitionsSignificance, significant_transitions, segmented_significance
export QuantileSignificance, SigmaSignificance, SurrogatesSignificance

Expand Down
16 changes: 13 additions & 3 deletions src/analysis/api.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,25 @@ Supertype used to define how indicators and their changes are estimated in
abstract type IndicatorsChangesConfig end

"""
estimate_indicator_changes(config::IndicatorsChangesConfig, x [,t]) → output
estimate_indicator_changes(config::IndicatorsChangesConfig, x [,t]) → result
Estimate possible transitions for input timeseries `x` using the approach specified
in the configuration type `config`, see [`IndicatorsChangesConfig`](@ref) for possibilities.
`t` is the time vector corresponding to `x`, which defaults to `eachindex(x)`.
Return the output as [`WindowResults`](@ref) which can be given to
Return the output as subtype of [`IndicatorsChangesResults`](@ref).
The particular form of the output depends on the `config` and is described in its docstring.
Regardless of type, `result` can always be given to
[`significant_transitions`](@ref) to deduce which possible transitions are statistically
significant using a variety of significance tests.
"""
function estimate_indicator_changes end
# The function is extended via multiple dispatch in the specific files
# The function is extended via multiple dispatch in the specific files

"""
IndicatorsChangesResults
Supertype used to gather results of [`estimate_indicator_changes`](@ref).
The concrete subtype instances are described in the docstrings of configuration types.
"""
abstract type IndicatorsChangesResults end
70 changes: 65 additions & 5 deletions src/analysis/segmented_window.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ window segments as follows:
(the window segments may overlap, that's okay).
`indicators, change_metrics` are identical as in [`SlidingWindowConfig`](@ref).
The results output corresponding to `SlidingWindowConfig` is [`SegmentedWindowResults`](@ref).
## Keyword arguments
-
- `width_ind::Int=100, stride_ind::Int=1, whichtime = midpoint, T = Float64`: keywords
identical as in [`SlidingWindowConfig`](@ref).
- `min_width_cha::Int=50`: minimal width required to perform the change metric estimation.
If segment not sufficiently long, return `NaN`.
- `min_width_cha::Int=typemax(Int)`: minimal width required to perform the change metric estimation.
If a segment is not sufficiently long, the change metric is `NaN`.
"""
struct SegmentedWindowConfig{F, G, W<:Function} <: IndicatorsChangesConfig
indicators::F
Expand All @@ -37,7 +38,7 @@ function SegmentedWindowConfig(
indicators, change_metrics, tseg_start, tseg_end;
width_ind = 100,
stride_ind = 1,
min_width_cha = 50,
min_width_cha = typemax(Int),
whichtime = midpoint,
T = Float64,
)
Expand Down Expand Up @@ -94,10 +95,69 @@ function estimate_indicator_changes(config::SegmentedWindowConfig, x, t)
end
end
# put everything together in the output type
return SegmentWindowResults(t, x, t_indicator, x_indicator, t_change, x_change, config)
return SegmentedWindowResults(t, x, t_indicator, x_indicator, t_change, x_change, config)
end

function segment(t, x, t1, t2)
i1, i2 = argmin(abs.(t .- t1)), argmin(abs.(t .- t2))
return t[i1:i2], x[i1:i2]
end


"""
SegmentedWindowResults <: IndicatorsChangesResults
A struct containing the output of [`estimate_indicator_changes`](@ref) used with
[`SegmentedWindowConfig`](@ref). It can be used for further analysis, visualization,
or given to [`significant_transitions`](@ref).
It has the following fields that the user may access
- `x`: the input timeseries.
- `t`: the time vector of the input timeseries.
- `x_indicator::Vector{Matrix}`, with `x_indicator[k]` the indicator timeseries (matrix
with each column one indicator) of the `k`-th segment.
- `t_indicator::Vector{Vector}`, with `t_indicator[k]` the time vector of the indicator
timeseries for the `k`-th segment.
- `x_change::Matrix`, the change metric values with `x[k, i]` the change metric of the
`i`-th indicator for the `k`-th segment.
- `t_change`, the time vector of the change metric.
- `config::SegmentedWindowConfig`, what was used for the analysis.
"""
struct SegmentedWindowResults{TT, T<:Real, X<:Real, XX<:AbstractVector{X},
W} <: IndicatorsChangesResults
t::TT # original time vector; most often it is `Base.OneTo`.
x::XX
t_indicator::Vector{Vector{T}}
x_indicator::Vector{Matrix{X}}
t_change::Vector{T}
x_change::Matrix{X}
config::W
end

# Segmented and Sliding results share their show method
function Base.show(io::IO, ::MIME"text/plain", res::Union{SegmentedWindowResults, SlidingWindowResults})
println(io, "IndicatorsChangesResults")
descriptors = [
"input timeseries" => summary(res.x),
"indicators" => [nameof(i) for i in res.config.indicators],
"indicator (window, stride)" => (res.config.width_ind, res.config.stride_ind),
"change metrics" => [nameof(c) for c in res.config.change_metrics],
show_changemetric(res),
]
padlen = maximum(length(d[1]) for d in descriptors) + 2
for (desc, val) in descriptors
println(io, rpad(" $(desc): ", padlen), val)
end
end

function show_changemetric(res::SlidingWindowResults)
return "change metric (window, stride)" => (res.config.width_cha, res.config.stride_cha)
end

function show_changemetric(res::SegmentedWindowResults)
return "change metric (window)" => ([length(t) for t in res.t_indicator])
end
76 changes: 5 additions & 71 deletions src/analysis/sliding_window.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ Both indicators and change metrics are **generic Julia functions** that input an
see [making custom indicators/change metrics](@ref own_indicator) in the documentation
for more information on possible optimizations.
The results output corresponding to `SlidingWindowConfig` is [`SlidingWindowResults`](@ref).
## Keyword arguments
- `width_ind::Int=100, stride_ind::Int=1`: width and stride given to [`WindowViewer`](@ref)
Expand Down Expand Up @@ -122,18 +124,7 @@ function estimate_indicator_changes(config::SlidingWindowConfig, x, t = eachinde
end

"""
WindowResults
Supertype used to gather results of [`estimate_indicator_changes`](@ref).
Valid subtypes are:
- [`SlidingWindowResults`](@ref).
- [`SegmentWindowResults`](@ref).
"""
abstract type WindowResults end

"""
SlidingWindowResults
SlidingWindowResults <: IndicatorsChangesResults
A struct containing the output of [`estimate_indicator_changes`](@ref) used with
[`SlidingWindowConfig`](@ref). It can be used for further analysis, visualization,
Expand All @@ -150,10 +141,10 @@ It has the following fields that the user may access
- `x_change`, the change metric timeseries (matrix with each column one change metric).
- `t_change`, the time vector of the change metric timeseries.
- [`config::SlidingWindowConfig`](@ref), used for the analysis.
- `config::SlidingWindowConfig`, what was used for the analysis.
"""
struct SlidingWindowResults{TT, T<:Real, X<:Real, XX<:AbstractVector{X},
W} <: WindowResults
W} <: IndicatorsChangesResults
t::TT # original time vector; most often it is `Base.OneTo`.
x::XX
t_indicator::Vector{T}
Expand All @@ -162,60 +153,3 @@ struct SlidingWindowResults{TT, T<:Real, X<:Real, XX<:AbstractVector{X},
x_change::Matrix{X}
config::W
end

"""
SegmentWindowResults
A struct containing the output of [`estimate_indicator_changes`](@ref) used with
[`SegmentedWindowConfig`](@ref). It can be used for further analysis, visualization,
or given to [`significant_transitions`](@ref).
It has the following fields that the user may access
- `x`: the input timeseries.
- `t`: the time vector of the input timeseries.
- `x_indicator::Vector{Matrix}`, with `x_indicator[k]` the indicator timeseries (matrix
with each column one indicator) of the `k`-th segment.
- `t_indicator::Vector{Vector}`, with `t_indicator[k]` the time vector of the indicator
timeseries for the `k`-th segment.
- `x_change::Matrix`, the change metric values with `x[k, i]` the change metric of the
`i`-th indicator for the `k`-th segment.
- `t_change`, the time vector of the change metric.
- [`config::SegmentedWindowConfig`](@ref), used for the analysis.
"""
struct SegmentWindowResults{TT, T<:Real, X<:Real, XX<:AbstractVector{X},
W} <: WindowResults
t::TT # original time vector; most often it is `Base.OneTo`.
x::XX
t_indicator::Vector{Vector{T}}
x_indicator::Vector{Matrix{X}}
t_change::Vector{T}
x_change::Matrix{X}
config::W
end

function Base.show(io::IO, ::MIME"text/plain", res::WindowResults)
println(io, "WindowResults")
descriptors = [
"input timeseries" => summary(res.x),
"indicators" => [nameof(i) for i in res.config.indicators],
"indicator (window, stride)" => (res.config.width_ind, res.config.stride_ind),
"change metrics" => [nameof(c) for c in res.config.change_metrics],
show_changemetric(res),
]
padlen = maximum(length(d[1]) for d in descriptors) + 2
for (desc, val) in descriptors
println(io, rpad(" $(desc): ", padlen), val)
end
end

function show_changemetric(res::SlidingWindowResults)
return "change metric (window, stride)" => (res.config.width_cha, res.config.stride_cha)
end

function show_changemetric(res::SegmentWindowResults)
return "change metric (window)" => ([length(t) for t in res.t_indicator])
end
4 changes: 2 additions & 2 deletions src/significance/api_significance.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ abstract type TransitionsSignificance end


"""
significant_transitions(res::WindowResults, signif::TransitionsSignificance)
significant_transitions(res::IndicatorsChangesResults, signif::TransitionsSignificance)
Estimate significant transtions in `res` using the method described by `signif`.
Return `flags`, a Boolean matrix with identical size as `res.x_change`.
It contains trues wherever a change metric of `res` is deemed significant.
"""
function significant_transitions(::WindowResults, ::TransitionsSignificance) end
function significant_transitions(::IndicatorsChangesResults, ::TransitionsSignificance) end
8 changes: 4 additions & 4 deletions src/significance/quantile_significance.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
QuantileSignificance(; p = 0.95, tail = :both) <: TransitionsSignificance
A configuration struct for significance testing [`significant_transitions`](@ref).
When used with [`WindowResults`](@ref), significance is estimated
When used with [`IndicatorsChangesResults`](@ref), significance is estimated
by comparing the value of each change metric with its `p`-quantile.
Values that exceed the `p`-quantile (if `tail = :right`)
or subseed the `1-p`-quantile (if `tail = :left`)
Expand All @@ -20,7 +20,7 @@ end

using Statistics: quantile

function significant_transitions(res::WindowResults, signif::QuantileSignificance)
function significant_transitions(res::IndicatorsChangesResults, signif::QuantileSignificance)
flags = similar(res.x_change, Bool)
for (i, x) in enumerate(eachcol(res.x_change))
qmin, qmax = quantile(x, (1 - signif.p, signif.p))
Expand All @@ -42,7 +42,7 @@ end
SigmaSignificance(; factor = 3.0, tail = :both) <: TransitionsSignificance
A configuration struct for significance testing [`significant_transitions`](@ref).
When used with [`WindowResults`](@ref), significance is estimated
When used with [`IndicatorsChangesResults`](@ref), significance is estimated
by comparing how many standard deviations (`σ`) the value exceeds the mean value (`μ`).
Values that exceed (if `tail = :right`) `μ + factor*σ`, or subseed (if `tail = :left`) `μ - factor*σ`
are deemed significant.
Expand All @@ -60,7 +60,7 @@ end

using Statistics: std, mean

function significant_transitions(res::WindowResults, signif::SigmaSignificance)
function significant_transitions(res::IndicatorsChangesResults, signif::SigmaSignificance)
flags = similar(res.x_change, Bool)
for (i, x) in enumerate(eachcol(res.x_change))
μ = mean(x)
Expand Down
8 changes: 4 additions & 4 deletions src/significance/surrogates_significance.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ using timeseries surrogates.
## Description
When used with [`WindowResults`](@ref), significance is estimated as follows:
When used with [`IndicatorsChangesResults`](@ref), significance is estimated as follows:
`n` surrogates from the input timeseries are generated using `surromethod`, which is
any `Surrogate` subtype provided by
[TimeseriesSurrogates.jl](https://juliadynamics.github.io/TimeseriesSurrogates.jl/dev/api/).
Expand All @@ -34,7 +34,7 @@ higher change metric, discriminatory statistic values. This is the case for stat
that quantify entropy. For statistics that quantify autocorrelation, use `tail = :right`
instead. For anything else, use the default `tail = :both`.
An iterable of `tail` values can also be given, in which case a specific `tail`
is used for each change metric in [`WindowResults`](@ref).
is used for each change metric in [`IndicatorsChangesResults`](@ref).
Note that the raw p-values can be accessed in the field `.pvalues`, after calling the
[`significant_transitions`](@ref) function with `SurrogatesSignificance`, in case you wish
Expand Down Expand Up @@ -90,7 +90,7 @@ function significant_transitions(res::SlidingWindowResults, signif::SurrogatesSi
return pvalues .< signif.p
end

function significant_transitions(res::SegmentWindowResults, signif::SurrogatesSignificance)
function significant_transitions(res::SegmentedWindowResults, signif::SurrogatesSignificance)
# Unpack and sanity checks
X = eltype(res.x_change)
(; indicators, change_metrics, tseg_start, tseg_end) = res.config
Expand Down Expand Up @@ -182,7 +182,7 @@ function segmented_surrogates_loop!(
pval_right = zeros(length(pval))
pval_left = copy(pval_right)
end

# parallelized surrogate loop
Threads.@threads for _ in 1:n_surrogates
id = Threads.threadid()
Expand Down

0 comments on commit 72e5cbc

Please sign in to comment.