Skip to content

Correlation

circ_corrcc(a, b, method='fl', test=False, strict=True)

Angular-Angular / Spherical Correlation.

Three methods are available:

  • 'fl' (Fisher & Lee, 1983): T-linear association. The correlation coefficient
\[ r = \frac{\sum_{i=1}^{n-1}\sum_{j=i+1}^{n} \sin(a_{ij}) \sin(b_{ij})}{\sqrt{\sum_{i=1}^{n-1}\sum_{j=i+1}^{n} \sin^2(a_{ij}) \sum_{i=1}^{n-1}\sum_{j=i+1}^{n} \sin^2(b_{ij})}} \]
  • 'js' (Jammalamadaka & SenGupta, 2001)
\[ r = \frac{\sum \sin(a_i - \bar{a}) \sin(b_i - \bar{b})}{\sqrt{\sum \sin^2(a_i - \bar{a}) \sum \sin^2(b_i - \bar{b})}} \]
  • 'nonparametric'
\[ r = \frac{\sum \cos(C \cdot \text{rankdiff})^2 + \sum \sin(C \cdot \text{rankdiff})^2}{n^2} - \frac{\sum \cos(C \cdot \text{ranksum})^2 + \sum \sin(C \cdot \text{ranksum})^2}{n^2} \]

, where \(C = 2\pi / n\) and \(\text{rankdiff} = \text{rank}_a - \text{rank}_b\) and \(\text{ranksum} = \text{rank}_a + \text{rank}_b\).

Parameters:

Name Type Description Default
a Union[Circular, ndarray, Sequence[float]]

Angles in radian

required
b Union[Circular, ndarray, Sequence[float]]

Angles in radian

required
method str
  • 'fl' (Fisher & Lee, 1983): T-linear association. The correlation coefficient is computed as:
  • 'js' (Jammalamadaka & SenGupta, 2001)
  • 'nonparametric'
'fl'
test bool

Return significant test results.

False
strict bool

Strict mode. If True, raise an error when mean direction is not significant. Only for method="js" (Jammalamadaka & SenGupta, 2001).

True

Returns:

Name Type Description
r float

Correlation coefficient.

reject bool

Return significant test if test is set to True.

Source code in pycircstat2/correlation.py
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
def circ_corrcc(
    a: Union[Circular, np.ndarray, Sequence[float]],
    b: Union[Circular, np.ndarray, Sequence[float]],
    method: str = "fl",
    test: bool = False,
    strict: bool = True,
) -> Union[float, CorrelationResult]:
    r"""
    Angular-Angular / Spherical Correlation.

    Three methods are available:

    - 'fl' (Fisher & Lee, 1983): T-linear association. The correlation coefficient

    $$
    r = \frac{\sum_{i=1}^{n-1}\sum_{j=i+1}^{n} \sin(a_{ij}) \sin(b_{ij})}{\sqrt{\sum_{i=1}^{n-1}\sum_{j=i+1}^{n} \sin^2(a_{ij}) \sum_{i=1}^{n-1}\sum_{j=i+1}^{n} \sin^2(b_{ij})}}
    $$

    - 'js' (Jammalamadaka & SenGupta, 2001)

    $$
    r = \frac{\sum \sin(a_i - \bar{a}) \sin(b_i - \bar{b})}{\sqrt{\sum \sin^2(a_i - \bar{a}) \sum \sin^2(b_i - \bar{b})}}
    $$

    - 'nonparametric'

    $$
    r = \frac{\sum \cos(C \cdot \text{rankdiff})^2 + \sum \sin(C \cdot \text{rankdiff})^2}{n^2} - \frac{\sum \cos(C \cdot \text{ranksum})^2 + \sum \sin(C \cdot \text{ranksum})^2}{n^2}
    $$

    , where $C = 2\pi / n$ and $\text{rankdiff} = \text{rank}_a - \text{rank}_b$ and $\text{ranksum} = \text{rank}_a + \text{rank}_b$.


    Parameters
    ----------
    a: Circular or np.ndarray
        Angles in radian
    b: Circular or np.ndarray
        Angles in radian
    method: str
        - 'fl' (Fisher & Lee, 1983): T-linear association. The correlation coefficient
          is computed as:
        - 'js' (Jammalamadaka & SenGupta, 2001)
        - 'nonparametric'
    test: bool
        Return significant test results.
    strict: bool
        Strict mode. If True, raise an error when mean direction is
        not significant. Only for method="js" (Jammalamadaka & SenGupta, 2001).

    Returns
    -------
    r: float
        Correlation coefficient.
    reject: bool
        Return significant test if `test` is set to True.
    """

    method = method.lower()
    if method == "fl":  # Fisher & Lee (1983)
        _corr = _circ_corrcc_fl
    elif method == "js":  # Jammalamadaka & SenGupta (2001)
        _corr = _circ_corrcc_js
    elif method == "nonparametric":
        _corr = _circ_corrcc_np
    else:
        raise ValueError("Invalid method. Choose from 'fl', 'js', or 'nonparametric'.")

    result = _corr(a, b, test, strict)

    return result if test else result.r

