pingouin.circ_mean

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

Mean direction for (binned) 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.

axisint or None

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

Returns
mufloat

Circular mean, in radians.

Notes

From Wikipedia:

In mathematics, a mean of circular quantities is a mean which is sometimes better-suited for quantities like angles, daytimes, and fractional parts of real numbers. This is necessary since most of the usual means may not be appropriate on circular quantities. For example, the arithmetic mean of 0° and 360° is 180°, which is misleading because for most purposes 360° is the same thing as 0°. As another example, the “average time” between 11 PM and 1 AM is either midnight or noon, depending on whether the two times are part of a single night or part of a single calendar day.

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

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

For binned angles with weights \(w\), this becomes:

\[\bar{\alpha} = \text{angle} \left ( \sum_{j=1}^n w \cdot \exp(i \cdot \alpha_j) \right )\]

Missing values in angles are omitted from the calculations.

References

Examples

  1. Circular mean of a 1-D array of angles, in radians

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

Compare with SciPy:

>>> from scipy.stats import circmean
>>> import numpy as np
>>> round(circmean(angles, low=0, high=2*np.pi), 4)
1.013
  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_mean(rad)  # On the first axis (default)
array([1.27532162, 1.94336576, 2.23195927, 0.52110503, 1.80240563])
>>> pg.circ_mean(rad, axis=-1)  # On the last axis (default)
array([0.68920819, 2.49334852, 1.5954149 ])
>>> round(pg.circ_mean(rad, axis=None), 4)  # Across the entire array
1.6954

Missing values are omitted from the calculations:

>>> rad[0, 0] = np.nan
>>> pg.circ_mean(rad)
array([1.76275   , 1.94336576, 2.23195927, 0.52110503, 1.80240563])
  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_mean(angles_bins, w), 4)
0.606