import numpy as np
%matplotlib inline
from matplotlib import pyplot as pl
zhash=np.load("../TPX/select_commun.npz",allow_pickle=True)#['arr_0']
zhash=zhash.get('arr_0').reshape(1)[0]
cname='Salerno'
#zhash=zhash.get('arr_0').reshape(1)[0]
pl.plot(zhash[cname],'+')
pl.xlabel('days')
pl.ylabel('positives')
pl.title(cname)
Poissonovská veličina se řídí rozdělením $$P(j)=\frac{\lambda(x)^j}{j!}\ \exp(-\lambda(x)),$$
kde $\lambda(x)$ je její očekávaná hodnota (závisí na nějaké další veličině $x$).
Pokud pro sadu bodů $x_i,j_i$ ($i=1-N$) máme model $\lambda(x_i)$, logaritmus věrohodnosti pak vychází
$$\log L = \sum_i \log P (j_i) = \sum_i j_i \log(\lambda(x_i)) - \sum \log(j_i !) - \sum \lambda(x_i)$$
Parametry modelu $\lambda(x)$ pak hledáme derivací této funkce (prostřední člen na $\lambda$ nezávisí, můžeme ho dále vynechat). Předpokládejme kvadratickou závislost $\lambda(x|p_k)=p_0+p_1\ x+p_2\ x^2$
Hledáme teď řešení soustavy $$\sum_i \frac{j_i\ x_i^k}{\lambda(x_i|p_k)} = \sum_i x_i^k$$
Analytické řešení se zdá být obtížné (parametry jsou ve jmenovateli, přesněji $n$ jmenovatelích v sumě vlevo), ne-li nemožné, proto použijeme obecnou numerickou minimalizační metodu.
from scipy import optimize as op
j=zhash[cname]
x=np.r_[:len(j)]
pini=[1,5,3]
lig_ml=lambda p:-(j*np.log(abs(np.polyval(p[::-1],x)))).sum()+np.polyval(p[::-1],x).sum()
par1=op.fmin(lig_ml,pini)
par1
Můžeme se pokusit nafitovat tutéž funkci pomocí nejmen. čtverců, což odpovídá předpokládu normálního rozdělení dat. Minimalizujeme zde veličinu $$S=(J-A P)^T\ (J-A P),$$ kde $J$ je vektor měření a modelová matice (design matrix) $$A=\left(\begin{matrix} 1 & x_1 & x_1^2 \\ 1 & x_2 & x_2^2 \\ & \dots & \\ \\ 1 & x_n & x_n^2\end{matrix} \right).\label{desmat} $$ Řešení podmínky pro derivaci podle parametrů $P$ je dáno $\hat P = H^{-1} A^T\ J$, kde $H$ je čtvercová matice $A^T\ A$ (Hessian).
Numericky vychází odhad parametrů takto:
amat=np.array([np.ones_like(x),x,x**2]).T
hess=amat.T@amat
par2=np.linalg.inv(hess)@amat.T@j
par2
Výsledek se výrazně liší od prvního odhadu, problém je ovšem ve výrazné korelaci parametrů (koeficientů polynomu). Inverzní Hessian je úměrný kovarianční matici, korelační z ní určíme normalizací diagonály:
cov=np.linalg.inv(hess)
err=np.sqrt(cov.diagonal())
cor=cov/err[np.newaxis,:]/err[:,np.newaxis]
cor
Je vidět, že korelační koeficient dosahuje až 96% - jde tady o antikorelaci, tedy zvyšování jednoho koeficientu je dobře kompenzováno sni
Ve skutečnosti se od sebe modelové funkce příliš neliší - pod 3 procenta rozsahu dat $J$.
model1=amat@par1
model2=amat@par2
max(abs(model2-model1)), max(j)-min(j)
Korektní nahrazení poisson. rozdělení pomocí normálně rozdělených proměnných musímě vzít v úvahu proměnný rozptyl: $D(J)=E(J)=\lambda(x)$. V odhadu $P$ se tedy objeví váhová matice W, inverzní ke kovarianční $J$, zde diagonální $W_{ii}=1/D(j_i)$
Pak dosadíme $ H=A^T\ W\ A$ do odhadu $\hat P = H^{-1} A^T\ W\ J$ (je dobré si všimnout, že výsledek nezávisí na normalizaci matice W, můžeme nejistoty měření v jednotlivých bodech znát jen relativně). Odhady i modely se od "poissonovského" výsledku liší jen o necelých 5, tedy méně než jedno procento.
wmat=np.eye(len(j))
wmat[x,x]=1/j #diagonala
hess3=amat.T@wmat@amat
par3=np.linalg.inv(hess3)@amat.T@wmat@j
par3
model1=amat@par1
model3=amat@par3
pl.plot(x,model1, label="Poisson")
pl.plot(x,model3, label="LSM")
pl.plot(x,j,'+',label="data")
pl.legend()
max(abs(model3-model1))
Rozdíl mezi oběma fity už na grafu není viditelný.
Korelace lze v případě fitování polynomem výrazně omezit jednoduchým trikem (pokud je nezávislá proměnná $x$ vzorkována rovnoměrně): posuneme-li počátek doprostřed intervalu hodnot $x$, všechny korelace koeficientů u sudé a liché mocniny budou blízké nule. Je totiž $\sum_i (x_i-x_m)^{2k+1}=0$ při sčítání přes interval symetrický kolem $x_m$. Za těchto podmínek jsou liché a sudé sloupce modelové matice navzájem otrogonální.
xb=x-x.mean()
amatb=np.array([np.ones_like(xb),xb,xb**2]).T
hessb=amatb.T@amatb
par2b=np.linalg.inv(hessb)@amatb.T@j
par2b
covb=np.linalg.inv(hessb)
errb=np.sqrt(covb.diagonal())
corb=covb/errb[np.newaxis,:]/errb[:,np.newaxis]
corb
Omezení korelací způsobí zkrácení elips "ekvipotenciálních" kontur minimalizované funkce (viz demonstrace u fitování Drudeho modelu), což výrazně zmenší i velikost nejistot (hodnoty na diagonále kovarianční matice):
print("nejistoty bez posunuti: ",err)
print("nejistoty po posunuti: ",errb)
Obě modelové křivky (a tedy i hodnoty reziduí či jejich sumy) jsou samozřejmě identické - v obou případech fitujeme parabolu za stejných podmínek (stejné minimalizované veličiny). Rozdíl je na úrovni zaokrouhlovací chyby:
model2=amat@par2
model2b=amatb@par2b
max(abs(model2-model2b))
xb=x-x.mean()
lig_ml=lambda p:-(j*np.log(abs(np.polyval(p[::-1],xb)))).sum()+np.polyval(p[::-1],xb).sum()
par1b=op.fmin(lig_ml,par2b)
par1b
hess3b=amatb.T@wmat@amatb
par3b=np.linalg.inv(hess3b)@amatb.T@wmat@j
par3b
Pokud započítáme "poissonovské" váhy, korelace jsou o poznání větší - ortogonalita už není splněna při aplikaci wmat
. Jednotlivé sloupce modelové matice by se daly ortogonalizovat obvyklými matematickými postupy s případným započtením váhy (je známo hodně ortogonálních sad polynomů), ve výsledku ale bude průběh modelové funkce stejný (a určované parametry ztratí svůj zjevný smysl).
cov3b=np.linalg.inv(hess3b)
err3b=np.sqrt(cov3b.diagonal())
cor3b=cov3b/err3b[np.newaxis,:]/err3b[:,np.newaxis]
cor3b