pcc

Provides pcc function to estimate Pearson Correlation Coefficients (PCC)

Date: 2019-04-25 Authors: Renaud Pacalet, renaud.pacalet@telecom-paris.fr

The Pearson Correlation Coefficient (PCC) is a statistical tool to evaluate the linear correlation between two random variables. The formula of a PCC between random variables X and Y is:

PCC(X,Y) = [E(XY) - E(X)E(Y)] / [s(X) * s(Y)]

where E(Z) is the expectation (average value) of random variable Z and s(Z) is its standard deviation. The value of the PCC is in range -1 to +1. Values close to 0 indicate no or a weak linear correlation. Values close to -1 or +1 indicate strong linear correlations.

The basic form of the pcc function computes an estimate of PCC(X,Y), the Pearson Correlation Coefficient between two scalar random variables X and Y. It computes the estimate from two samples of X and Y. The samples must contain the same number N of observations, with N>=2. The samples are passed as two lists of N numbers:

x = [0]N y = [0]N p = 0 ... p = pcc.pcc(x,y)

The returned value is a floating point number between -1.0 and 1.0.

In a second form the pcc function computes the K estimates of PCC(X,Yk), 0<=k=2 numbers each, where N is the length of the sublists and also of the list representing the sample of X. This second form returns the list of the K PCC estimates:

x = [0]N y = [[0]N for k in range(K)] p = [0]*K ... p = pcc.pcc(x,y)

A third and fourth forms are the equivalents of the two first forms but where X is a L-components vector random variable. The PCC estimates are computed component-wise of X:

x = [[0]L for n in range(N)] y = [0]N z = [[0]N for k in range(K)] pxy = [0]L pxz = [[0]*L for k in range(K)] ... pxy = pcc.pcc(x,y) pxz = pcc.pcc(x,z)

All forms return a list of lists.

Usage: import pcc

