Marsaglia法とBox-Muller法
一様分布からガウス分布を作るアルゴリズムとして有名なBox-Muller法というのがあります.
式としては、とした時に
という変換を行う.これがBox-Muller
ボックス=ミュラー法 - Wikipedia
それと似たもので、一様分布する変数の範囲がちょっと変わってとしてやって、更に
を満たすものだけを取り出して(要するにそうじゃないやつを棄却して)
という変換をしてやるのが、Marsaglia
Marsaglia polar method - Wikipedia, the free encyclopedia
なんか読むとBox-Mullerのほうがcosとsinの計算を並列でできる?から早いとかなんとか.まあ棄却する部分があるMarsagliaのほうが遅そうやなぁという雰囲気はあるよね.
というわけで実装
import numpy as np import math as math import time import matplotlib.pyplot as plt pears = 1000 ##compare marsaglia with box-muller def boxmuller(): """ using box-muller method return:points random sampling following N(0,1) """ points = [] for i in range(pears): z1 = np.random.uniform(0,1) z2 = np.random.uniform(0,1) y1 = np.power((-2 * math.log(z1)),0.5) * math.cos(2 * np.pi * z2) y2 = np.power((-2 * math.log(z1)),0.5) * math.sin(2 * np.pi * z2) points.append([y1,y2]) return points def marsaglia(): """ marglia method return:points random sampling following N(0,1) """ points = [] for i in range(pears): z1,z2 = 0.,0. r = 0. while 1: z1 = np.random.uniform(-1,1) z2 = np.random.uniform(-1,1) r = z1 * z1 + z2 * z2 if r <= 1: break y1 = z1 * np.power(-2. * math.log(r) / r,0.5) y2 = z2 * np.power(-2. * math.log(r) / r,0.5) points.append([y1,y2]) return points methods = [boxmuller,marsaglia] for i in methods: start_time = time.time() for k in range(10): i() end_time = time.time() print (end_time-start_time)/100,i points = np.array(marsaglia()) plt.plot(points[:,0],points[:,1],"ro",alpha=0.5) points = np.array(boxmuller()) plt.plot(points[:,0],points[:,1],"go",alpha=0.5) plt.show()
結果
0.00240999937057 <function boxmuller at 0x04357D70> 0.00396000146866 <function marsaglia at 0x04357DB0>
やっぱboxmullerのほうが早いみたい.
どっちも標準正規分布にはなってるみたい.
PRML 第5章
ニューラルネットワークのところを読んでいますが詰まりました.
ニューラルネットワークでは、最終的な出力が
という風になっていて、
そこで疑問なのが、
例えばKクラスの分類問題をニューラルネットワークに説かせようと思った時、
この最後のの部分をソフトマックス関数
とすれば良い
(ただしは出力ユニットへの活性である)
という説明があるのだけれど、疑問がひとつ.
最終の出力ユニットの活性はとなっているのだから、
出力ユニットjへの入力は既に隠れユニットの出力と重みの積の和になっているはずで、
そこからどうやって各々のを計算しなおしてるんだろうか…という
なんか多分どうでもいい勘違いなんだろうけど凄くイライラ.
prml 第4章
先週から読み始めてようやく第四章までたどり着きました。噂には聞いていたのですが、ここまで重たいものだとは正直予想外で、なんとかかんとか頑張ってついていっているのか、はたまたわかったような気になっているのかは謎ですが、とりあえずちょっとづつ前進している感じです。
読んでいて思うのは、式変形はわかるんだけど、その意味合いを考えるとちょっとこんがらがるというか、冷静に考えると意味わかってないなって気づくところが多いということ。これはベイズの定理を使うのに慣れ始めてから少しづつ改善はしているのですが、やっぱりなぜこの式をここで使うのか?とかをちゃんと考えながら読まないと、ビショップさんの意図を汲み取れなくなっていくので、そこがしんどいです。
あと自分が理解できていないからかも知れませんが、微妙に天下り的に結果を先に与えていたり、すでにわかっているパラメータを条件付き確率の既知の部分から省いていたり、そういう微妙な罠がそこかしこにあって、記述は綺麗だけど意味を汲み取るのに時間が掛かる時があって、そこも苦労している点です。
まあわかってる人からすれば大したことはない省略だとは思うんですけども。モデルの選択の部分でモデル選択のMiが突然なくなった時とか、結構悩まされました。みんなどうやってクリアしてるのか気になるところです。
やっぱ誰か一緒に読む人がいたほうがいいなぁ…
あと、今まで研究室にあったやつを借りて読んでいたのですが、やっぱ高いけどこの本は買わないとダメだと決心がついたので、そろそろ買いに行こうかと思います。買ったら投げ出さんやろうという、退路を断つ作戦。そうでもしないと最後まで絶対やらんしな。
カーネル密度推定
PRMLを読んでいます。とりあえず出てくる式はすべて自分で追って、変形とかもやってるのでなかなか進まなくてもどかしいですが、もう多分確率密度関数とかを復習することは無いだろうし…と思いながらやってます。
今日は二章のおわりまで行きました。
ノンパラメトリックの推定方法のところで、この間「外野フライをカーネル密度推定を用いて解析する」っていう論文を読んで気になってたカーネル密度推定のお話が出てきました。ざっくり言うと、その点の周りにいっぱい点があれば、そこの確率は高いよねっていうことです。発想としては至ってシンプルなんですね。直感的。
なんか可視化してみたら面白そうだったので、pythonの練習も兼ねて実装をしてみました。
やってるのは、一次元のガウス分布に従うサンプルから確率密度関数を推定するっていうものです。
import numpy as np import matplotlib.pyplot as plt from scipy.stats import multivariate_normal class KernelEstimation(): def __init__(self,trainingdata,h,D,kernel): self.trainingdata = trainingdata self.h = h self.D = D self.kernel = kernel def labeltext(self): return "kernel: "+self.kernel+" sigma: "+str(self.h) def _kernel(self,d): """ return kernel distance """ if self.kernel == "gausian": norm = np.linalg.norm(d) return np.exp(-norm*norm/(2.*self.h*self.h)) return 0 def _normalize(self): """ normalization parametor """ if self.kernel == "gausian": return 1/np.power((2*self.h*self.h*np.pi),(self.D/2.))/self.trainingdata.size else: return 0 def predict(self,x): """ predict by kernal estimate """ prob = np.zeros(x.size) for i in range(x.size): for k in range(self.trainingdata.size): prob[i] += self._kernel(x[i]-self.trainingdata[k]) return prob*self._normalize() rv = multivariate_normal(1,1) x = np.linspace(-5,5,100) plt.plot(x,rv.pdf(x),"k-") samples = rv.rvs(100)#sampleの生成 plt.hist(samples,normed=True, facecolor='green',alpha=0.3) kernel = KernelEstimation(samples,0.30,1,"gausian") plt.plot(x,kernel.predict(x),"b--",label=kernel.labeltext()) plt.legend() plt.show()
KernelEstimationというクラス作ってみました、完全に練習ですが少しは見通しが良くなってるかな?
sigmaの値を変えると推定の雰囲気が色々と変わるので面白いですね。