Monte Carlo yanılgısı (Kumarbaz yanılgısı)

Üniversitede elektronik okumak istiyordum, çünkü aklıma gelen her şey için elektronik devre yapabileceğimi hayal ediyordum. İlk yıllarda bölümün düşündüğüm gibi olmadığını anlayınca bir boşluğa düşmüş oldum. Ne yapabilirim diye düşünürken dördüncü sınıfta aldığım bir dersten sonra istediğim devrelerin çoğunu yazılımla yapabileceğimi farkettim. O andan itibaren tamamen yazılıma kaydım.

Zaman geçtikçe deneyler de ilgimi çekmeye başladı. İlginç bir şekilde okulda deneylere yatkındım ama tembeldim. Deney yapmayı okul hayatım bittikten sonra daha çok sevmeye başladım. Kimya, elektronik deneyleri için bodrumda laboratuvar bile kurdum.

Çok daha sonraları deneylere bilgisayarı da ekledim. Genelde veri toplama ve işleme için kullandım. Son zamanlarda simülasyonlar ve olasılık deneyleri için de programlar yazmaya başladım.

Bugün kumarbaz yanılgısını denemek istedim. Simülasyonda bir kumarbazımız var. Bu kumarbaz yazı tura oyunu oynuyor. Parayı attıktan sonra tahminde bulunuyor ve eski tahminleri de not alıyor. Merak ettiğim şey şuydu: Eğer kumarbaz kararını eski sonuçlara göre verirse rastgele bir karara göre nasıl bir ortalama tutturabilir? Daha iyi mi daha kötü mü?

Bunun için çeşitli stratejileri karşılaştırdım:

  1. Kumarbaz daha önce gelen sonuçları not alır ve eğer daha fazla tura gelmişse yazı, daha fazla yazı gelmişse tura der. Eğer eşit sayıda yazı ve tura gelmişse rastgele karar verir. Bunun da değişik türleri olabilir. Örneğin toplamlar arasındaki fark belli bir sayıdan büyükse bu şekilde davranır, fark küçükse rastgele cevap verebilir.
  2. Kumarbaz her yazı tura atışı için aynı cevabı verir. Hep yazı ya da hep tura.
  3. Kumarbaz her yazı tura atışı için rastgele bir cevap verir (Örneğin başka bir parayla yazı tura atar ve onun sonucunu söyler).

Çok daha farklı stratejiler de bulunabilir elbette ama hedeflerim sadece basit durumları denemek ve kolayca deney tasarlayabileceğim bir sistem kurmak olduğundan burada bıraktım. Şimdi kısaca deneyden ve sonuçlarından bahsedeyim.

Deney programını R dilinde yazdım. Her deney adımında 10000 yazı tura atıldı ve stratejiler doğru tahmin sayılarına göre birbirleriyle karşılaştırıldı. Kazanan strateji o tur için bir puan aldı, diğerleri ise sıfır. Eşitlik durumunda eşit skor alan stratejiler birer puan aldı. 1000 deney sonucunda her stratejinin puanı listelendi.

convert <- function(v) {
  if(v == 'T') {
    1
  } else {
    -1
  }
}

call <- function(v, offset) {
  if(v < -offset) {
    'T'
  } else if(v > offset) {
    'H'
  } else {
    if(sample(c(1, -1), size=1) == 1) {
      'T'
    } else {
      'H'
    }
  }
}

filter_max <- function(l) {
  which(sapply(l, function(x) l[1] %in% x));
}