circ_corrcl(a, x)

Angular-Linear / Cylindrical Correlation based on Mardia (1972).

Also known as Linear-circular or C-linear association (Fisher, 1993).

\[ r = \sqrt{\frac{r_{xc}^2 + r_{xs}^2 - 2r_{xc}r_{xs}r_{cs}}{1 - r_{cs}^2}} \]

where \(r_{xc}\), \(r_{xs}\), and \(r_{cs}\) are the correlation coefficients between \(\cos(a)\) and \(x\), \(x\) and \(\sin(a)\), and \(\sin(a)\) and \(\cos(a)\), respectively.

Parameters:

Name Type Description Default
a Union[Circular, ndarray, Sequence[float]]

Angles in radian

required
x Union[ndarray, Sequence[float]]

Linear variable

required

Returns:

Name Type Description
ral float

correlation coefficient.

pval float
Reference

P658-659, Section 27.15(b) of Example 27.21 (Zar, 2010).

Source code in pycircstat2/correlation.py
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
def circ_corrcl(
    a: Union[Circular, np.ndarray, Sequence[float]],
    x: Union[np.ndarray, Sequence[float]],
) -> CorrelationResult:
    r"""Angular-Linear / Cylindrical Correlation based on Mardia (1972).

    Also known as Linear-circular or C-linear association (Fisher, 1993).

    $$
    r = \sqrt{\frac{r_{xc}^2 + r_{xs}^2 - 2r_{xc}r_{xs}r_{cs}}{1 - r_{cs}^2}}
    $$

    where $r_{xc}$, $r_{xs}$, and $r_{cs}$ are the correlation coefficients between
    $\cos(a)$ and $x$, $x$ and $\sin(a)$, and $\sin(a)$ and $\cos(a)$, respectively.

    Parameters
    ----------
    a: Circular or np.ndarray
        Angles in radian
    x: np.ndarray
        Linear variable

    Returns
    -------
    ral: float
        correlation coefficient.
    pval: float

    Reference
    ----
    P658-659, Section 27.15(b) of Example 27.21 (Zar, 2010).
    """

    a_alpha, _ = _coerce_angles(a)
    x_arr = np.asarray(x, dtype=float)
    if x_arr.ndim != 1:
        raise ValueError("`x` must be a one-dimensional array.")
    if a_alpha.size != x_arr.size:
        raise ValueError("`a` and `x` must be the same length.")
    if a_alpha.size < 3:
        raise ValueError("At least three paired observations are required.")

    n = a_alpha.size

    cos_a = np.cos(a_alpha)
    sin_a = np.sin(a_alpha)

    rxc = np.corrcoef(cos_a, x_arr)[0, 1]
    rxs = np.corrcoef(x_arr, sin_a)[0, 1]
    rcs = np.corrcoef(sin_a, cos_a)[0, 1]

    num = rxc**2 + rxs**2 - 2 * rxc * rxs * rcs
    den = 1 - rcs**2
    if np.isclose(den, 0.0):
        raise ValueError("Degenerate data produced division by zero in denominator.")
    r = np.sqrt(max(num / den, 0.0))

    pval = 1 - chi2(df=2).cdf(n * r**2)

    return CorrelationResult(r=float(r), p_value=float(pval))