Analýza Gaussovy křivky

nalezení středu rozdělení (předpoklad normálnosti) s odhadem nejistot

předpokládáme profil histogramu BEZ POZADÍ $$D \exp(-(x-\mu)^2/(2\sigma^2)),$$ po zlogaritmování dostáváme polynom 2. řádu

$$\log D -\mu^2/(2\sigma^2) + x \mu/\sigma^2 - x^2 /(2\sigma^2)$$

pro nafitování polynomem $\sum_{i=0}^2 p_i x^i$ dostaneme pro parametry gausovky

$$\sigma^2=-\frac{1}{2 p_2} \\ \mu=-\frac{p_1}{2 p_2} \\ \log D = p_0 + \frac{p_1^2}{4 p_2}$$

Problémem polynomu v zákl. tvaru jsou silné korelace mezi parametry $p_i$.
Otázka korelace je řešena ortogonalizací polynomů, viz http://nymeria.physics.muni.cz/face/praxis/doc/mmzm_ortopolynom/.

nalezení ortonormálních polynomů

ortogonalizace na intervalu <-1,1>

$$\int_{-1}^1{g_i(x) g_j(x) d x} = \delta_{ij}$$

(6 rovnic) dá renorm. Legendrovy polynomy

$$g_0=\sqrt{1/2} \\ g_1=\sqrt{3/2}x \\ g_2=\sqrt{5/8} (3x^2-1)$$

Pozn.: někdy uváděná dodatečná normaliz. podmínka $$\int_{-1}^1{g_i(x) d x} = 0$$ vyplyne z předchozího pro $j>0$, pokud $g_0=\rm{const}$ .


In [2]:
%pylab inline
a,b=[2,4.]
y=r_[a:b:41j]
x=2*y/(b-a) - (a+b)/(b-a)
def mat_Leg(x):
    g_0=sqrt(1/2.)*ones(x.shape)
    g_1=sqrt(3/2.)*x
    g_2=sqrt(5/8.)*(3*x**2-1)
    return r_[[g_0,g_1,g_2]]


Populating the interactive namespace from numpy and matplotlib

aplikace na lib. interval $(a,b)$ lze provést transformací $y=(a+b)/2 + x (b-a)/2$, resp. dosazením $x=2y/(b-a) - (a+b)/(b-a) = y c - d$: $$h_1 = \sqrt{3/2} (yc-d)\\ h_2 = \sqrt{5/8} (3c y^2 - 6cd y +3d^2-1) $$ Najdeme-li (téměř) nekorelované koeficienty $k_i$ pro polynomy $h_i(x)$, koeficienty pro počáteč. polynomy $x^i$ dostaneme maticovými operacemi, kdy zavedeme

$$g_i(x)=\sum_j G_{ij} x^j$$

kde

$$G_{ij}=\left( \begin{array}{ccc} \sqrt{1/2} & 0 & 0 \\ 0 & \sqrt{3/2} & 0 \\ -\sqrt{5/8} & 0 & \sqrt{45/8}\end{array}\right)$$$$h_i(y)=\sum_j G_{ij} (cy-d)^j = \sum_j H_{ij} y^j= \sum_j \sum_k T_{ik} G_{kj} y^j$$

.

Prvky matice $T_{ij}$ vycházejí z kombin. čísel, potom model logaritmu fitované gausovky vychází $f(y) = \sum_i k_i h_i(y)= \sum_i k_i \sum_j \sum_k T_{ik} G_{kj} y^j$, tedy koeficienty $p_j$ dostaneme jako $$p_j= \sum_k \sum_i k_i T_{ik} G_{kj}$$.


In [16]:
# v maticovem zapisu je to jednodussi
matG=sqrt(r_[[[0.5,0,0],[0,1.5,0],[5/8.,0,45/8.]]])
matG[2][0]*=-1
mat_poly2=lambda x:r_[[x**i for i in range(3)]] #obyčejné mocniny
mat_Leg2=lambda x:dot(matG,mat_poly2(x)) #Legendrovy polynomy

In [4]:
[plot(y,a) for a in mat_Leg2(x)]
title("prvni tri Legendrovy polynomy")
grid()



In [9]:
# transformacni matice polynomu pri presunu intervalu
def mat_trans(c,d,n=2):
    rep=[[1]+[0]*n]
    from scipy.misc import comb
    clin=c**r_[:n+1]
    dlin=d**r_[n:-1:-1]
    for i in range(1,n+1):
        #lin=[factorial(i)/factorial(j)/factorial(i-j)*(c**j)*(d**(i-j)) for j in range(i)]
        lin=comb(ones(i+1)*i,r_[:i+1])*clin[:i+1]*dlin[-i-1:]
        rep.append(list(lin)+[0]*(n-i))
    return array(rep)
a,b=2,4
F=mat_trans(2/(b-a),-(b+a)/(b-a),2)
F


Out[9]:
array([[ 1.,  0.,  0.],
       [-3.,  1.,  0.],
       [ 9., -6.,  1.]])

Simulace - normálně rozděl. data a rekonstrukce

funkce pokus vrací rekonstruované parametry, kovarianční matici, střední hodnotu a směrod. odchylku a hodnoty histogramu


In [6]:
# generovani normalne rozdel. nahodnych cisel
def pokus(dsize=500,a=2,b=4,step=0.05,full=0):
    data=normal((a+b)/2.,(b-a)/4.,size=dsize) # interval pokryje -2sigma - +2sigma
    z=r_[(a-step/2):(b+step/2):step]
    x=2*z/(b-a) - (a+b)/(b-a)
    A=mat_Leg2((x[1:]+x[:-1])/2)
    #print A.shape
    v,z=histogram(data,z)
    H=dot(A,A.transpose())
    D=inv(H)
    res=dot(D,dot(A,log(v)))
    if full==3: return res,D,data.mean(),data.std(),v,z
    if full==2: return res,D,data.mean(),data.std()
    if full==1: return res,D
    return res

