Processing math: 0%
MKZR:Dodatek

Z Skrypty dla studentów Ekonofizyki UPGOW

(Różnice między wersjami)
(Utworzył nową stronę „===Histogramy=== Ważną umiejętnością jest estymacja funkcji gęstości z pewnej (dużej) licznby danych liczbowych. Proces taki jest nazywany hostogramowaniem. …”)
m
 
(Nie pokazano 32 wersji pomiędzy niniejszymi.)
Linia 1: Linia 1:
 +
[[Category:MKZR|100]]
 +
=== Wektoryzacja obliczeń w środowsku matlab/GNU Octave ===
 +
 +
Matlab/GNU Octave są językami interpretowanymi. W znacznym stopniu ułatwia to przejście do sedna rozwiązywanego problemu z pominięciem wielu informatycznych aspektów programowania. Jednak ceną za taki komfort jest często wydajność pisanych programów. W przypadku ogólnym bezpośrednie przepisanie kodu w języku typu Fortran czy C/C++ na matlab może spowolnić jego działanie kilkaset razy. Stosując jednak języki interpretowane świadomie i wykorzystując ich możliwości w wielu przypadkach można uniknąć spowolnienia i otrzymać bardzo wydajny program.
 +
 +
Podstawowym elementem języka wykorzystywanym w jest pętla "for". Rozważmy następujący program:
 +
 +
 +
<source lang='matlab'>
 +
N=15000;
 +
x=linspace(0,2*pi,N);
 +
tic;
 +
for i=2:N
 +
  x(i)=x(i)*0.1;
 +
endfor
 +
toc
 +
</source>
 +
 +
Inicjalizujemy wektor x zawierający punkty jednorodnie położone na odcinku <math>(0,2 \pi)</math>. Chcemy pomnożyć każdą ze współrzędnych przez 0.1. Powyższy program wykonuje to za pomocą pętli for. Jest to poprawny sposób wykonania tego zadania. Instrukcje tic/toc mierzą czas wykonania wszystkich komend pomiędzy nimi. Na typowym komputerze PC wynosi on ok 0.2 sekundy.
 +
 +
Wykonajmy identyczną operację w sposób który umożliwia nam śwodowisko matlab/GNU Octave. Operator mnożenia jest zdefiniowany nie tylko na liczbach, ale również na wektorach. Możeme więc zapisać:
 +
 +
<source lang='matlab'>
 +
N=15000;
 +
x=linspace(0,2*pi,N);
 +
tic
 +
x=0.1*x;
 +
toc
 +
</source>
 +
 +
Przy takim sposobie zapisu czas wykonania jest rzędu 0.001 sekundy.
 +
 +
Rozważmy teraz trochę bardziej skomplikowany problem. Majać wektor z wartosciami pewnej funkcji na odcinku chcemy policzyć pochodna korzystając ze wzroru na iloraz różnicowy. Kod napisany z użyciem pętli for może wyglądać tak:
 +
 +
<source lang='matlab'>
 +
N=15000;
 +
x=linspace(0,2*pi,N);
 +
z=sin(x);
 +
h=2*pi/N;
 +
 +
tic
 +
for i=2:N
 +
  diffz(i)=(z(i)-z(i-1))/h;
 +
endfor
 +
toc
 +
 +
diffz(1)=diffz(2);
 +
plot(x,z,x,diffz)
 +
</source>
 +
 +
a czas jego  wykonania będzie również rzędy 0.2 sekundy. By napisać program wektorowy warto zapoznać sie z funkcja przesuwającą index w wektorze "shift".
 +
<source lang='matlab'>
 +
octave:142> shift([1,2,3],1)
 +
ans =
 +
 +
  3  1  2
 +
</source>
 +
 +
Dysponując taką funkcję można wektorowo zapisać żądaną operacje w poniższy sposób:
 +
 +
<source lang='matlab'>
 +
x=linspace(0,2*pi,N);
 +
z=sin(x);
 +
h=2*pi/N;
 +
tic
 +
for i=2:N
 +
  diffz(i)=(z(i)-z(i-1))/h;
 +
endfor
 +
 +
toc
 +
diffz(1)=diffz(2);
 +
