Korelace 2 proměnných

po převedení na standardiz. proměnné $X_m=(X-E(X))/\sqrt{V(X)}$

dostáváme korelační koef. $r=X_m Y_m$

udává i sklon regresní přímky (bez standardizace je to poměr $cov(X,Y)/V(X)$). Nejistota $V(\hat r)=V(Y)/(N V(X))$

simulujeme N=2000 opakování normálně rozdělených dat, vykreslíme ve scatter plotu i pro kernel density estimate (KDE)

In [1]:
%pylab inline

import numpy as np
from scipy import stats
def measure(n,frac=0.5):
     "Measurement model, return two coupled measurements."
     l1 = np.random.normal(size=n)
     l2 = np.random.normal(scale=0.5, size=n)
     return l1+frac*l2, frac*l1-l2

m1, m2 = measure(2000)
xmin = m1.min()
xmax = m1.max()
ymin = m2.min()
ymax = m2.max()
plot(m1,m2,'.')
Populating the interactive namespace from numpy and matplotlib
Out[1]:
[<matplotlib.lines.Line2D at 0x7fe189536240>]
In [2]:
#Perform a kernel density estimate on the data:

X, Y = np.mgrid[xmin:xmax:100j, ymin:ymax:100j]
positions = np.vstack([X.ravel(), Y.ravel()])
values = np.vstack([m1, m2])
kernel = stats.gaussian_kde(values)
kdeZ = np.reshape(kernel(positions).T, X.shape)
imshow(kdeZ,origin="lower",extent=[xmin, xmax, ymin, ymax])
Out[2]:
<matplotlib.image.AxesImage at 0x7fe189449b38>
In [3]:
stats.gaussian_kde?

porovnání korelační matice a odhadu z KDE

teoretický rozptyl
$V(m_1)=V(l_1)+f^2 V(l_2)$ = 1+0.25 * 0.25=1.063
$V(m_2)=f^2 V(l_1) + V(l_2)$ = 0.25 + 0.25=0.5

In [14]:
print corrcoef(m1,m2)
r1=m1-m1.mean()
r2=m2-m2.mean()
print (r1*r2).sum()/sqrt((r1**2).sum()*(r2**2).sum()),
print "zname stred:",(m1*m2).sum()/sqrt((m1**2).sum()*(m2**2).sum()),
print "zname sigma:",(m1*m2).sum()/sqrt(0.5*1.0625)/2000
[[ 1.          0.53815875]
 [ 0.53815875  1.        ]]
0.538158747492 zname stred: 0.536260669532 zname sigma: 0.535067486636
In [4]:
kernel.covariance
Out[4]:
array([[ 0.0820134 ,  0.03102003],
       [ 0.03102003,  0.04051154]])
In [5]:
# mensi stupen korelace
n1,n2=measure(2000,0.1)

r1=n1-n1.mean()
r2=n2-n2.mean()

(r1*r2).sum()/sqrt((r1**2).sum()*(r1**2).sum())
Out[5]:
0.084848084672529966

Jaký bude výsledek při opakování pokusu?

teoretické rozdělení (Fisher 1944) $$prob(r|\rho,H) =\frac{(1-\rho^2)^{(N-1)/2} (1-r^2)^{(N-4)/2} }{(1-\rho r)^{N-3/2}} \left( 1+ \frac{1}{N-1/2} \frac{1+\rho r}{8} + \dots \right) $$

poloha maxima z 1. derivace $$-(N/2-2)\frac{(1-\rho^2)^{(N-1)/2} 2 r (1-r^2)^{N/2-3} }{(1-\rho r)^{N-3/2}}+\rho(N-3/2)\frac{(1-\rho^2)^{(N-1)/2} (1-r^2)^{N/2-2} }{(1-\rho r)^{N-1/2}}=0$$

$$-(1-\rho\ r)\ 2 r\ (N/2-2) + (1-r^2)\ \rho\ (N-3/2) = 0$$
$$r^2\ \rho /2 - r\ (N-4) - \rho\ (N-3/2) =0$$
In [6]:
tefun=lambda r,rho,N:pow(1-rho**2,(N-1)/2.)*pow(1-r**2,(N-4)/2.)/pow(1-rho*r,N-1.5)*(1+(1+rho*r)/8./(N-0.5))

n1,n2=10,20

