Monte Carlo ile Rastgele Yürüyüş ve Pi Sayısının hesaplanmas¶Python öğretirken en büyük sorunlardan biri anlaşılabilir kısa kodlar ile anlamlı sonuçlar çıkarabilmektir. Benim de yaşadığım bu problem için internette de örnekleri yer alan iki kodlama konusuna değineceğiz.
Tüm bunları yaparken de Monte Carlo yöntemini kullanacağız. Şöyle anlatmak gerekirse, mesela sıra ile tüm olasılıkları denemek yerine, rastgele olasılıklar ile sonuçların nasıl şekillendiğine, sonuçların nereye evrildiğine bakacağız. Rasgele Yürüyüş¶Önce kütüphanelerimizi yükleyerek başlayalım. math ve random kütüphanelerini yükleyeceğiz In [2]:
import math
import random
Tüm bu çalışma boyunca iki temel komut kullanacağız
Önce random.choice ile başlayalım. random.choice içine mesela dilediğimiz harfleri vererek Bir kelime bir işlem oyunundaki gibi harfler üretmesini de sağlayabiliriz. Mesela önce sesli harflerden başlayalım In [3]:
random.choice(['a','e','i','ı'])
Out[3]:
Şimdi de sessiz harfleri deneyelim In [4]:
random.choice(['n','r','d','k','m','l','t'])
Out[4]:
Şimdi hepsini karıştırarak, for ile tekrar ettirelim In [5]:
harfsayisi=6 # 1
for i in range(harfsayisi): # 2
sesliharf=random.choice(['a','e','i','ı']) # 2.a önce verilen seriden bir sesli harf seçelim
sessizharf=random.choice(['n','r','d','k','m','l','t']) # 2.b şimdi de sessiz harf seçelim
harf=random.choice([sessizharf,sesliharf]) # 2.c yukarıda seçtiğimiz sesli ve sessiz harflerden ikisinden biri
print(harf,end="") # 2.d harfi yaz ama sonuna yeni satır ekleme
Yukarıdaki kod da sırası ile
Şimdi konumuza gelelim. bir parçacık 1 boyutta ya ileri gidebilir ya geri ya sabit kalabilir. "0" noktasından başlarsa, ya 1 noktasına, ya -1 noktasına ya da hareket etmeyerek 0 noktasında kalarak devam edebilir. Hareket seçenekleri -1,0,1'dir In [6]:
random.choice([-1,0,1])
Out[6]:
Şimdi rastgele 10 adım atalım In [7]:
for i in range(10):
print(random.choice([-1,0,1]),end=",")
Fakat rastgele 10 adım sonucunda hangi noktada olacak? Bu sebeple bir pozisyon değişkeni tanımlayalım. Aşağıdaki kodu her çalıştırdığımızda farklı bir sonuç göreceğiz In [8]:
pozisyon=0
for i in range(10):
pozisyon=pozisyon+random.choice([-1,0,1])
print("Son geldiğim nokta = ", pozisyon)
Son pozisyon negatif ise, uzaklık ise bunun mutlak değeridir. In [9]:
abs(pozisyon)
Out[9]:
10 adım atıp başlangıç noktasından 5 adım uzakta olabiliyoruz. Kodu her çalıştırdığınızda bu rakam değişecektir. Aynı rakamları elde etmek için random.seed() komutunu kullanmanız gerekir. Rastgele adımda Monte Carlo ile simulasyon¶Rastgele adım sayımız arttıkça başlangıç noktasından uzaklığımız neye göre değişmektedir? Şimdi bunu test edelim. Bunun için 100 rastgele adımı 500 defa tekrarlayarak çıkan sonuca bakalım.
Şimdi kodumuzu basitçe çalıştıralım In [14]:
baslangic=0
adimsayisi=100
simulasyonsayisi=500
for s in range(simulasyonsayisi):
baslangic=0
for i in range(adimsayisi):
baslangic=baslangic+random.choice([-1,0,1])
print(baslangic,end=",")
Evet, 500 defa 100 adım attık ama elimizde bir sürü rastgele 100 adım atılan 500 örnekleme oldu. Bunları nasıl kullanacağız? Bunun için tüm sonuçları kayıt altına alacağız. Bunun için de bir dizi (list) kullanacağız. Kullanımı gayet basit.
Şimdi tüm simulasyon sonuçlarını kayıt altına alalım. In [15]:
baslangic=0
adimsayisi=100
simulasyonsayisi=500
kayit=[]
for s in range(simulasyonsayisi):
baslangic=0
for i in range(adimsayisi):
baslangic=baslangic+random.choice([-1,0,1])
kayit.append(baslangic)
Artık tüm değişkenlerimiz hafızada kayıt değişkeni içinde. Dolayısıyla daha detaylı bir analiz yapabiliriz. Önce grafikleme için %pylab inline komutunu kullanalım In [17]:
%pylab inline
Hemen kayit değişkeni ile ilgili analizleri yapalım. Önce boyutu ne ona bakalım. shape komutu tam bu konu için uygun. In [20]:
shape(kayit)
Out[20]:
Tüm 500 simulasyonun ortalamasına bakalım In [21]:
mean(kayit)
Out[21]:
Bu ne yahu? 500 kere 100 rastgele adımdaki tüm simulasyonların ortalaması -0.5 mi? Bir de grafiğe bakalım In [22]:
plot(kayit)
Out[22]:
Bunun bir de histogramı var tabii ki In [26]:
hist(kayit, bins=20);
Görüldüğü gibi 100 tane ileri geri rastgele adımların dağılımında önemli bir kısmı -10 ile 10 arasında sıralanmış durumda Pi sayısının hesaplanması¶Pi sayısının hesaplanmasında yine bir Monte Carlo metodu kullanacağız. Farzedin ki belirli bir mesafeden kare şeklinde ve üzerinde bir daire resmi olan (soldaki resim) hedefe ok/dart atıyorsunuz. Sizin attığınız okların kareye denk gelenlerinin daire içerisinde kalma ihtimali:
Dairenin yarı çapı 1 ise dairenin alanı pi*1*1 (pi*r^2) olacaktır. Yani pi olacaktır. Karenin bir kenarı ise dairenin çapı kadar yani iki yarıçap kadar olacaktır. o da 2*r'dir. O zaman karenin alanı 2*r*2*r yani 4*r^2 'dir. r=1 olduğundan 4 'tür. Yani karenin üzerine rastgele atılan okların daire içerisine gelme ihtimali Pi/4'tür. (daire alanı=pi / kare alanı=4) Bu sebeple ilk fonksiyonumuz random.uniform ile başlayalım. Bu yöntemle arttığımız her dart/ok'un herhangi bir noktaya isabet etme ihtimalini eşitlemiş oluyoruz. Küçük bir ayrıntı olarak kare ve dairenin merkezini 0,0 noktasına yerleştiriyoruz. Böylelikle kalenin bir ucu -1'den 1'e uzarken bir kenar uzunluğu da 2 olmuş oluyor. Dolayısıyla kartezyen koordinatta iki boyutlu -1 ve 1 arasında rastgele sayılar üreteceğiz. Bu üretilen sayılar dartımızı/okumuzu attığımı koordinati vermiş olacak. Daha sonra bu koordinatların daire içinde kalıp kalmadıklarını test ederek daire içine düşmüşler ise iceride diye tanımladığımız değişkeni 1 arttıracağız. Sonra da iceride değişkenini tüm atissayisi'na böleceğiz. Hatırlarsanız okun daire içine düşen miktarının tüm kare alanına düşen miktarı pi/4 dü. Yukarıda çıkan oranı da o sebeple 4 ile çarpınca pi'yi bulmuş olacağız. Yani:
In [34]:
random.uniform(-1,1)
Out[34]:
Adım adım kodumuz şöyle çalışacak
In [35]:
atissayisi=100000 # adım 1
iceride=0 # adım 2
for d in range(atissayisi): # adım 3
x=random.uniform(-1,1) # adım 4
y=random.uniform(-1,1) # adım 5
if (x*x+y*y)<=1: # adım 6
iceride=iceride+1 # adım 6.1
print(4*iceride/atissayisi) # adım 7
Evet 100,000 adım ile bir pi sayısı ürettik. Ama acaba atissayisi arttıkça sonuç nereye gidiyor. Bunu da kayit değişkeni ile izleyelim In [42]:
kayit=[] # tüm sonuçları hafızaya almak ve analiz etmek için dizi değişkeni kayit
atissayisi=100 # adım 1
simulasyonsayisi=50 # adım 1.1 simulasyon sayısı belirleyelim
for s in range(simulasyonsayisi):# simulasyon sayısı kadar tekrar et
iceride=0 # adım 2, bu sefer iceride'yi her simulasyon adımında tekrar sıfırlıyoruz
for d in range(atissayisi): # adım 3
x=random.uniform(-1,1) # adım 4
y=random.uniform(-1,1) # adım 5
if (x*x+y*y)<=1: # adım 6
iceride=iceride+1 # adım 6.1
kayit.append((4*iceride/atissayisi) ) # hesapladığımız pi değerini hafızaya al
atissayisi=100*simulasyonsayisi
50 simulasyonda her seferinde adım sayısını arttırarak (atissayisi=100*simulasyonsayisi, yani 100,200,...5000 adıma kadar) pi sayısını hesapladığımızda sonucun gittikçe 3.14'e yakınsadığımı görürürüz. Önce grafiğine sonra histogramına bakalım. In [43]:
plot(kayit)
Out[43]:
In [46]:
hist(kayit, range=(3,3.4)); # sondaki ; gereksiz ekran çıktılarından kurtulmak için
Hatta bir de ortalamasına bakalım In [47]:
mean(kayit)
Out[47]:
Atış sayısını attırdıkça rakam daha fazla pi sayısına yaklaşacaktır. Bu sebeple üşenmedim 104,857,600 defa çalıştırarak pi sayısını 3.1415010833740236 olarak da hesapladım. Sonuç¶Monte Carlo yöntemi çıkışı itibari ile tek tek tüm olasılıkları deneyerek sonuca ulaşmanın imkansız olduğu durumlarda, tüm sistemi arka arkaya rastgele yöntemlerle çalıştırarak sonuca yaklaşmaya yardımcı olur. Özellikle bir çok tahmin yönteminde sisteme arka arkaya rastlantısal girdiler vererek tepkisini görmek önemlidir. Bu örnekte:
Soru ve önerileriniz için barissanli2@gmail.com Ankara, 5 Haziran 2019 In [ ]:
|