tic
 +
 +
diff2z=(z-shift(z,1))/h;
 +
toc
 +
plot(x,z,x,diff2z)
 +
 +
</source>
 +
 +
 +
Czas wykonania takiego programu jest znacząca krótszy i wynosi ok 0.01 sekundy.
 +
===Histogramy===
===Histogramy===
-
Ważną umiejętnością jest estymacja  funkcji gęstości z pewnej (dużej) licznby danych liczbowych. Proces taki jest nazywany hostogramowaniem.  
+
Ważną umiejętnością jest estymacja  funkcji gęstości z pewnej (dużej) liczby danych. Proces taki jest nazywany histogramowaniem.  
 +
 
 +
Histogram jest to sposób przedstawienia częstości występowania pewnej cechy w postaci wykresu słupkowego. Weźmy na przykład ciągłą zmienną losową. Podzielmy przestrzeń wartości przyjmowanych przez tą zmienna na N równych przedziałów. Przypuścmy, że dysponumemy M realizacjami zmiennej losowej. Na histogramie można umieścić liczbę realizacji, które należa do danego przedziału. Co więcej taki wykres bedzie w granicy <math>N,M\to \infty</math> taki sam jak wykres gęstości prawdopodobieństwa nasze zmiennej losowej.
 +
By  otrzymać dokładnie gęstość prawdopodobieństwa trzeba przeskalować liczbę zliczeń do gęstości. Niech <math>n_i, i=1..N</math> będą zliczeniami w kolejnych przedziałach. 
 +
Gęstość prawdopodobieństwa  jest unormowana do jedności (bierzemy zmienną losową przyjmującą wartości między a i b):
 +
 
 +
<math>1=\int_a^b f(x) dx=\sum_{i=1}^N f(x_i) h</math>
 +
 
 +
gdzie h jest szerokością jednego przedziału <math>h=(x_i-x_{i-1})/(N-1)</math>.
 +
Wynika z tego, że
 +
 
 +
<math>\sum_{i=1}^N f(x_i) =1/h</math>,
 +
 
 +
podczas gdy liczby zliczeń są unormowane do pewnej wartości <math>\sum_{i=1}^N n_i </math>.
 +
 
 +
Widać z tego, że formuła łącząca liczby zliczeń z wartościami gęstości wewnątrz odcinków
 +
wyraża się:
 +
 
 +
<math>f_i=f(x_i)=\frac{1}{h}\frac{n_i}{\sum_{i=1}^N n_i} </math>.
 +
 
 +
W systemie GNU Octave wbudowana funkcja '''hist''' umożliwia podanie drugiego argumentu, który jest czynnikiem normalizacyjnym sumy wszystkich zliczeń i w rozważanym przypadku powinien od wynosić 1/h.
 +
 
 +
====Histogramy 1D====
 +
 
 +
Jako przykład wykonajmy histogram 10000 liczb o rozkładzie normalnym i porównajmy go ze wzrorem analitycznym na funkcję Gaussa.  Najprostszy skrypt w GNU Octave realizujący to zadanie to:
 +
 
 +
<source lang='matlab'>
 +
xmax=5;
 +
h=0.1;
 +
mydata=normrnd (0,1,10000,1);
 +
hist(mydata,[-xmax:h:xmax],1/h);
 +
</source>
 +
 
 +
Zauważmy, że:
 +
 
 +
Nie została zadana liczba przedziałow, ale szerokość. Liczba przedziałow w tym przypadku to:
 +
<source lang='matlab'>
 +
octave:38> length( [xmin:h:xmax] )
 +
ans =  101</source>
 +
 
 +
Pomimo, ze zmienna losowa przyjmuje wartości na całej osi rzeczywistej, to histogram wykonaliśmy na skończonym przedziale. Wybranie wartości x a przedziału -5..5 jest w przypadku rozkładu Gaussa dobrym wyborem. Zauważmy jest stosunek funkcji gęstości w punktach 0 i 5 wynosi
 +
<source lang='matlab'>octave:42> normpdf(0,0,1)/normpdf(5,0,1)
 +
ans =  2.6834e+05
 +
</source> więc dla 10000 punktów możemy się spodziewać, że zaden z nim nie wyjdzie poza przedział -5...5.
 +