experiment <- function() {
  number_of_experiments <- 1000;
  constants_H <- "constants_H";
  constants_T <- "constants_T";
  gambler <- "gambler";
  gambler_with_offset_1 <- "gambler_with_offset_1";
  gambler_with_offset_2 <- "gambler_with_offset_2";
  gambler_with_offset_3 <- "gambler_with_offset_3";
  random <- "random";
  counter_gambler <- 0;
  counter_random <- 0;
  counter_constant <- 0;
  counters <- c(constants_H = 0, constants_T = 0, gambler = 0, gambler_with_offset_1 = 0, gambler_with_offset_2 = 0,
                gambler_with_offset_3 = 0, random = 0);
  scores <- c(constants_H = 0, constants_T = 0, gambler = 0, gambler_with_offset_1 = 0, gambler_with_offset_2 = 0,
              gambler_with_offset_3 = 0, random = 0);
  for(i in 1:number_of_experiments) {
    number_of_trials <- 10000;
    coin <- c('T', 'H')
    coins <- sample(coin, size = number_of_trials, replace = TRUE);
    converted_coins = lapply(coins, convert);
    sums = cumsum(converted_coins);

    gambler_guesses = lapply(sums, call, offset = 0);
    gambler_guesses_1 = lapply(sums, call, offset = 1);
    gambler_guesses_2 = lapply(sums, call, offset = 2);
    gambler_guesses_3 = lapply(sums, call, offset = 3);
    random_guesses <- sample(coin, size = number_of_trials, replace = TRUE);
    constant_guesses_H <-sample(c('H'), size = number_of_trials, replace = TRUE)
    constant_guesses_T <-sample(c('T'), size = number_of_trials, replace = TRUE)

    scores[constants_T] = sum(constant_guesses_T == coins);
    scores[constants_H] = sum(constant_guesses_H == coins);
    scores[gambler] = sum(gambler_guesses == coins);
    scores[random] = sum(random_guesses == coins);
    scores[gambler_with_offset_1] = sum(gambler_guesses_1 == coins);
    scores[gambler_with_offset_2] = sum(gambler_guesses_2 == coins);
    scores[gambler_with_offset_3] = sum(gambler_guesses_3 == coins);
    sorted <- scores[order(unlist(scores), decreasing = TRUE)];
    maximum_values <- filter_max(sorted);
    for(x in maximum_values) {
      counters[names(maximum_values[x])] = counters[names(maximum_values[x])] + 1;
    }
  }
  print(counters);
}


Programın son hali bu ama ilk denememde sadece kumarbazın en basit stratejisiyle (daha fazla tura gelmişse yazı, daha fazla yazı gelmişse tura demek) rastgele karar verme stratejisini karşılaştırmıştım. Onun sonuçları ilk bakışta bir sürpriz olmuştu.

1000 deney sonucunda
Kumarbaz = 85
Rastgele = 916

Toplam 1000 deney yaptım ve kazanma toplamları 1000’den fazla olduğuna göre bir deneyde ikisi de eşit skor tutturmuş olmalı. Kumarbaz yanılgısı durumu bildiğim bir olaydı ama durumun ciddiyetinin bu derece olduğunu beklemiyordum. Bu arada küçük bir not da ekleyeyim, bu kavramı biliyordum dedim ama bunun hesaplarını daha önce hiç yapmadım. Bu deneylerin amacı da hesap yapmak değil sadece bu konu hakkında basitçe fikir sahibi olmaktı.

Sonra deneye bir de kumarbazın her zaman yazı dediği stratejiyi ekleyeyim dedim. Beklentim bu stratejini en az rastgele karar verme kadar iyi olması yönündeydi.

1000 deney sonucunda
Kumarbaz = 0
Rastgele = 504
Hep yazı= 502

Üç stratejinin yarıştığı durumda rastgele karar stratejisi kendisine gerçek bir rakip bulmuş gibiydi. Bu ortamda kumarbazın basit stratejisinin artık bir şansı yok gibi görünüyordu.

Sonra programda da yaptığım gibi bütün stratejilerin aynı anda yarıştığı bir deneme yaptım. Bu da sonuçları:

1000 deney sonucunda
Kumarbaz türevleri = 0
Rastgele = 271
Hep yazı = 385
Hep tura = 351

Görüldüğü gibi hep yazı ve hep tura oyunu eşit derecede domine etmeye başladılar. İkisinin de tek başına yaklaşık yüzde elli doğru tahminde bulunacağını beklemek normal bir durum. Diğer stratejiler bundan daha iyi skorlar elde edemeyecektir. Peki kumarbazın stratejisine yardım edilebilir mi? Eğer kumarbazın verdiği kararları biraz daha rastgeleleştirirsek daha iyi sonuçlar almasını beklemek çok da yanlış olmaz. Eğer hep rastgele karar verirse rastgele stratejiye yaklaşacaktır. O zaman rastgele karar verdiği aralığı (toplamlar arasındaki fark) büyüttüm ve bir iyileşme gördüm ama beklediğim hızda bir iyileşme olmadı bu.