x0 = [0]*N
x1 = [[0]*L for n in range(N)]
y0 = [0]*N
y1 = [[0]*N for k in range(K)]
px0y0 = [[0]]
px0y1 = [[0]*K]
px1y0 = [[0]*L]
px1y1 = [[0]*L for k in range(K)]
...
px0y0 = pcc.pcc(x0,y0)
px0y1 = pcc.pcc(x0,y1)
px1y0 = pcc.pcc(x1,y0)
px1y1 = pcc.pcc(x1,y1)
  1#!/usr/bin/env python2
  2
  3# MAIN-ONLY: DO NOT MODIFY THIS FILE
  4
  5#
  6# Copyright (C) Telecom Paris
  7# 
  8# This file must be used under the terms of the CeCILL. This source
  9# file is licensed as described in the file COPYING, which you should
 10# have received as part of this distribution. The terms are also
 11# available at:
 12# https://cecill.info/licences/Licence_CeCILL_V2.1-en.html
 13#
 14
 15"""
 16Provides pcc function to estimate Pearson Correlation Coefficients (PCC)
 17
 18Date:    2019-04-25
 19Authors: Renaud Pacalet, renaud.pacalet@telecom-paris.fr
 20
 21The Pearson Correlation Coefficient (PCC) is a statistical tool to evaluate the
 22linear correlation between two random variables. The formula of a PCC between
 23random variables X and Y is:
 24
 25PCC(X,Y) = [E(X*Y) - E(X)*E(Y)] / [s(X) * s(Y)]
 26
 27where E(Z) is the expectation (average value) of random variable Z and s(Z) is
 28its standard deviation. The value of the PCC is in range -1 to +1. Values close
 29to 0 indicate no or a weak linear correlation. Values close to -1 or +1
 30indicate strong linear correlations.
 31
 32The basic form of the pcc function computes an estimate of PCC(X,Y), the
 33Pearson Correlation Coefficient between two scalar random variables X and Y. It
 34computes the estimate from two samples of X and Y. The samples must contain the
 35same number N of observations, with N>=2. The samples are passed as two lists
 36of N numbers:
 37
 38x = [0]*N
 39y = [0]*N
 40p = 0
 41...
 42p = pcc.pcc(x,y)
 43
 44The returned value is a floating point number between -1.0 and 1.0.
 45
 46In a second form the pcc function computes the K estimates of PCC(X,Yk),
 470<=k<K. The Yk are K distinct scalar random variables. Their samples are passed
 48as a list of K lists of N>=2 numbers each, where N is the length of the
 49sublists and also of the list representing the sample of X. This second form
 50returns the list of the K PCC estimates:
 51
 52x = [0]*N
 53y = [[0]*N for k in range(K)]
 54p = [0]*K
 55...
 56p = pcc.pcc(x,y)
 57
 58A third and fourth forms are the equivalents of the two first forms but where X
 59is a L-components vector random variable. The PCC estimates are computed
 60component-wise of X:
 61
 62x = [[0]*L for n in range(N)]
 63y = [0]*N
 64z = [[0]*N for k in range(K)]
 65pxy = [0]*L
 66pxz = [[0]*L for k in range(K)]
 67...
 68pxy = pcc.pcc(x,y)
 69pxz = pcc.pcc(x,z)
 70
 71All forms return a list of lists.
 72
 73Usage:
 74    import pcc
 75
 76    x0 = [0]*N
 77    x1 = [[0]*L for n in range(N)]
 78    y0 = [0]*N
 79    y1 = [[0]*N for k in range(K)]
 80    px0y0 = [[0]]
 81    px0y1 = [[0]*K]
 82    px1y0 = [[0]*L]
 83    px1y1 = [[0]*L for k in range(K)]
 84    ...
 85    px0y0 = pcc.pcc(x0,y0)
 86    px0y1 = pcc.pcc(x0,y1)
 87    px1y0 = pcc.pcc(x1,y0)
 88    px1y1 = pcc.pcc(x1,y1)
 89
 90"""
 91
 92import numpy as np
 93import numbers
 94
 95def pcc(x, y):
 96    """
 97Computes an estimate of the PCC between random variables X and Y
 98
 99First form:
100    Args:
101        x (list of N floats, N>1): N-points sample of random variable X
102        y (list of N floats, N>1): N-points sample of random variable Y
103    
104    Returns:
105        [[p]]: where p (float) is the PCC estimate of random variables X and Y
106
107    Example:
108        import pcc
109        ...
110        x = [0]*N                       # X sample
111        y = [0]*N                       # Y sample
112        p = [[0]]                       # PCC estimate
113        for n in range (N):             # For N draws
114            x[n] = draw_X               # Draw random variable X
115            y[n] = draw_Y               # Draw random variable Y
116        p = pcc.pcc (x,y)               # Compute PCC(X,Y) estimate
117        print ("PCC(X,Y) = %lf" % p[0][0])    # Print PCC estimate
118        ...
119
120Second form:
121    Args:
122        x (list of N floats, N>1): N-points sample of random variable X
123        y (list of K lists of N floats, N>1): K different N-points
124            samples of random variables Y0,Y1,...,YK-1
125    
126    Returns:
127        [[p0 p1...]]: where pi (float) is the PCC estimate of random variables
128            X and Yi
129
130    Example:
131        import pcc
132        ...
133        x = [0]*N                         # X sample
134        y = [[0]*N for k in range(K)]     # Yk samples, 0<=k<K
135        p = [[0]*K]                       # K PCC estimates
136        for n in range (N):               # For N draws
137            x[n] = draw_X                 # Draw random variable X
138            for k in range (K):           # For K random variables Yk
139                y[k][n] = draw_Y (k)      # Draw random variable Yk
140        p = pcc.pcc (x,y)                 # Compute PCC(X,Yk) estimates, 0<=k<K
141        for k in range (K):               # For K PCC estimates
142            print ("PCC(X,Y%d)=%lf" % (k,p[k][0])) # Print PCC estimates
143        ...
144
145Third form:
146    Args:
147        x (list of N lists of L floats, N>1): N-points sample of vector random variable X
148        y (list of N floats, N>1): N-points sample of random variable Y
149    
150    Returns:
151        [[p0 p1...]]: where pi (float) is the PCC estimate of random variables
152            X[i] (component i of vector X) and Y
153
154    Example:
155        import pcc
156        ...
157        x = [[0]*L for n in range(N)]   # X sample
158        y = [0]*N                       # Y sample
159        p = [[0]*L]                     # PCC estimate
160        for n in range (N):             # For N draws
161            for l in range (L):         # For L components
162                x[n][l] = draw_X (l)    # Draw component of random variable X
163            y[n] = draw_Y               # Draw random variable Y
164        p = pcc.pcc (x,y)               # Compute PCC(X,Y) estimate
165        for l in range (L):             # For L components
166            print ("PCC(X,Y)[%d] = %lf" % (l,p[l][0])) # Print component of PCC estimate
167        ...
168
169Fourth form:
170    Args:
171        x (list of N lists of L floats, N>1): N-points sample of vector random variable X
172        y (list of K lists of N floats, N>1): K different N-points
173            samples of random variables Y0,Y1,...,YK-1
174    
175    Returns:
176        [[p00 p01...] [p10 p11...]...]: where pji is the PCC estimate of random
177            variables X[i] (component i of vector X) and Yj
178
179    Example:
180        import pcc
181        ...
182        x = [[0]*L for n in range(N)]   # X sample
183        y = [[0]*N for k in range(K)]   # Yk samples, 0<=k<K
184        p = [[0]*L for k in range(K)]   # PCC estimate
185        for n in range (N):             # For N draws
186            for l in range (L):         # For L components
187                x[n][l] = draw_X (l)    # Draw component of random variable X
188            for k in range (K):         # For K random variables Yk
189                y[k][n] = draw_Y (k)    # Draw random variable Yk
190        p = pcc.pcc (x,y)               # Compute PCC(X,Y) estimate
191        for k in range (K):             # For K PCC estimates
192            for l in range (L):         # For L components
193                print ("PCC(X,Y%d)[%d] = %lf" % (k,l,p[k][l])) # Print component of PCC estimate
194        ...
195
196Raises:
197    TypeError: x,y lengths mismatch (first form)
198    TypeError: x,y-sub-lists lengths mismatch (second form)
199    TypeError: x not list of floats and not list of lists of floats
200    TypeError: y not list of floats and not list of lists of floats
201    ValueError: length of x < 2
202    ValueError: x variance estimate=0 (constant x?)
203    ValueError: y variance estimate=0 (constant y?)
204
205Note:
206    The second and fourth forms are equivalent to:
207        p = map(lambda z:pcc.pcc(x,z),y)
208    but are much more efficient.
209    """
210
211    # check types
212    if not isinstance(x, list):
213        raise TypeError('X must be a list of numbers or a list of lists of numbers')
214    if not isinstance(y, list):
215        raise TypeError('Y must be a list of numbers or a list of lists of numbers')
216
217    x0 = len(x)
218    y0 = len(y)
219    if (x0 < 2):
220        raise ValueError('samples with less than 2 values are not supported')
221
222    if all(isinstance(item, numbers.Number) for item in x):
223        x1 = 0
224    elif all(isinstance(item, list) for item in x):
225        x1 = len(x[0])
226        if not all(len(item) == x1 for item in x):
227            raise TypeError('X realizations of different lengths are not supported')
228        if not all(all(isinstance(item, numbers.Number) for item in row) for row in x):
229            raise TypeError('X must be a list of numbers or a list of lists of numbers')
230
231    if all(isinstance(item, numbers.Number) for item in y):
232        y1 = 0
233    elif all(isinstance(item, list) for item in y):
234        y1 = len(y[0])
235        if not all(len(item) == y1 for item in y):
236            raise TypeError('Y realizations of different lengths are not supported')
237        if not all(all(isinstance(item, numbers.Number) for item in row) for row in y):
238            raise TypeError('Y must be a list of numbers or a list of lists of numbers')
239
240    if (y1 == 0 and x0 != y0) or (y1 != 0 and x0 != y1):
241            raise TypeError('samples of different lengths are not supported')
242
243    xarray = np.asarray(x, dtype=np.float64)
244    yarray = np.asarray(y, dtype=np.float64)
245    if x1 == 0:
246        sum_x = np.sum(xarray)
247        sum_x2 = np.sum(xarray * xarray)
248        std_x = np.sqrt(x0 * sum_x2 - sum_x * sum_x)
249        if std_x == 0.0:
250            raise ValueError('variance(X)=0')
251    else:
252        sum_x = np.sum(xarray, axis=0)
253        sum_x2 = np.apply_along_axis(lambda t:sum(t * t), 0, xarray)
254        std_x = np.sqrt(x0 * sum_x2 - sum_x * sum_x)
255        if any(item == 0.0 for item in std_x):
256            raise ValueError('variance(X)=0 at indexes ' + numpy.where(std_x == 0.0)[0])
257    if y1 == 0:
258        sum_y = np.sum(yarray)
259        sum_y2 = np.sum(yarray * yarray)
260        std_y = np.sqrt(y0 * sum_y2 - sum_y * sum_y)
261        if std_y == 0.0:
262            raise ValueError('variance(Y)=0')
263    else:
264        sum_y = np.sum(yarray, axis=1)
265        sum_y2 = np.apply_along_axis(lambda t:sum(t * t), 1, yarray)
266        std_y = np.sqrt(y1 * sum_y2 - sum_y * sum_y)
267        if any(item == 0.0 for item in std_y):
268            raise ValueError('variance(Y)=0 at indexes ' + numpy.where(std_y == 0.0)[0])
269
270    sum_xy = np.dot(xarray.T, yarray.T)
271    sum_x_sum_y = np.outer(sum_x.T, sum_y)
272    std_x_std_y = np.outer(std_x, std_y)
273    if x1 != 0 and y1 == 0:
274        sum_x_sum_y = sum_x_sum_y.T
275        std_x_std_y = std_x_std_y.T
276    p = (x0 * sum_xy - sum_x_sum_y) / std_x_std_y
277    return p.T.tolist()
278
279# vim: set tabstop=8 softtabstop=4 shiftwidth=4 expandtab textwidth=0:
def pcc(x, y):
 96def pcc(x, y):
 97    """
 98Computes an estimate of the PCC between random variables X and Y
 99
100First form:
101    Args:
102        x (list of N floats, N>1): N-points sample of random variable X
103        y (list of N floats, N>1): N-points sample of random variable Y
104    
105    Returns:
106        [[p]]: where p (float) is the PCC estimate of random variables X and Y
107
108    Example:
109        import pcc
110        ...
111        x = [0]*N                       # X sample
112        y = [0]*N                       # Y sample
113        p = [[0]]                       # PCC estimate
114        for n in range (N):             # For N draws
115            x[n] = draw_X               # Draw random variable X
116            y[n] = draw_Y               # Draw random variable Y
117        p = pcc.pcc (x,y)               # Compute PCC(X,Y) estimate
118        print ("PCC(X,Y) = %lf" % p[0][0])    # Print PCC estimate
119        ...
120
121Second form:
122    Args:
123        x (list of N floats, N>1): N-points sample of random variable X
124        y (list of K lists of N floats, N>1): K different N-points
125            samples of random variables Y0,Y1,...,YK-1
126    
127    Returns:
128        [[p0 p1...]]: where pi (float) is the PCC estimate of random variables
129            X and Yi
130
131    Example:
132        import pcc
133        ...
134        x = [0]*N                         # X sample
135        y = [[0]*N for k in range(K)]     # Yk samples, 0<=k<K
136        p = [[0]*K]                       # K PCC estimates
137        for n in range (N):               # For N draws
138            x[n] = draw_X                 # Draw random variable X
139            for k in range (K):           # For K random variables Yk
140                y[k][n] = draw_Y (k)      # Draw random variable Yk
141        p = pcc.pcc (x,y)                 # Compute PCC(X,Yk) estimates, 0<=k<K
142        for k in range (K):               # For K PCC estimates
143            print ("PCC(X,Y%d)=%lf" % (k,p[k][0])) # Print PCC estimates
144        ...
145
146Third form:
147    Args:
148        x (list of N lists of L floats, N>1): N-points sample of vector random variable X
149        y (list of N floats, N>1): N-points sample of random variable Y
150    
151    Returns:
152        [[p0 p1...]]: where pi (float) is the PCC estimate of random variables
153            X[i] (component i of vector X) and Y
154
155    Example:
156        import pcc
157        ...
158        x = [[0]*L for n in range(N)]   # X sample
159        y = [0]*N                       # Y sample
160        p = [[0]*L]                     # PCC estimate
161        for n in range (N):             # For N draws
162            for l in range (L):         # For L components
163                x[n][l] = draw_X (l)    # Draw component of random variable X
164            y[n] = draw_Y               # Draw random variable Y
165        p = pcc.pcc (x,y)               # Compute PCC(X,Y) estimate
166        for l in range (L):             # For L components
167            print ("PCC(X,Y)[%d] = %lf" % (l,p[l][0])) # Print component of PCC estimate
168        ...
169
170Fourth form:
171    Args:
172        x (list of N lists of L floats, N>1): N-points sample of vector random variable X
173        y (list of K lists of N floats, N>1): K different N-points
174            samples of random variables Y0,Y1,...,YK-1
175    
176    Returns:
177        [[p00 p01...] [p10 p11...]...]: where pji is the PCC estimate of random
178            variables X[i] (component i of vector X) and Yj
179
180    Example:
181        import pcc
182        ...
183        x = [[0]*L for n in range(N)]   # X sample
184        y = [[0]*N for k in range(K)]   # Yk samples, 0<=k<K
185        p = [[0]*L for k in range(K)]   # PCC estimate
186        for n in range (N):             # For N draws
187            for l in range (L):         # For L components
188                x[n][l] = draw_X (l)    # Draw component of random variable X
189            for k in range (K):         # For K random variables Yk
190                y[k][n] = draw_Y (k)    # Draw random variable Yk
191        p = pcc.pcc (x,y)               # Compute PCC(X,Y) estimate
192        for k in range (K):             # For K PCC estimates
193            for l in range (L):         # For L components
194                print ("PCC(X,Y%d)[%d] = %lf" % (k,l,p[k][l])) # Print component of PCC estimate
195        ...
196
197Raises:
198    TypeError: x,y lengths mismatch (first form)
199    TypeError: x,y-sub-lists lengths mismatch (second form)
200    TypeError: x not list of floats and not list of lists of floats
201    TypeError: y not list of floats and not list of lists of floats
202    ValueError: length of x < 2
203    ValueError: x variance estimate=0 (constant x?)
204    ValueError: y variance estimate=0 (constant y?)
205
206Note:
207    The second and fourth forms are equivalent to:
208        p = map(lambda z:pcc.pcc(x,z),y)
209    but are much more efficient.
210    """
211
212    # check types
213    if not isinstance(x, list):
214        raise TypeError('X must be a list of numbers or a list of lists of numbers')
215    if not isinstance(y, list):
216        raise TypeError('Y must be a list of numbers or a list of lists of numbers')
217
218    x0 = len(x)
219    y0 = len(y)
220    if (x0 < 2):
221        raise ValueError('samples with less than 2 values are not supported')
222
223    if all(isinstance(item, numbers.Number) for item in x):
224        x1 = 0
225    elif all(isinstance(item, list) for item in x):
226        x1 = len(x[0])
227        if not all(len(item) == x1 for item in x):
228            raise TypeError('X realizations of different lengths are not supported')
229        if not all(all(isinstance(item, numbers.Number) for item in row) for row in x):
230            raise TypeError('X must be a list of numbers or a list of lists of numbers')
231
232    if all(isinstance(item, numbers.Number) for item in y):
233        y1 = 0
234    elif all(isinstance(item, list) for item in y):
235        y1 = len(y[0])
236        if not all(len(item) == y1 for item in y):
237            raise TypeError('Y realizations of different lengths are not supported')
238        if not all(all(isinstance(item, numbers.Number) for item in row) for row in y):
239            raise TypeError('Y must be a list of numbers or a list of lists of numbers')
240
241    if (y1 == 0 and x0 != y0) or (y1 != 0 and x0 != y1):
242            raise TypeError('samples of different lengths are not supported')
243
244    xarray = np.asarray(x, dtype=np.float64)
245    yarray = np.asarray(y, dtype=np.float64)
246    if x1 == 0:
247        sum_x = np.sum(xarray)
248        sum_x2 = np.sum(xarray * xarray)
249        std_x = np.sqrt(x0 * sum_x2 - sum_x * sum_x)
250        if std_x == 0.0:
251            raise ValueError('variance(X)=0')
252    else:
253        sum_x = np.sum(xarray, axis=0)
254        sum_x2 = np.apply_along_axis(lambda t:sum(t * t), 0, xarray)
255        std_x = np.sqrt(x0 * sum_x2 - sum_x * sum_x)
256        if any(item == 0.0 for item in std_x):
257            raise ValueError('variance(X)=0 at indexes ' + numpy.where(std_x == 0.0)[0])
258    if y1 == 0:
259        sum_y = np.sum(yarray)
260        sum_y2 = np.sum(yarray * yarray)
261        std_y = np.sqrt(y0 * sum_y2 - sum_y * sum_y)
262        if std_y == 0.0:
263            raise ValueError('variance(Y)=0')
264    else:
265        sum_y = np.sum(yarray, axis=1)
266        sum_y2 = np.apply_along_axis(lambda t:sum(t * t), 1, yarray)
267        std_y = np.sqrt(y1 * sum_y2 - sum_y * sum_y)
268        if any(item == 0.0 for item in std_y):
269            raise ValueError('variance(Y)=0 at indexes ' + numpy.where(std_y == 0.0)[0])
270
271    sum_xy = np.dot(xarray.T, yarray.T)
272    sum_x_sum_y = np.outer(sum_x.T, sum_y)
273    std_x_std_y = np.outer(std_x, std_y)
274    if x1 != 0 and y1 == 0:
275        sum_x_sum_y = sum_x_sum_y.T
276        std_x_std_y = std_x_std_y.T
277    p = (x0 * sum_xy - sum_x_sum_y) / std_x_std_y
278    return p.T.tolist()

