Skip to main content

power_law_fit

Function power_law_fit 

Source
pub fn power_law_fit(
    data: &[f64],
    xmin: Option<f64>,
    force_continuous: bool,
) -> Result<PowerLawFit<'_>>
Expand description

Fits a power-law distribution to a sample, with the maximum likelihood method of Clauset, Shalizi and Newman.

data holds the samples (e.g. the degrees of the vertices of a graph), not a histogram or a distribution function. For a given xmin, the exponent alpha that maximizes the likelihood of the samples >= xmin is returned. The threshold is:

  • None: estimated, choosing the xmin for which the Kolmogorov–Smirnov distance between the fitted law and the sample is the smallest (slower, as every distinct value is tried);
  • Some(x): fixed to x; samples below x are ignored. x must be positive for a continuous law and at least 1 for a discrete one (so Some(1.0) uses all the positive integer samples); Some(0.0) is rejected by igraph.

A discrete power law is fitted if all samples are integers, unless force_continuous is true; a continuous one otherwise.

Degenerate samples give degenerate or failed fits. For a discrete law with no sample reaching the given xmin, igraph returns alpha = inf and a NaN log-likelihood (check alpha.is_finite() when xmin is chosen by hand); the continuous fit fails with ErrorKind::InvalidValue instead, and a single sample makes both fail.

See also Graph::degree (the usual sample to fit), and the generators of scale-free graphs Graph::barabasi_game and Graph::static_power_law_game.

Reference: A. Clauset, C. R. Shalizi and M. E. J. Newman, Power-law distributions in empirical data, SIAM Review 51(4):661–703, 2009.

Binds igraph_power_law_fit. Time complexity: O(n log n) in the continuous case with a fixed xmin; the discrete case is dominated by an L-BFGS optimization; estimating xmin multiplies the cost by the number of distinct samples.

§Errors

ErrorKind::InvalidValue for invalid data (e.g. no samples, NaN or infinite samples, an xmin below 1 for discrete or not positive for continuous samples, discrete samples or xmin of 2^62 or more), and other kinds for numerical failures of the fitting procedure.

Integer samples of 2^62 (about 4.6e18) or more are only accepted with force_continuous = true: for huge discrete samples plfit’s L-BFGS optimization fails, and igraph 1.0.1 then reads the error message from a stack buffer that no longer exists. The bound matches the one of PowerLawFit::p_value, so every discrete fit can be tested.

§Examples

Continuous samples drawn by inverse transform sampling from a power law with alpha = 2.5 and xmin = 1:

use igraph::{misc, prelude::*};

rng::seed(7)?;
let sample: Vec<f64> =
    (0..5000).map(|_| (1.0 - rng::uniform01()).powf(-1.0 / 1.5)).collect();
let fit = misc::power_law_fit(&sample, Some(1.0), false)?;
assert!(fit.continuous);
assert!((fit.alpha - 2.5).abs() < 0.1);
assert_eq!(fit.xmin, 1.0);

The degrees of a Barabási–Albert graph (igraph’s examples/simple/igraph_power_law_fit.c, with the same seed and output):

use igraph::{games::BarabasiOptions, misc, prelude::*};

rng::seed(42)?;
let options = BarabasiOptions {
    m: 2,
    algorithm: BarabasiAlgorithm::Bag,
    ..Default::default()
};
let g = Graph::barabasi_game(10_000, &options)?;
let degrees: Vec<f64> = g
    .degree(.., NeighborMode::All, Loops::None)?
    .into_iter()
    .map(|d| d as f64)
    .collect();
let fit = misc::power_law_fit(&degrees, None, false)?;
assert!(!fit.continuous); // integer samples: a discrete law
assert_eq!(fit.xmin, 7.0);
assert!((fit.alpha - 3.04393).abs() < 1e-5);