In [7]:
res,D,mu,st,v,z=pokus(dsize=500,full=3,step=0.1)
polres=polyfit((z[:-1]+z[1:])/2.,log(v),2)

In [19]:
zz=(z[:-1]+z[1:])/2.
bar(zz,v,0.1,color='r',alpha=0.3)
a,b=2,4
#xx=2*zz/(b-a) - (a+b)/(b-a)
F=mat_trans(2/(b-a),-(b+a)/(b-a),2)#.transpose()
#m1=mat_poly2(xx)
polym2=mat_poly2(zz)
A=dot(dot(matG,F),polym2)
T=dot(matG,F)
newres=dot(res,T)
newD=inv(dot(T,dot(inv(D),T.transpose())))
newsig=sqrt(newD.diagonal())
newrho=newD/(newsig.reshape(3,1)*newsig.reshape(1,3))
D2=inv(dot(polym2,polym2.transpose()))
sig2=sqrt(D2.diagonal())
rho2=D2/(sig2.reshape(3,1)*sig2.reshape(1,3))
#plot(zz,exp(dot(res,A)),'r',hold=1)
plot(zz,exp(dot(newres,polym2)),'g',hold=1)
print "fit Legend. polynomy (po transformaci):",newres
print "fit mocninami:",polres[::-1]
sig=sqrt(D.diagonal())
print "korelační matice.. \n",D/(sig.reshape(3,1)*sig.reshape(1,3))
print "korelační matice..(po transformaci) \n",newrho
rho2


fit Legend. polynomy (po transformaci): [-16.08968757  13.06549445  -2.15623845]
fit mocninami: [-16.08968757  13.06549445  -2.15623845]
korelační matice.. 
[[ 1.          0.08693164  0.01120797]
 [ 0.08693164  1.          0.19104018]
 [ 0.01120797  0.19104018  1.        ]]
korelační matice..(po transformaci) 
[[ 1.          0.98560734  0.95097407]
 [ 0.98560734  1.          0.98734087]
 [ 0.95097407  0.98734087  1.        ]]
Out[19]:
array([[ 1.        , -0.99514148,  0.98339914],
       [-0.99514148,  1.        , -0.99622942],
       [ 0.98339914, -0.99622942,  1.        ]])

původně nekorelované parametry jsou opět provázány...

opakování simulace - rozdělení rekonstruovaných parametrů


In [32]:
if True: #případně vypneme, pokud chceme ušetřit čas
    rep=[pokus(full=2,step=0.1) for i in range(200)]
    mux,sigx=array([r[2:] for r in rep]).transpose()
    pask1=array([r[0] for r in rep]).transpose()
    plot(pask1[0],pask1[1],'.')
    xlabel("param. 0")
    ylabel("param. 1")



In [23]:
sel=(pask1[0]>0)*(pask1[1]+10>0)*(pask1[2]+10>0)
pask1=pask1[:,sel]
sum(sel)


-c:1: RuntimeWarning: invalid value encountered in greater
Out[23]:
197

In [17]:
plot(mux,sigx,'.')
xlabel('mu')
ylabel('sigma')


Out[17]:
<matplotlib.text.Text at 0x3a16bd0>

In [20]:
corrcoef(mux,sigx)[0,1]


Out[20]:
-0.08716590305947472

korelace mezi odhadem střední hodnoty a rozptylu na úrovni 8%


In [25]:
plot(pask1[0],pask1[2],'.')
print "korelace 1,2:",corrcoef(pask1[2],pask1[1])[0,1]
print "korelace 0,2:",corrcoef(pask1[0],pask1[2])[0,1]


korelace 1,2: 0.0829466115427
korelace 0,2: 0.897925312243

testovací otázka - proč je parametr 0 korelován s 2 ?

(hint: vzorce v úvodu)

přepočet na parametry norm. rozdělení


In [46]:
pask2=dot(pask1.transpose(),T).transpose()
estmu=-pask2[1]/2./pask2[2]
estsigma=-1/pask2[2]
plot(estmu,estsigma,'.')
xlabel('est. mu')
ylabel('est. sigma')


Out[46]:
<matplotlib.text.Text at 0x49af950>

In [49]:
estamp=pask2[0]+pask2[1]**2/4/pask2[2]
plot(estmu,estamp,'.')
estamp.mean(),estamp.std()


Out[49]:
(-33.73252068939432, 4.5105622876492362)

In [58]:
print "korelace urcenych parametru:",corrcoef(estmu,estsigma)[0,1]
(mux.std(),estmu.std()),(sigx.std(),estsigma.std())


korelace urcenych parametru: -0.00136500227817
Out[58]:
((0.022686527533512014, 0.031323047658358014),
 (0.015334608965372086, 0.059549372246621927))

použití knihovních procedur a vah


In [51]:
plot(zz,log(v))
from numpy.polynomial import legendre as pc
legres=pc.legfit(zz,log(v),2,w=sqrt(v),full=True)
legres[1][2]/legres[0]


Out[51]:
array([-0.1059002 ,  0.01558241, -0.00703655])


In [52]:
fval=pc.legval(zz,legres[0])
plot(zz,v,'s')
plot(zz,exp(fval))


Out[52]:
[<matplotlib.lines.Line2D at 0x4ab0050>]

In [54]:
# kde je maximum - kde je prvni derivace nulova
print "střední hodnota:",pc.legroots(pc.legder(legres[0]))[0]


střední hodnota: 3.02394178224