:''Proszę sprawdzić jak będzie wyglądał histogram jeśli weżmiemy xmin=-1 i xmax=1
 +
''
 +
Funkcja '''hist''' została wywołana bez argumentów zwrotnych i zgodnie z dokumentacja narysowała ona wykres. Można postąpić inaczej:
 +
 
 +
<source lang='matlab'>
 +
xmax=5;
 +
h=0.1;
 +
mydata=normrnd (0,1,10000,1);
 +
[NN,XX]=hist(mydata,[-xmax:h:xmax],1/h);
 +
</source>
 +
Podając argumenty zwrotne funkcja hist zamiast rysować wykres, zwraca wektor liczb zliczeń i wartość zmiennej w przedziałach. Można to wykorzystać: 
 +
<source lang='matlab'>
 +
plot(XX,NN,"-",XX,normpdf(XX,0,1),"r-")
 +
bar(XX,NN)
 +
</source>
 +
 
 +
=====Jak działa funkcja hist?=====
 +
 
 +
Poniższy kod ilustruje prostą implementacje funkcji histogramującej w GNU/Octave. Nie jest ona efektywna, gdyż wykorzystuje pętlę po wszystkich danych wejściowych (kod nie jest wektorowy).
 +
 +
<source lang='matlab'>
 +
xmax=5;
 +
xmin=-5;
 +
h=.1;
 +
XX=[xmin:h:xmax];
 +
mydata=normrnd (0,1,10000,1);
 +
NN=zeros(1,101);
 +
for i=1:length(mydata)
 +
idx=  ceil ( (mydata(i)-xmin)/(xmax-xmin) * length(NN)  ) ;
 +
if idx>0 && idx<=length(NN)
 +
NN(idx)++;
 +
endif
 +
endfor
 +
plot(XX,NN)
 +
</source>
 +
 
 +
====Histogramy 2D====
 +
[[Plik:Gauss2d.png|thumb|360px|Estymacja gęstości dla dwów nielależnych zmiennych losowych Gaussowskich za pomocą funkcji hist2d.]]
 +
 
 +
