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
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:
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.