cores=r_[[corrcoef(*measure(n1,0.5))[1,0] for i in range(200)]]
h1=hist(cores,20,alpha=0.5)
cores2=r_[[corrcoef(*measure(n2,0.5))[1,0] for i in range(200)]]
h2=hist(cores2,h1[1],alpha=0.5)
rd=np.r_[-0.5:1:0.05]
v1=tefun(rd,0.5,n1)
plot(rd,v1/v1.sum()*200)
v2=tefun(rd,0.5,n2)
plot(rd,v2/v2.sum()*200)
v1.max(),v2.max()
Out[6]:
(1.516547153689749, 1.4083729388131005)
In [7]:
from scipy.integrate import quad
qlist=[.25,.5,.75]
cnorm=[[quad(lambda x:tefun(x,q,i),-0.999,0.999)[0] for i in range(2,30)] for q in qlist]
cmids=[[quad(lambda x:tefun(x,q,i),0,0.999)[0] for i in range(2,30)] for q in qlist]

podle teoret. rozdělení určíme pravděpodobnost, že hodnota $r$ překročí jistou mez (0, 0.5) pro danou hodnotu $\rho$

In [8]:
cquant=array(cmids)/array(cnorm)
[plot(range(2,30),c) for c in cquant]
legend(qlist,loc=4)
xlabel("velikost vzorku")
ylabel("prst. nezapornosti r")
Out[8]:
<matplotlib.text.Text at 0x3540850>
In [9]:
clev1=[[quad(lambda x:tefun(x,q,i),0.5,0.999)[0] for i in range(2,30)] for q in qlist]
[plot(range(2,30),c) for c in array(clev1)/array(cnorm)]
legend(qlist,loc=4)
xlabel("velikost vzorku")
ylabel("prst. r>0.5")
Out[9]:
<matplotlib.text.Text at 0x3e82710>

podle Wolfram Mathworld

$$E(r)=\rho - \frac{\rho(1-\rho^2)}{2n}$$$$V(r)=\frac{(1-\rho^2)^2}{n}(1+\frac{11 \rho^2}{2n})$$
In [26]:
n1,n2=10,20

rm1,rm2=0.5-0.5*(1-0.25)/(2*n1),0.5-0.5*(1-0.25)/(2*n2)
print "střední hodnota - teorie: ",rm1,rm2
print "simulace:"
sum(rd*v1)/v1.sum(),sum(rd*v2)/v2.sum()
střední hodnota - teorie:  0.48125 0.490625
simulace:
Out[26]:
(0.48038841786488023, 0.48999064263872694)
In [25]:
print "směrod. odchylka - teorie: ",sqrt((1-0.25)**2/n1*(1+11*0.25/2./n1)),sqrt((1-0.25)**2/n2*(1+11*0.25/2./n2))
print "simulace:"
sqrt(sum((rd-rm1)**2*v1)/v1.sum()),sqrt(sum((rd-rm2)**2*v2)/v2.sum())
směrod. odchylka - teorie:  0.252951329311 0.173374143834
simulace:
Out[25]:
(0.26363860623629282, 0.17797754501211949)

Máme-li jen jedno měření, lze odhadnout směrodatná odchylka určovaného $r$ ze vzorku podle vztahu $$\sigma_r=\frac{1-r^2}{\sqrt{n-1}}$$

Při testování nulové hypotézy ($\rho=0$) lze použít transformaci na proměnnou $$t=r \frac{\sqrt{n-2}}{\sqrt{1-r^2}}$$ která má Studentovo rozdělení s $n-2$ stupni volnosti (původní proměnná $r$ má pro $\rho=0$ rozdělení $prob(r)= (1-r^2)^{N/2-2}$).

In [45]:
n1,n2=10,20
t=cores/sqrt(1-cores**2)*sqrt(n1-2)
t2=cores2/sqrt(1-cores2**2)*sqrt(n2-2)
qa,qb,cx=hist(t,20,alpha=0.5)
qa2,qb,cx2=hist(t2,qb,alpha=0.5)
print '10 samp.:',t.mean(),t.std()
print '20 samp.:',t2.mean(),t2.std()
10 samp.: 2.00453911922 1.41956398276
20 samp.: 2.55959503776 1.17600364094

Vynesené histogramy samozřejmě neodpovídají Studentovu rozdělení, které má střední hodnotu 0 (mohou být srovnána s necentrálním Studentovým rozdělením, které má složitější tvar).

