pingouin.circ_r

pingouin.circ_r(angles, w=None, d=None, axis=0)[source]

Mean resultant vector length for circular data.

Parameters
anglesarray_like

Samples of angles in radians. The range of angles must be either \([0, 2\pi]\) or \([-\pi, \pi]\). If angles is not expressed in radians (e.g. degrees or 24-hours), please use the pingouin.convert_angles() function prior to using the present function.

warray_like

Number of incidences per bins (i.e. “weights”), in case of binned angle data.

dfloat

Spacing (in radians) of bin centers for binned data. If supplied, a correction factor is used to correct for bias in the estimation of r.

axisint or None

Compute along this dimension. Default is the first axis (0).

Returns
rfloat

Circular mean vector length.

Notes

The length of the mean resultant vector is a crucial quantity for the measurement of circular spread or hypothesis testing in directional statistics. The closer it is to one, the more concentrated the data sample is around the mean direction (Berens 2009).

The circular vector length of a set of angles \(\alpha\) is defined by:

\[\bar{\alpha} = \frac{1}{N}\left \| \sum_{j=1}^n \exp(i \cdot \alpha_j) \right \|\]

Missing values in angles are omitted from the calculations.

References

Examples

  1. Mean resultant vector length of a 1-D array of angles, in radians

>>> import pingouin as pg
>>> angles = [0.785, 1.570, 3.141, 0.839, 5.934]
>>> r = pg.circ_r(angles)
>>> round(r, 4)
0.4972

Note that there is a close relationship between the vector length and the circular standard deviation, i.e. \(\sigma = \sqrt{-2 \ln R}\):

>>> import numpy as np
>>> round(np.sqrt(-2 * np.log(r)), 4)
1.1821

which gives similar result as SciPy built-in function:

>>> from scipy.stats import circstd
>>> round(circstd(angles), 4)
1.1821

Sanity check: if all angles are the same, the vector length should be one:

>>> angles = [3.14, 3.14, 3.14, 3.14]
>>> round(pg.circ_r(angles), 4)
1.0
  1. Using a 2-D array of angles in degrees

>>> np.random.seed(123)
>>> deg = np.random.randint(low=0, high=360, size=(3, 5))
>>> deg
array([[322,  98, 230,  17,  83],
       [106, 123,  57, 214, 225],
       [ 96, 113, 126,  47,  73]])

We first need to convert from degrees to radians:

>>> rad = np.round(pg.convert_angles(deg, low=0, high=360), 4)
>>> rad
array([[-0.6632,  1.7104, -2.2689,  0.2967,  1.4486],
       [ 1.85  ,  2.1468,  0.9948, -2.5482, -2.3562],
       [ 1.6755,  1.9722,  2.1991,  0.8203,  1.2741]])
>>> pg.circ_r(rad)  # On the first axis (default)
array([0.46695499, 0.98398294, 0.3723287 , 0.31103746, 0.42527149])
>>> pg.circ_r(rad, axis=-1)  # On the last axis (default)
array([0.28099998, 0.45456096, 0.88261161])
>>> round(pg.circ_r(rad, axis=None), 4)  # Across the entire array
0.4486

Missing values are omitted from the calculations:

>>> rad[0, 0] = np.nan
>>> pg.circ_r(rad)
array([0.99619613, 0.98398294, 0.3723287 , 0.31103746, 0.42527149])
  1. Using binned angles

>>> np.random.seed(123)
>>> nbins = 18  # Number of bins to divide the unit circle
>>> angles_bins = np.linspace(0, 2 * np.pi, nbins)
>>> # w represents the number of incidences per bins, or "weights".
>>> w = np.random.randint(low=0, high=5, size=angles_bins.size)
>>> round(pg.circ_r(angles_bins, w), 4)
0.3642