1000 deney sonucunda
Kumarbaz (toplamlar arasındaki fark 50 ise rastgele) = 99
Rastgele = 223
Hep yazı = 351
Hep tura = 339

Bu kadar basit bir problem üzerine bu kadar çok deney tasarlanabilmesi hoşuma gitti. Bence deneyler de teoriler kadar önemli bir alan, bence deneyin sonucu teorinin sonucundan daha etkileyici ve şaşırtıcı.

Dil öğrenme (Programlama dili)

Bir programlama dilini neden öğrenmek isterim? Bunun çeşitli cevapları var tabii ki. Örneğin çalıştığım projede kullanılan bir dil olabilir ve bu nedenle o dili öğrenmem gerekiyordur. İleride bu dil işime yarayabilir diye düşünüyor olabilirim. Aklımdaki projelere uygun araçlar olduğu için öğrenmek isteyebilirim. Belki de sadece yeni bir şey öğrenmek için.

Programlama dili öğrenmek için kullandığım üç temel yöntem var:

  1. Programlama dilini bilgisayarıma kurup dil ile ilgili dökümanları ya da bir kitabı sırayla okuyup denemek.
  2. İlgilendiğim bir alanda bir proje seçmek ve o projeyi öğrenmek istediğim dil ile programlamak.
  3. Hackerrank gibi sitelerdeki soruları çözmek.

Birinci yöntemde vurgulamak istediğim nokta dökümanlar ya da kitaplar değil tabii ki. Bu kaynaklara her yöntemde ihtiyacım var. Yöntemlerdeki farklar öğrenme yolculuğunda kullandığım araçlar değil de daha çok bu sırada izlediğim rotalar.

İlk programlama dillerimi kitaplardan öğrendim. Üniversitede öğrendiğim dilleri de bu yöntem altında değerlendiriyorum. Kaynaklar yardımıyla bir dili öğrenmek ve bu bilgileri denemek o dilin inceliklerini öğrenmek için iyi bir yöntem olabilir. En azından bu şekilde büyük olasılıkla dili doğru kaynaklardan, dilin hangi fikirlere önem verdiğini de anlayarak doğru şekilde öğrenebiliriz.

Birkaç dil öğrendikten sonra bu yöntem bana verimsiz gelmeye başladı. Verimsizliği biraz açıklamam lazım tabii. Örneğin her dilde ilk kısımlar, değişkenler, döngüler, fonksiyonlar gibi aynı kavramlar üzerine oluyor. Bu kadar tekrar hoşuma gitmemeye başladı haliyle. Oraları hızla geçince de başka bir sorunla karşı karşıya kaldım. Kavramlar ne kadar aynı olsa da buralarda kullanılan isimler farklı olabiliyor. Bir dilin değişken dediğine diğeri değer ya da nesne diyebiliyor. İlerdeki konularda bu kavramlarla karşılaşınca nasıl olsa biliyorum bunları diye hızla geçtiğimde bir süre sonra bazı çelişkilerle karşılaştığım oldu. Çelişkilerin nedeni tabii ki o sıkıcı ilk üniteleri atladığımdan kavramların tanımlarının kafamdaki tanımlardan farklı olduğunu fark edememiştim.

Demek ki yeni bir dili kaynaklardan öğrenmek için de yine kaynaklardaki sırayı takip etmem gerekiyordu. Tabii ki her istasyonda aynı süre duraklamama gerek yoktu ama yol haritası hemen hemen tamamen benim kontrolüm dışındaydı.

Eğer bir dili o an çok iyi öğrenmeme gerek yoksa ama ilerisi için yatırım yapmak istiyorsam o zaman elimdeki bazı projeleri o dilde yapmayı deniyorum. Bu projeler kişisel, hobi projeleri olabildiği gibi şirket içinde de olabiliyor. Bu şekilde dili öğrenme yolculuğunu gerçek bir hikayenin üzerine oturtmuş oluyorum ve motivasyon açısından da faydalı oluyor ama profesyönel işlerde biraz dikkatli olmak gerekiyor. Örneğin yöneticilere ya da arkadaşlara o proje için neden o dili seçtiğimi açıklamam gerekebiliyor. Kişisel projelerde böyle bir sorun yok ama. İşin geri kalan kısmında yine kaynakları okumam gerekiyor ama bu sefer kendimi motive etmem daha kolay oluyor. Belli bir hedefim var ve yarım yamalak da olsa dil öğrenmenin getirisini hemen alıyorum.

