Skip to content

Commit

Permalink
approximate entropy function (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
chungg authored Aug 28, 2024
1 parent c4423f5 commit ed79801
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 0 deletions.
8 changes: 8 additions & 0 deletions benches/traquer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,14 @@ fn criterion_benchmark(c: &mut Criterion) {
)
})
});
c.bench_function("stats-dist-approx_entropy", |b| {
b.iter(|| {
black_box(
statistic::distribution::approx_entropy(&stats.close, 16, None, None)
.collect::<Vec<_>>(),
)
})
});

c.bench_function("stats-regress-mse", |b| {
b.iter(|| {
Expand Down
54 changes: 54 additions & 0 deletions src/statistic/distribution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,60 @@ pub fn cv<T: ToPrimitive>(data: &[T], window: usize) -> impl Iterator<Item = f64
}))
}

/// Approximate Entropy
///
/// A measure used to quantify the amount of regularity and the unpredictability of fluctuations
/// over time-series data.
///
/// ## Sources
///
/// [[1]](https://en.wikipedia.org/wiki/Approximate_entropy)
/// [[2]](https://www.nature.com/articles/s41598-019-49320-9)
///
/// # Examples
///
/// ```
/// use traquer::statistic::distribution;
///
/// distribution::approx_entropy(
/// &[1.0,2.0,3.0,4.0,5.0], 3, Some(2), Some(0.1)
/// ).collect::<Vec<f64>>();
/// ```
pub fn approx_entropy<T: ToPrimitive>(
data: &[T],
window: usize,
run_length: Option<usize>,
tolerance: Option<f64>,
) -> impl Iterator<Item = f64> + '_ {
fn phi<T: ToPrimitive>(ts: &[T], m: usize, tol: f64) -> f64 {
let win_len = ts.len() - m + 1;
let mut cm = 0.0;
for i in 0..win_len {
let mut count = 0.0;
for j in 0..win_len {
count += (ts[i..i + m]
.iter()
.zip(&ts[j..j + m])
.map(|(x, y)| (x.to_f64().unwrap() - y.to_f64().unwrap()).abs())
.fold(f64::NAN, f64::max)
<= tol) as u8 as f64;
// any() is faster when tolerance is very low and slower when high.
// finding max is consistently in between.
}
cm += (count / win_len as f64).ln();
}
cm / win_len as f64
}

let run_length = run_length.unwrap_or(2);
let tolerance = tolerance.unwrap_or_else(|| _std_dev(data, data.len()).last().unwrap() * 0.2);
iter::repeat(f64::NAN).take(window - 1).chain(
data.windows(window).map(move |w| {
(phi(w, run_length + 1, tolerance) - phi(w, run_length, tolerance)).abs()
}),
)
}

/// Kurtosis
///
/// A measure of the "tailedness" of the probability distribution of a real-valued random
Expand Down
76 changes: 76 additions & 0 deletions tests/stat_dist_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,3 +388,79 @@ fn test_rank() {
rank(input, Some(RankMode::Dense)).collect::<Vec<_>>()
);
}

#[test]
fn test_approx_entropy() {
let stats = common::test_data();
let result = approx_entropy(
&stats
.close
.iter()
.zip(&stats.close[1..])
.map(|(x, y)| (y / x).ln())
.collect::<Vec<f64>>(),
16,
Some(2),
Some(0.1),
)
.collect::<Vec<_>>();
assert_eq!(stats.close.len() - 1, result.len());
assert_eq!(
vec![
0.3899689516358784,
0.40809929232328257,
0.25004368014823874,
0.12031030800877052,
0.17403528234884807,
0.15900363263070655,
0.13096809113760582,
0.1104630098022307,
0.1194853281985502,
0.12858861838106073,
0.15395314742114657,
0.11830103980290227,
0.11462052987046589,
0.0758266584781783,
0.06679983850538206,
0.036712468860765346,
0.020434877610718875,
0.016727783315437166
],
result[16 - 1..]
);
let result = approx_entropy(
&stats
.close
.iter()
.zip(&stats.close[1..])
.map(|(x, y)| (y / x).ln())
.collect::<Vec<f64>>(),
16,
Some(2),
None,
)
.collect::<Vec<_>>();
assert_eq!(
vec![
0.06899287148695166,
0.06899287148695166,
0.06899287148695166,
0.06899287148695166,
0.023426752587707433,
0.023426752587707433,
0.11584637666236697,
0.11584637666236697,
0.023426752587707433,
0.023426752587707877,
0.11584637666236697,
0.11584637666236697,
0.11584637666236697,
0.11584637666236697,
0.20826600073702695,
0.18248579418728994,
0.18248579418728994,
0.18248579418728994
],
result[16 - 1..]
);
}

0 comments on commit ed79801

Please sign in to comment.