provádíme Studentův test (isf = inverse survival function dává kvantil $P(\alpha)$)

In [41]:
from scipy import stats
tlim=stats.t(n1-2).isf(0.05)
tlim,sum(t>tlim)/200.
Out[41]:
(1.8595480375228428, 0.48999999999999999)
In [22]:
tlim2=stats.t(n2-2).isf(0.05)
tlim2,sum(t2>tlim2)/200.
Out[22]:
(1.7340636066175357, 0.88)

Příklad

V prvním případě (korelace určené z 10 bodů) můžeme 'nulovou hypotézu' vyloučit v polovině případů, při určování korelací z 20 bodů už v 88 procentech.

bootstrap z jednoho pokusu

bootstrap = náhodné výběry s opakováním ze stále téhož vzorku (simulace opakování měření)

In [42]:
ms=measure(20)
plot(ms[0],ms[1],'o')
Out[42]:
[<matplotlib.lines.Line2D at 0xae68954c>]
In [43]:
array(ms)
Out[43]:
array([[-0.77841408,  0.03454069, -1.79899753,  2.6222784 ,  0.63986075,
        -0.87700664, -1.26332108, -0.8353549 ,  0.24776914,  0.00467435,
         0.81616138,  2.04825502,  0.74176523, -2.47762032, -1.41996646,
         1.72124518, -0.8370706 , -1.7750684 , -0.23498758,  0.7306629 ],
       [-0.34831945,  0.13939541, -0.96261126,  0.8360406 ,  0.10520864,
        -0.26646201, -0.89675214,  0.64380745,  0.25353027,  0.38875257,
         1.15674848, -0.16074746,  0.71530618, -1.22475345, -0.36005832,
        -0.59058315, -0.33944503, -0.02032342, -1.29055216, -0.35020398]])
In [44]:
rho=corrcoef(array(ms))[1,0]
print rho,rho*sqrt(18/(1-rho**2))
array(ms)[:,randint(0,20,20)]
0.508292526035 2.50411218838
Out[44]:
array([[ 2.6222784 , -0.8353549 ,  0.03454069,  0.00467435, -0.87700664,
        -2.47762032,  0.81616138,  0.74176523, -1.41996646,  0.81616138,
         0.63986075, -1.79899753,  0.63986075, -0.23498758, -0.87700664,
        -1.26332108,  0.81616138, -0.8370706 , -2.47762032,  0.24776914],
       [ 0.8360406 ,  0.64380745,  0.13939541,  0.38875257, -0.26646201,
        -1.22475345,  1.15674848,  0.71530618, -0.36005832,  1.15674848,
         0.10520864, -0.96261126,  0.10520864, -1.29055216, -0.26646201,
        -0.89675214,  1.15674848, -0.33944503, -1.22475345,  0.25353027]])
In [39]:
bset=[corrcoef(array(ms)[:,randint(0,20,20)])[1,0] for i in range(10000)]
In [43]:
hist(bset,20)
mean(bset),sum(r_[bset]<=0)
Out[43]:
(0.49517719255979209, 285)

t-transformace

převádí blíže normálnímu rozdělení

In [48]:
tset=r_[bset]*sqrt(18/(1-r_[bset]**2))
hist(tset,20)
tset.mean(),tset.std()
Out[48]:
(2.7637303676259606, 1.6219119416777574)

srovnání s jiným vzorkem ($\rho=0$)

In [52]:
# srovnavaci test
ms2=measure(20,0.)
bset2=[corrcoef(array(ms2)[:,randint(0,20,20)])[1,0] for i in range(10000)]
In [55]:
hist(bset2,20)
rho2=corrcoef(array(ms2))[1,0]
print rho2,rho2*sqrt(18/(1-rho2**2))
-0.182529241447 -0.787637969372
In [56]:
tset2=r_[bset2]*sqrt(18/(1-r_[bset2]**2))
hist(tset2,20)
tset2.mean(),tset2.std()
xlabel("t-hodnota")
Out[56]:
(-0.81980297180502637, 1.0883326729397584)

alternativně Spearman rank test

$$ r_s= 1-\frac{6 \sum d_i^2}{n(n^2-1)}$$

ilustrace

bližší konceptu maximální korelace

$$\sum (n-2i)^2 =n^2-4\frac{n(n+1)}{2}+4\frac{n\ K(n+1)}{2}$$