Üçüncü yöntemi, hackerrank ve benzeri siteleri yeni yeni kullanmaya başladım. Bunu da daha çok bildiğim dilleri unutmamak ya da yeni özelliklerini deneyerek öğrenmek için yapıyorum. Bu şekilde bir dil gerçekten öğrenilemez sanırım ama boş zamanlarda kısa antrenmanlar için iyi olabilir.

Bu kullandığım yöntemlerin doğru kombinlendiği zaman iyi sonuçlar vereceğine inanıyorum. İlk diller bence birinci yöntemle daha iyi öğrenilebilir, çünkü hiçbir dil bilmeden bir projeyi, hobi projesi bile olsa yapmaya kalkmak bu sırada verilecek bir sürü yanlış karar yüzünden hem zorlaştırır hem de dile karşı yalancı bir güvensizlik yaratabilir. Bir dili ve program geliştirmeyi iyi öğrendikten sonra yeni dillerde ikinci yöntem daha iyi sonuç verebilir. Bu sırada hem bir projenin başarılı olmasına şahit olmanın heyecanı da öğrenmeyi destekleyici bir etki yapabilir. Son olarak da eski bilgileri unutmamak için üçüncü yöntem kullanılabilir.

Tutuklular ve kutular (Çözüm)

Soru

Aklıma ilk gelen yöntem şu şekildeydi. İçinde kağıt olan kutuyu göstermek için birden fazla yazı tura dizilimi tanımlayabilirsem ve bunların her birine hangi konumdan olursa olsun tek bir yazı tura değişimiyle gelebilirsem o zaman soruyu çözmüş olurum. Dört kutu ve dört para var. Dört para için toplam 16 tane değişik yazı tura dizilimi var. Her bir kutu için dört tane dizilim kullanma şansım var yani. Peki bunları yukarıdaki varsayımıma uygun bir şekilde seçebilir miyim?

Öncelikle birinci kutu için seçeceğim ilk para diziliminin herhangi bir dizilim olabileceğini düşündüm. Diyelim ki YYYY (yazı – yazı – yazı – yazı) dizilimi birinci kutuda kağıt var anlamına gelsin. Bu durumda gardiyan kağıdı birince kutuya koyduktan sonra paraların durumu YYYY de olabilir. Yani bu dizilimden bir yazıyı tura yaptığım dizilimin de birinci kutu anlamına gelmesi lazım. Bu dizilimi de YYYT şeklinde seçeyim.

Şimdi YYYY ve YYYT dizilimlerine tek bir değişimle erişebilen dizilimleri bulmaya çalışayım.

Not: Burada dizilimlere ayrıca sayısal bir değer vereceğim ki, tabloların bütünlüğü daha kolay anlaşılsın. Dizilimlerin sayı değerini hesaplarken ikilik düzeni kullanacağım. Y için 0, T için 1 değerini kullanacağım ve dizinin onluk düzendeki değerini dizinin yanında parantez içinde göstereceğim.

YYYY (0) -> YYYT (1)
YYYT (1) -> YYYY (0)
YYTY (2) -> YYYY (0)
YYTT (3) -> YYYT (1)
YTYY (4) -> YYYY (0)
YTYT (5) -> YYYT (1)
TYYY (8) -> YYYY (0)
TYYT (9) -> YYYT (1)

Bu şekilde sekiz dizilim için ilk kutuyu gösterebileceğim iki dizilim bulmuş oldum. Kalan sekiz dizilim için de birinci kutuyu simgeleyen iki dizilim bulmam lazım şimdi. Aklıma ilk gelen fikir yukarıdaki tablonun tam tersini almak oldu. Yani T yerine Y ve Y yerine T olacak şekilde seçimlerimi yapabilirim belki. Bu şekilde yukarıdaki tabloda olmayan dizileri elde edeceğimi göstermem lazım. Bunun en kolay yolu tabii ki yeni tabloyu yazmak olacaktır.