Computes an estimate of the PCC between random variables X and Y

First form: Args: x (list of N floats, N>1): N-points sample of random variable X y (list of N floats, N>1): N-points sample of random variable Y

Returns:
    [[p]]: where p (float) is the PCC estimate of random variables X and Y

Example:
    import pcc
    ...
    x = [0]*N                       # X sample
    y = [0]*N                       # Y sample
    p = [[0]]                       # PCC estimate
    for n in range (N):             # For N draws
        x[n] = draw_X               # Draw random variable X
        y[n] = draw_Y               # Draw random variable Y
    p = pcc.pcc (x,y)               # Compute PCC(X,Y) estimate
    print ("PCC(X,Y) = %lf" % p[0][0])    # Print PCC estimate
    ...

Second form: Args: x (list of N floats, N>1): N-points sample of random variable X y (list of K lists of N floats, N>1): K different N-points samples of random variables Y0,Y1,...,YK-1

Returns:
    [[p0 p1...]]: where pi (float) is the PCC estimate of random variables
        X and Yi

Example:
    import pcc
    ...
    x = [0]*N                         # X sample
    y = [[0]*N for k in range(K)]     # Yk samples, 0<=k<K
    p = [[0]*K]                       # K PCC estimates
    for n in range (N):               # For N draws
        x[n] = draw_X                 # Draw random variable X
        for k in range (K):           # For K random variables Yk
            y[k][n] = draw_Y (k)      # Draw random variable Yk
    p = pcc.pcc (x,y)                 # Compute PCC(X,Yk) estimates, 0<=k<K
    for k in range (K):               # For K PCC estimates
        print ("PCC(X,Y%d)=%lf" % (k,p[k][0])) # Print PCC estimates
    ...