Podobnie jak w przypadku jednej zmiennej losowej, histogram można utworzyć dla wielu zmiennych losowych. Do celów wizualizacyjnych nadaje się jednak tylko przypadek dwuwymiarowy. W sysemie GNU/Octave nie ma bezpośrednio wbudowanej funkcji histogramującej dwie zmienne losowe, ale jest pakiet rozszerzający '''plot''' (dostępny z [http://octave.sourceforge.net/]). Po zciągnieciu pliku instalujemy go za pomocą
 +
<source lang='matlab'>
 +
pkg install 'plot-1.0.8.tar.gz'
 +
</source>
 +
 
 +
 
 +
Z jego pomoca narysujemy histogram dwoch niezależnych gausowskich zmienych  losowych:
 +
 
 +
 
 +
<source lang='matlab'>
 +
hist2d(normrnd(0,1,250000,2),60);
 +
</source>
-
===Histogramy 1D===
+
Podobnie jak w przypadku funkcji '''hist''' można dane zapisać do tablic by np. użyć innej procedury rysującej:
-
===Histogramy 2D===
+
<source lang='matlab'>
 +
[nn,x,y]=hist2d(normrnd(0,1,134100,2),60);
 +
imagesc(nn)
 +
</source>
-
===Rysunki===
+
[[Plik:Gauss2da.png|thumb|360px|Estymacja gęstości dla dwów nielależnych zmiennych losowych Gaussowskich za pomocą funkcji hist2d, dane przedstawione za pomocą imagesc.]]

Aktualna wersja na dzień 15:20, 23 sty 2011

Spis treści

[ukryj]

Wektoryzacja obliczeń w środowsku matlab/GNU Octave

Matlab/GNU Octave są językami interpretowanymi. W znacznym stopniu ułatwia to przejście do sedna rozwiązywanego problemu z pominięciem wielu informatycznych aspektów programowania. Jednak ceną za taki komfort jest często wydajność pisanych programów. W przypadku ogólnym bezpośrednie przepisanie kodu w języku typu Fortran czy C/C++ na matlab może spowolnić jego działanie kilkaset razy. Stosując jednak języki interpretowane świadomie i wykorzystując ich możliwości w wielu przypadkach można uniknąć spowolnienia i otrzymać bardzo wydajny program.

Podstawowym elementem języka wykorzystywanym w jest pętla "for". Rozważmy następujący program:


N=15000;
x=linspace(0,2*pi,N);
tic;
for i=2:N
   x(i)=x(i)*0.1;
endfor
toc

Inicjalizujemy wektor x zawierający punkty jednorodnie położone na odcinku . Chcemy pomnożyć każdą ze współrzędnych przez 0.1. Powyższy program wykonuje to za pomocą pętli for. Jest to poprawny sposób wykonania tego zadania. Instrukcje tic/toc mierzą czas wykonania wszystkich komend pomiędzy nimi. Na typowym komputerze PC wynosi on ok 0.2 sekundy.

Wykonajmy identyczną operację w sposób który umożliwia nam śwodowisko matlab/GNU Octave. Operator mnożenia jest zdefiniowany nie tylko na liczbach, ale również na wektorach. Możeme więc zapisać:

N=15000;
x=linspace(0,2*pi,N);
tic
x=0.1*x;
toc

Przy takim sposobie zapisu czas wykonania jest rzędu 0.001 sekundy.

Rozważmy teraz trochę bardziej skomplikowany problem. Majać wektor z wartosciami pewnej funkcji na odcinku chcemy policzyć pochodna korzystając ze wzroru na iloraz różnicowy. Kod napisany z użyciem pętli for może wyglądać tak:

N=15000;
x=linspace(0,2*pi,N);
z=sin(x);
h=2*pi/N;
 
tic
for i=2:N
   diffz(i)=(z(i)-z(i-1))/h;
endfor
toc
 
diffz(1)=diffz(2);
plot(x,z,x,diffz)

a czas jego wykonania będzie również rzędy 0.2 sekundy. By napisać program wektorowy warto zapoznać sie z funkcja przesuwającą index w wektorze "shift".

octave:142> shift([1,2,3],1)
ans =
 
   3   1   2

Dysponując taką funkcję można wektorowo zapisać żądaną operacje w poniższy sposób:

x=linspace(0,2*pi,N);
z=sin(x);
h=2*pi/N;
tic
for i=2:N
   diffz(i)=(z(i)-z(i-1))/h;
endfor
 
toc
diffz(1)=diffz(2);
tic 
 
diff2z=(z-shift(z,1))/h;
toc
plot(x,z,x,diff2z)


Czas wykonania takiego programu jest znacząca krótszy i wynosi ok 0.01 sekundy.

Histogramy

Ważną umiejętnością jest estymacja funkcji gęstości z pewnej (dużej) liczby danych. Proces taki jest nazywany histogramowaniem.

Histogram jest to sposób przedstawienia częstości występowania pewnej cechy w postaci wykresu słupkowego. Weźmy na przykład ciągłą zmienną losową. Podzielmy przestrzeń wartości przyjmowanych przez tą zmienna na N równych przedziałów. Przypuścmy, że dysponumemy M realizacjami zmiennej losowej. Na histogramie można umieścić liczbę realizacji, które należa do danego przedziału. Co więcej taki wykres bedzie w granicy N,M\to \infty taki sam jak wykres gęstości prawdopodobieństwa nasze zmiennej losowej. By otrzymać dokładnie gęstość prawdopodobieństwa trzeba przeskalować liczbę zliczeń do gęstości. Niech n_i, i=1..N będą zliczeniami w kolejnych przedziałach. Gęstość prawdopodobieństwa jest unormowana do jedności (bierzemy zmienną losową przyjmującą wartości między a i b):

1=\int_a^b f(x) dx=\sum_{i=1}^N f(x_i) h

gdzie h jest szerokością jednego przedziału h=(x_i-x_{i-1})/(N-1). Wynika z tego, że

\sum_{i=1}^N f(x_i) =1/h,

podczas gdy liczby zliczeń są unormowane do pewnej wartości \sum_{i=1}^N n_i .

Widać z tego, że formuła łącząca liczby zliczeń z wartościami gęstości wewnątrz odcinków wyraża się:

f_i=f(x_i)=\frac{1}{h}\frac{n_i}{\sum_{i=1}^N n_i} .

W systemie GNU Octave wbudowana funkcja hist umożliwia podanie drugiego argumentu, który jest czynnikiem normalizacyjnym sumy wszystkich zliczeń i w rozważanym przypadku powinien od wynosić 1/h.

Histogramy 1D

Jako przykład wykonajmy histogram 10000 liczb o rozkładzie normalnym i porównajmy go ze wzrorem analitycznym na funkcję Gaussa. Najprostszy skrypt w GNU Octave realizujący to zadanie to:

xmax=5;
h=0.1;
mydata=normrnd (0,1,10000,1);
hist(mydata,[-xmax:h:xmax],1/h);

Zauważmy, że:

Nie została zadana liczba przedziałow, ale szerokość. Liczba przedziałow w tym przypadku to:

octave:38> length( [xmin:h:xmax] )
ans =  101

Pomimo, ze zmienna losowa przyjmuje wartości na całej osi rzeczywistej, to histogram wykonaliśmy na skończonym przedziale. Wybranie wartości x a przedziału -5..5 jest w przypadku rozkładu Gaussa dobrym wyborem. Zauważmy jest stosunek funkcji gęstości w punktach 0 i 5 wynosi

octave:42> normpdf(0,0,1)/normpdf(5,0,1)
ans =  2.6834e+05

więc dla 10000 punktów możemy się spodziewać, że zaden z nim nie wyjdzie poza przedział -5...5.

Proszę sprawdzić jak będzie wyglądał histogram jeśli weżmiemy xmin=-1 i xmax=1

Funkcja hist została wywołana bez argumentów zwrotnych i zgodnie z dokumentacja narysowała ona wykres. Można postąpić inaczej:

xmax=5;
h=0.1;
mydata=normrnd (0,1,10000,1);
[NN,XX]=hist(mydata,[-xmax:h:xmax],1/h);

Podając argumenty zwrotne funkcja hist zamiast rysować wykres, zwraca wektor liczb zliczeń i wartość zmiennej w przedziałach. Można to wykorzystać:

plot(XX,NN,"-",XX,normpdf(XX,0,1),"r-")
bar(XX,NN)
Jak działa funkcja hist?

Poniższy kod ilustruje prostą implementacje funkcji histogramującej w GNU/Octave. Nie jest ona efektywna, gdyż wykorzystuje pętlę po wszystkich danych wejściowych (kod nie jest wektorowy).

xmax=5;
xmin=-5;
h=.1;
XX=[xmin:h:xmax];
mydata=normrnd (0,1,10000,1);
NN=zeros(1,101);
for i=1:length(mydata)
	idx=  ceil ( (mydata(i)-xmin)/(xmax-xmin) * length(NN)  ) ;
	if idx>0 && idx<=length(NN)
 		NN(idx)++;
	endif
endfor
plot(XX,NN)

Histogramy 2D

Estymacja gęstości dla dwów nielależnych zmiennych losowych Gaussowskich za pomocą funkcji hist2d.

Podobnie jak w przypadku jednej zmiennej losowej, histogram można utworzyć dla wielu zmiennych losowych. Do celów wizualizacyjnych nadaje się jednak tylko przypadek dwuwymiarowy. W sysemie GNU/Octave nie ma bezpośrednio wbudowanej funkcji histogramującej dwie zmienne losowe, ale jest pakiet rozszerzający plot (dostępny z [1]). Po zciągnieciu pliku instalujemy go za pomocą

pkg install 'plot-1.0.8.tar.gz'


Z jego pomoca narysujemy histogram dwoch niezależnych gausowskich zmienych losowych:


hist2d(normrnd(0,1,250000,2),60);

Podobnie jak w przypadku funkcji hist można dane zapisać do tablic by np. użyć innej procedury rysującej:

[nn,x,y]=hist2d(normrnd(0,1,134100,2),60);
imagesc(nn)


Estymacja gęstości dla dwów nielależnych zmiennych losowych Gaussowskich za pomocą funkcji hist2d, dane przedstawione za pomocą imagesc.