TTTT (15) -> TTTY (14)
TTTY (14) -> TTTT (15)
TTYT (13) -> TTTT (15)
TTYY (12) -> TTTY (14)
TYTT (11) -> TTTT (15)
TYTY (10) -> TTTY (14)
YTTT (7) -> TTTT (15)
YTTY (6) -> TTTY (14)

Böylece birinci kutuyu simgeleyecek dört adet dizilim bulmuş oldum: YYYY, YYYT, TTTT, TTTY. Olası her dizilimden bu dizilimlere tek bir hareketle geçiş yapabiliyorum.

Şimdi ikinci kutu için bir seçim yapayım. Şimdiye kadar seçtiğim dört dizilim dışındaki herhangi bir dizilim başlangıç için işe yarayacaktır. Örneğin YYTY dizisini alayım. Şimdi yine yukarıdaki mantığı yürüterek başlangıçta bu dizilimin oluşabileceğini varsayıp tek bir değişimle elde edebileceğim ve daha önce seçilmemiş başka bir dizilim seçeyim. O da YYTT olsun. Yine yukarıdaki gibi bu iki dizilime tek bir değişimle ulaşılabilen dizilimleri yazayım.

YYYY (0) -> YYTY (2)
YYTT (3) -> YYTY (2)
YTTY (6) -> YYTY (2)
TYTY (10) -> YYTY (2)
YYTY (2) -> YYTT (3)
YYYT (1) -> YYTT (3)
YTTT (7) -> YYTT (3)
TYTT (11) -> YYTT (3)

Aynı şekilde bu dizilimlerin terslerini aldığımda da kalan dizilimler için gereken ikinci kutu çözümlerini de şu şekilde yazabilirim:

TTTT (15) -> TTYT (13)
TTYY (12) -> TTYT (13)
TYYT (9) -> TTYT (13)
YTYT (5) -> TTYT (13)
TTYT (13) -> TTYY (12)
TTTY (14) -> TTYY (12)
TYYY (8) -> TTYY (12)
YTYY (4) -> TTYY (12)

Böylece ikinci kutuyu kodlamak için şu dizilimleri bulmuş oldum: YYTY, YYTT, TTYT ve TTYY.

Bu yöntem madem şimdilik çalışıyor gibi gözüküyor, o zaman devam edeyim. Üçüncü kutuyu kodlama için bu sefer YTYY dizilimiyle başlayayım. Yukarıdaki yöntemleri tekrarlayacağım. Başlangıç dizisi YTYY olabileceğine göre tek değişiklikle ulaşabileceğim ama daha önceki kutular için seçmediğim bir dizilim seçeyim. Örneğin, YTYT. Tekrar bu dizilimlere her dizilimden tek bir değişiklikle geçebilir miyim kontrolünü yapayım.

YTYT (5) -> YTYY (4)
YTTY (6) -> YTYY (4)
YYYY (0) -> YTYY (4)
TTYY (12) -> YTYY (4)
YTYY (4) -> YTYT (5)
YTTT (7) -> YTYT (5)
YYYT (1) -> YTYT (5)
TTYT (13) -> YTYT (5)

Yine sekiz değişik dizilimden bu iki dizilime geçebildim. Şimdi bunların da tersleri dizilimleriyle kalan tabloyu oluşturayım.

TYTY (10) -> TYTT (11)
TYYT (9) -> TYTT (11)
TTTT (15) -> TYTT (11)
YYTT (3) -> TYTT (11)
TYTT (11) -> TYTY (10)
TYYY (8) -> TYTY (10)
TTTY (14) -> TYTY (10)
YYTY (2) -> TYTY (10)

Böylece üçüncü kutuyu kodlayan dizilimleri de bulmuş oldum: YTYY, YTYT, TYTT ve TYTY.

Kalan dört dizilim de dördüncü kutuyu kodlamak için kullanılabilir: TYYT, TYYY, YTTT, YTTY.

YYYY (0) -> TYYY (8)
YYYT (1) -> TYYT (9)
YYTY (2) -> YTTY (6)
YYTT (3) -> YTTT (7)
YTYY (4) -> YTTY (6)
YTYT (5) -> YTTT (7)
YTTY (6) -> YTTT (7)
YTTT (7) -> YTTY (6)
TYYY (8) -> TYYT (9)
TYYT (9) -> TYYY (8)
TYTY (10) -> TYYY (8)
TYTT (11) -> TYYT (9)
TTYY (12) -> TYYY (8)
TTYT (13) -> TYYT (9)
TTTY (14) -> YTTY (6)
TTTT (15) -> YTTT (7)

