MCPcopy Create free account
hub / github.com/Open-Quant/openquant / variation_of_information_score

Function variation_of_information_score

crates/openquant/src/codependence.rs:340–404  ·  view source on GitHub ↗
(
    x: &[f64],
    y: &[f64],
    n_bins: Option<usize>,
    normalize: bool,
)

Source from the content-addressed store, hash-verified

338 d_cov_yy /= denom;
339
340 let denom = (d_cov_xx.sqrt() * d_cov_yy.sqrt()).sqrt();
341 if denom == 0.0 {
342 return Err(CodependenceError::ZeroDistanceVariance);
343 }
344
345 Ok(d_cov_xy.sqrt() / denom)
346}
347
348/// Histogram bin count that minimises the bias of entropy estimates (Hacine-Gharbi et al.,
349/// 2012).
350///
351/// With `corr_coef = None` uses the univariate (marginal entropy) rule; with the sample
352/// correlation `rho` of two series uses the bivariate (joint entropy) rule
353/// `round(sqrt(1 + sqrt(1 + 24 N / (1 - rho^2))) / sqrt(2))`. A correlation within `1e-4` of
354/// `+-1` falls back to the univariate rule.
355///
356/// # Errors
357///
358/// - [`CodependenceError::InputTooShort`] if `num_obs` is zero.
359/// - [`CodependenceError::InvalidBins`] if the rule does not yield a positive count (a `NaN`
360/// correlation).
361///
362/// ```
363/// use openquant::codependence::get_optimal_number_of_bins;
364///
365/// # fn main() -> Result<(), openquant::codependence::CodependenceError> {
366/// assert_eq!(get_optimal_number_of_bins(1_000, None)?, 15);
367/// assert_eq!(get_optimal_number_of_bins(1_000, Some(0.9))?, 13);
368/// # Ok(())
369/// # }
370/// ```
371pub fn get_optimal_number_of_bins(
372 num_obs: usize,
373 corr_coef: Option<f64>,
374) -> CodependenceResult<usize> {
375 if num_obs == 0 {
376 return Err(CodependenceError::InputTooShort);
377 }
378
379 let n = num_obs as f64;
380 let univariate = || {
381 let z = (8.0 + 324.0 * n + 12.0 * (36.0 * n + 729.0 * n * n).sqrt()).cbrt();
382 (z / 6.0 + 2.0 / (3.0 * z) + 1.0 / 3.0).round()
383 };
384 // Arm order keeps a NaN correlation on the bivariate branch, as before.
385 // At |corr| = 1 the bivariate formula divides by zero, so both signs fall back.
386 let bins = match corr_coef {
387 None => univariate(),
388 Some(corr) if (corr.abs() - 1.0).abs() <= 1e-4 => univariate(),
389 Some(corr) => {
390 let inner = (1.0 + 24.0 * n / (1.0 - corr * corr)).sqrt();
391 (2.0_f64).powf(-0.5) * (1.0 + inner).sqrt()
392 }
393 };
394
395 let bins = bins.round() as isize;
396 if bins <= 0 {
397 return Err(CodependenceError::InvalidBins);

Calls 7

histogram2dFunction · 0.85
entropyFunction · 0.85
histogramFunction · 0.85
lenMethod · 0.80
is_emptyMethod · 0.80
corrcoefFunction · 0.70

Tested by 1

test_information_metricsFunction · 0.68