-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dispersion and reverse dispersion probability estimators #96
Changes from 13 commits
5e95521
16c130d
1f1691f
5816ef8
5bab748
44354ef
394a4e7
3194f82
9900c81
97a4c3a
082a6a5
6ac6983
6b58635
aea3a03
9391e9f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,13 @@ | ||
# Complexity measures | ||
# [Complexity measures](@id complexity_measures) | ||
|
||
## Sample entropy | ||
|
||
## Approximate entropy | ||
|
||
## Reverse dispersion entropy | ||
|
||
```@docs | ||
reverse_dispersion | ||
``` | ||
|
||
## Disequilibrium |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,4 +33,4 @@ entropy_permutation | |
entropy_spatial_permutation | ||
entropy_wavelet | ||
entropy_dispersion | ||
``` | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include("reverse_dispersion_entropy.jl") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
export reverse_dispersion | ||
|
||
function distance_to_whitenoise(p::Probabilities, n_classes, m; normalize = false) | ||
# We can safely skip non-occurring symbols, because they don't contribute | ||
# to the sum in eq. 3 in Li et al. (2019) | ||
Hrde = sum(abs2, p) - 1/(n_classes^m) | ||
|
||
if normalize | ||
# The factor `f` considers *all* possible symbols (also non-occurring) | ||
f = n_classes^m | ||
return Hrde / (1 - (1/f)) | ||
else | ||
return Hrde | ||
end | ||
end | ||
|
||
""" | ||
reverse_dispersion(x::AbstractVector{T}, s = GaussianSymbolization(c = 5), m = 2, τ = 1, | ||
normalize = true) | ||
|
||
|
||
Compute the reverse dispersion entropy complexity measure (Li et al., 2019)[^Li2019]. | ||
|
||
## Algorithm | ||
kahaaga marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Li et al. (2021)[^Li2019] defines the reverse dispersion entropy as | ||
|
||
```math | ||
H_{rde} = \\sum_{i = 1}^{c^m} \\left(p_i - \\dfrac{1}{{c^m}} \\right)^2. | ||
``` | ||
|
||
where the probabilities ``p_i`` are obtained precisely as for the [`Dispersion`](@ref) | ||
probability estimator. Relative frequencies of dispersion patterns are computed using the | ||
symbolization scheme `s`, which defaults to symbolization using the normal cumulative | ||
distribution function (NCDF), as implemented by [`GaussianSymbolization`](@ref), using | ||
embedding dimension `m` and embedding delay `τ`. | ||
Recommended parameter values[^Li2018] are `m ∈ [2, 3]`, `τ = 1` for the embedding, and | ||
`c ∈ [3, 4, …, 8]` categories for the Gaussian mapping. If `normalize == true`, then | ||
the reverse dispersion entropy is normalized to `[0, 1]`. | ||
|
||
The minimum value of ``H_{rde}`` is zero and occurs precisely when the dispersion | ||
pattern distribution is flat, which occurs when all ``p_i``s are equal to ``1/c^m``. | ||
Because ``H_{rde} \\geq 0``, ``H_{rde}`` can therefore be said to be a measure of how far | ||
the dispersion pattern probability distribution is from white noise. | ||
|
||
## Example | ||
|
||
```jldoctest reverse_dispersion_example; setup = :(using Entropies) | ||
julia> x = repeat([0.5, 0.7, 0.1, -1.0, 1.11, 2.22, 4.4, 0.2, 0.2, 0.1], 10); | ||
|
||
julia> c, m = 3, 5; | ||
|
||
julia> reverse_dispersion(x, s = GaussianSymbolization(c = c), m = m, normalize = false) | ||
0.11372331532921814 | ||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure about this. I mean how much does it help really? It just shows the function call, and that it outputs a number, which is anyways understood by the first sentence of the docstring. Unlike Julia base functions, whose ouput can be deduced, and hence these tiny snippets actually make sure the user gets what's going on, here it's not like a user could deduce the More importantly, what are the principles that decide which methods have examples in their docstrings and which do not? Are we perhaps confusing the user? One of the principles of good documentation is that information should be where it is expected to be. So, are we creating the expectation that examples will be found in the docpage "Examples", or at the end of the docstrings? My vote is to stick with one mean of showing examples, and the vote for that is the dedicated examples page. P.s.: The argument of using this as a means of tests is totally unconvincing for me, that's why we write tests in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From the Documenter.jl docs:
One can discuss whether this advice is good or not, given precisely what you said:
There a balance to be struck between 1) the expectation a user has of where examples are found and 2) the ease of use and/or learning curve. I'm fine just having the extended examples in the online documentation pages, but it is also slightly annoying (for me) to have to open the browser and read through potentially many documentation pages to find a simple runnable example. I very much like the sci-py, e.g. approach, where most if not all methods have a simple runnable example AND some of these methods are exposed in more detail elsewhere in the docs. On the opposite end of the spectrum, you have packages like StatsBase.jl which have very few examples, except in some methods (where, funnily, for the example I looked at, they don't even use I do straight-forwardly agree that for functions as simple as |
||
|
||
!!! note | ||
#### A clarification on notation | ||
|
||
With ambiguous notation, Li et al. claim that | ||
|
||
``H_{rde} = \\sum_{i = 1}^{c^m} \\left(p_i - \\dfrac{1}{{c^m}} \\right)^2 = \\sum_{i = 1}^{c^m} p_i^2 - \\frac{1}{c^m}.`` | ||
|
||
But on the right-hand side of the equality, does the constant term appear within or | ||
outside the sum? Using that ``P`` is a probability distribution by | ||
construction (in step 4) , we see that the constant must appear *outside* the sum: | ||
|
||
```math | ||
\\begin{aligned} | ||
H_{rde} &= \\sum_{i = 1}^{c^m} \\left(p_i - \\dfrac{1}{{c^m}} \\right)^2 | ||
= \\sum_{i=1}^{c^m} p_i^2 - \\frac{2p_i}{c^m} + \\frac{1}{c^{2m}} \\\\ | ||
&= \\left( \\sum_{i=1}^{c^m} p_i^2 \\right) - \\left(\\sum_i^{c^m} \\frac{2p_i}{c^m}\\right) + \\left( \\sum_{i=1}^{c^m} \\dfrac{1}{{c^{2m}}} \\right) \\\\ | ||
&= \\left( \\sum_{i=1}^{c^m} p_i^2 \\right) - \\left(\\frac{2}{c^m} \\sum_{i=1}^{c^m} p_i \\right) + \\dfrac{c^m}{c^{2m}} \\\\ | ||
&= \\left( \\sum_{i=1}^{c^m} p_i^2 \\right) - \\frac{2}{c^m} (1) + \\dfrac{1}{c^{m}} \\\\ | ||
&= \\left( \\sum_{i=1}^{c^m} p_i^2 \\right) - \\dfrac{1}{c^{m}}. | ||
\\end{aligned} | ||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if there is any point in writing this huge block of text. Why don't we just type the correct formula in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think it does matter for the software, because the ambiguous notation caused me to spend a lot of extra time during development and testing figuring out (also not realizing that was a potential issue) whether there was a typo in their definition, or if they made a computational mistake. That could matter to anyone that want to use the formula to test something by hand themselves.
That's a good compromise. |
||
|
||
[^Li2019]: Li, Y., Gao, X., & Wang, L. (2019). Reverse dispersion entropy: a new | ||
complexity measure for sensor signal. Sensors, 19(23), 5203. | ||
""" | ||
function reverse_dispersion(x::AbstractVector{T}; s = GaussianSymbolization(5), | ||
m = 2, τ = 1, normalize = true) where T <: Real | ||
est = Dispersion(τ = τ, m = m, s = s) | ||
p = probabilities(x, est) | ||
|
||
# The following step combines distance information with the probabilities, so | ||
# from here on, it is not possible to use `renyi_entropy` or similar methods, because | ||
# we're not dealing with probabilities anymore. | ||
Hrde = distance_to_whitenoise(p, s.c, m) | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,6 +53,20 @@ function entropy_wavelet(x; wavelet = Wavelets.WT.Daubechies{12}(), base = MathC | |
entropy_renyi(x, est; base, q = 1) | ||
end | ||
|
||
function entropy_dispersion(args...) | ||
""" | ||
entropy_dispersion(x; m = 2, τ = 1, s = GaussianSymbolization(3), | ||
base = MathConstants.e) | ||
Comment on lines
+57
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, definitely. As I commented above, I unintentionally missed the semi-colon. |
||
|
||
Compute the dispersion entropy. This function is just a convenience call to: | ||
```julia | ||
est = Dispersion(m = m, τ = τ, s = s) | ||
entropy_shannon(x, est; base) | ||
``` | ||
See [`Dispersion`](@ref) for more info. | ||
""" | ||
function entropy_dispersion(x; wavelet = Wavelets.WT.Daubechies{12}(), | ||
base = MathConstants.e) | ||
|
||
end | ||
est = Dispersion(m = m, τ = τ, s = s) | ||
entropy_renyi(x, est; base, q = 1) | ||
end |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having so many optional arguments is inconvenient. If I want to change just
normalize
, I need to input all prior 4. I'd suggest to make everything besidesx
a keyword argument. I'd also recommend to not uses
, but rather something descriptive likesymbolization
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should indeed be keyword arguments. I missed the semi-colon.