Böylece problem için bir çözüm bulmuş oldum.

Algoritma olarak her bir kutuyu kodlamak için yaptığım adımlar şöyle oldu: Daha önce seçilmemiş bir dizilim aldım. Sonra bu dizilime bir değişiklik uzakta başka bir dizilim aldım ve sekiz değişik dizilimin bu iki dizilime bir değişiklik uzakta olduğunu gösterdim. Kalan diğer iki dizilimi de bu seçtiğim iki dizilimin tersi olarak seçtim ve bu dizilimlerin de diğer sekiz dizilime birer değişiklik uzaklıkta olduğunu gösterdim.

Şimdi aklıma takılan bazı sorulara bakayım:

  1. Her adımda seçtiğim ilk iki dizilim her zaman sekiz değişik dizilimden bir değişiklik uzakta mı? Birbirine bir değişiklik mesafede iki dizilimin bir basamakları farkllı ve diğer üç basamakları aynı olmak zorundadır. Seçtiğim iki dizilimin arasındaki mesafe bir değişiklik olduğundan ikisi de bu iki dizilime bir değişiklik mesafede olan dizilimler arasında olacak ve birbirlerinden farklıdırlar. Kalan üçer basamak için de ya elimdeki sayılara (ikisine de) o basamak değeri kadar ek yapacağım (eğer basamak değeri sıfır ise) ya da sayının değerinden o basamak değeri kadar çıkaracağım. İki durumda da oluşan sayılar elimdeki sayılardan ve birbirlerinden farklı olacaklar. Basamakların değerleri de 1, 2, 4 ya da 8 olduğundan değişik basamakların değerlerini (sadece bir basamağın) ekleyerek ya da çıkararak eşit sayılar elde edemeyiz.
  2. Dizilimlerin tersini aldığımda (yani yazı yerine tura, tura yerine yazı koyunca) önceki sekiz dizilimle bir çakışma olabilir mi? Dizilimlerin onluk düzendeki değerlerine bakarsak bir dizilimin değeriyle o dizilimin tersinin değerini topladığımızda her zaman 15 sayısına ulaşıyoruz. Çakışma olabilmesi için sekizlik grupta toplamları 15 olan iki dizilimin olması gerekir. Şöyle bir mantık yürüteyim. Birbirine mesafesi bir olan iki dizilimden herhangi birine mesafesi bir değişim olan iki rastgele dizilim arasındaki mesafe en fazla üç olabilir olabilir. Dizilimlerin birine A diyelim ve bu seçtiğim ilk dizilime bir değişim mesafede olsun. Diğer B dizilimi de ikinci dizilime bir değişim mesafede olsun. O zaman A diziliminden B dizilimine önce bir seçtiğim iki dizilim üzerinden en fazla üç dizilimle gidebilirim. Şimdi toplamları 15 değerini veren dizilimlere bakayım.
YYYY (0) -> TTTT (15) : aradaki mesafe 4
YYYT (1) -> TTTY (14) : aradaki mesafe 4
YYTY (2) -> TTYT (13) : aradaki mesafe 4
YYTT (3) -> TTYY (12) : aradaki mesafe 4
YTYY (4) -> TYTT (11) : aradaki mesafe 4
YTYT (5) -> TYTY (10) : aradaki mesafe 4
YTTY (6) -> TYYT (9) : aradaki mesafe 4
YTTT (7) -> TYYY (8) : aradaki mesafe 4

Tablodan da görüldüğü gibi toplamın 15 olabilmesi için seçtiğim iki dizilimin ürettiği sekiz dizilimdeki iki dizilim arasındaki mesafenin dört olması lazım ama bu mesafe en fazla üç olabiliyor. Demek ki toplamı 15 eden iki dizilim bu sekiz dizilim arasında yok. O zaman tersleri ile aralarında bir çakışma da olamaz. Yani kullandığım yöntem gerçekten de işe yarıyor gibi gözüküyor.

Not: Literatürde bu dizilimler arasındaki mesafeye (birinden diğerine geçişte gereken değişiklik sayısına) Hamming mesafesi deniyor.