Third form: Args: x (list of N lists of L floats, N>1): N-points sample of vector random variable X y (list of N floats, N>1): N-points sample of random variable Y

Returns:
    [[p0 p1...]]: where pi (float) is the PCC estimate of random variables
        X[i] (component i of vector X) and Y

Example:
    import pcc
    ...
    x = [[0]*L for n in range(N)]   # X sample
    y = [0]*N                       # Y sample
    p = [[0]*L]                     # PCC estimate
    for n in range (N):             # For N draws
        for l in range (L):         # For L components
            x[n][l] = draw_X (l)    # Draw component of random variable X
        y[n] = draw_Y               # Draw random variable Y
    p = pcc.pcc (x,y)               # Compute PCC(X,Y) estimate
    for l in range (L):             # For L components
        print ("PCC(X,Y)[%d] = %lf" % (l,p[l][0])) # Print component of PCC estimate
    ...

Fourth form: Args: x (list of N lists of L floats, N>1): N-points sample of vector random variable X y (list of K lists of N floats, N>1): K different N-points samples of random variables Y0,Y1,...,YK-1

Returns:
    [[p00 p01...] [p10 p11...]...]: where pji is the PCC estimate of random
        variables X[i] (component i of vector X) and Yj

Example:
    import pcc
    ...
    x = [[0]*L for n in range(N)]   # X sample
    y = [[0]*N for k in range(K)]   # Yk samples, 0<=k<K
    p = [[0]*L for k in range(K)]   # PCC estimate
    for n in range (N):             # For N draws
        for l in range (L):         # For L components
            x[n][l] = draw_X (l)    # Draw component of random variable X
        for k in range (K):         # For K random variables Yk
            y[k][n] = draw_Y (k)    # Draw random variable Yk
    p = pcc.pcc (x,y)               # Compute PCC(X,Y) estimate
    for k in range (K):             # For K PCC estimates
        for l in range (L):         # For L components
            print ("PCC(X,Y%d)[%d] = %lf" % (k,l,p[k][l])) # Print component of PCC estimate
    ...

Raises: TypeError: x,y lengths mismatch (first form) TypeError: x,y-sub-lists lengths mismatch (second form) TypeError: x not list of floats and not list of lists of floats TypeError: y not list of floats and not list of lists of floats ValueError: length of x < 2 ValueError: x variance estimate=0 (constant x?) ValueError: y variance estimate=0 (constant y?)

Note: The second and fourth forms are equivalent to: p = map(lambda z:pcc.pcc(x,z),y) but are much more efficient.