%matplotlib inline
from selenium import webdriver
from time import sleep
import csv
import pandas as pd
import numpy as np
import matplotlib.pyplot as pl
from collections import Counter
Milli Piyango web sitesine bağlanarak her haftanın Sayısal Loto sonuçlarını otomatik olarak okuyalım ve bir CSV dosyasına yazalım.
driver = webdriver.Firefox() # Bir tarayıcı penceresi aç.
driver.get("http://www.mpi.gov.tr/sonuclar/_cs_sayisal.php") # Sayısal Loto sonuçlarına git.
assert "Sayısal Çekiliş Sonucu" in driver.title # Doğru sayfa olduğundan emin ol.
csvfile = open("sayisalloto.csv", "w", newline="") # verilerin kaydedileceği dosyayı yarat.
writer = csv.writer(csvfile)
dates = driver.find_element_by_id("sayisal-tarihList")
all_options = dates.find_elements_by_tag_name("option")
# Tarih dropdown listesindeki bütün seçenekler üzerinden döngü yap.
for option in all_options:
date = option.get_attribute("value")
option.click()
sleep(1) # tam yüklenmesi için bekle.
# Hafta numarasını oku:
haftano = driver.find_element_by_id("sayisal-hafta").text
# Sonuçları oku:
numara_elem = driver.find_element_by_id("sayisal-numaralar")
numaralar = [i.text for i in numara_elem.find_elements_by_tag_name("li")]
# Kazanan İl/İlçe'yi oku (birden fazla olabilir):
il_ilce = driver.find_element_by_id("sayisal-buyukIkramiyeKazananIl").text
if il_ilce: # boş değilse
writer.writerow([date, haftano]+ numaralar + [il_ilce])
else: # İl/İlçe boşsa, büyük ödül devretti veya kazanan il kaydı yok.
bilenkisi = driver.find_element_by_id("sayisal-bilenkisisayisi-6_BILEN")
if "Devir" in bilenkisi.text:
writer.writerow([date, haftano]+ numaralar + ["Devir"])
else:
writer.writerow([date, haftano]+ numaralar + ["Yok"])
driver.quit()
csvfile.close()
Şimdi bu dosyayı kullanarak şanslı ilçeleri okuyalım ve her birinin kaç kere büyük ikramiye kazandığını sayalım.
lotodata = pd.read_csv("sayisalloto.csv", header=None, names=["tarih","hafta","n1","n2","n3","n4","n5","n6","İl/İlçe"])
Veri dosyasının sütunlarına bir örnek:
lotodata.head(10)
tarih | hafta | n1 | n2 | n3 | n4 | n5 | n6 | İl/İlçe | |
---|---|---|---|---|---|---|---|---|---|
0 | 20160813 | 1031 | 13 | 18 | 19 | 20 | 38 | 49 | ANKARA / YENİMAHALLE |
1 | 20160806 | 1030 | 2 | 18 | 27 | 31 | 33 | 38 | Devir |
2 | 20160730 | 1029 | 2 | 14 | 22 | 23 | 38 | 47 | Devir |
3 | 20160723 | 1028 | 7 | 12 | 14 | 34 | 40 | 46 | İZMİR / KARŞIYAKA |
4 | 20160716 | 1027 | 12 | 16 | 27 | 36 | 46 | 48 | Devir |
5 | 20160709 | 1026 | 6 | 11 | 21 | 39 | 40 | 48 | Devir |
6 | 20160702 | 1025 | 4 | 35 | 39 | 40 | 42 | 46 | BURSA / OSMANGAZİ - KIRKLARELİ / BABAESKİ |
7 | 20160625 | 1024 | 6 | 7 | 11 | 16 | 24 | 35 | DENİZLİ / PAMUKKALE |
8 | 20160618 | 1023 | 4 | 10 | 20 | 22 | 27 | 33 | ANKARA / YENİMAHALLE |
9 | 20160611 | 1022 | 14 | 16 | 26 | 37 | 38 | 45 | ANKARA / MAMAK - ESKİŞEHİR / ODUNPAZARI |
Büyük ikramiyeyi kazanan yerler "İL / İLÇE" biçiminde kaydedilmiş. İkramiye birden fazla yere çıktıysa "İL1 / İLÇE1 - İL2 / İLÇE2 - ..." biçiminde kayıtlı. Bu kaydı bölüp ayrı "İL /İLÇE" biçimlerine getirelim, ve sadece il/ilçelerden oluşan bir liste hazırlayalım.
ililceliste = []
for ii in lotodata["İl/İlçe"].values:
if ii not in ["Devir", "Yok"]:
ililceliste += ii.split(" - ")
print(ililceliste[:5])
['ANKARA / YENİMAHALLE', 'İZMİR / KARŞIYAKA', 'BURSA / OSMANGAZİ', 'KIRKLARELİ / BABAESKİ', 'DENİZLİ / PAMUKKALE']
Şimdi bu liste içinde her bir elemanın kaç kere bulunduğunun çetelesini oluşturalım, en şanslı on ilçeyi listeleyelim:
for a,b in Counter(ililceliste).most_common(10):
print(a,b)
ANKARA / YENİMAHALLE 9 İSTANBUL / KADIKÖY 9 İZMİR / KARŞIYAKA 8 ANKARA / ÇANKAYA 8 İSTANBUL / FATİH 6 İZMİR / KONAK 6 İSTANBUL / BAHÇELİEVLER 5 İSTANBUL / ŞİŞLİ 5 İZMİR / BORNOVA 5 İSTANBUL / ÜSKÜDAR 4
Görüyoruz ki Ankara Yenimahalle gerçekten şanslı, ama İstanbul Kadıköy de aynı derecede şanslı. Başka ilçelerle karşılaştırıldığında Yenimahalle'nin olağanüstü bir farklılığı yok.
Aynı analizi Şans Topu için yapalım. Önce Milli Piyango web sitesinden bütün haftaların verilerini çekelim. Bu sefer kazanan sayıları çekmeyeceğiz.
driver = webdriver.Firefox()
driver.get("http://www.mpi.gov.tr/sonuclar/_cs_sanstopu.php")
assert "Şans Topu Çekiliş Sonucu" in driver.title
csvfile = open("sanstopu.csv", "w", newline="")
writer = csv.writer(csvfile)
dates = driver.find_element_by_id("sanstopu-tarihList")
all_options = dates.find_elements_by_tag_name("option")
# Tarih dropdown listesindeki bütün seçenekler üzerinden döngü
for option in all_options:
date = option.get_attribute("value")
option.click()
sleep(1) # tam yüklenmesi için bekle
# Hafta numarasını oku:
haftano = driver.find_element_by_id("sanstopu-hafta").text
# Kazanan İl/İlçe'yi oku (birden fazla olabilir):
il_ilce = driver.find_element_by_id("sanstopu-buyukIkramiyeKazananIl").text
if il_ilce: # if not empty
writer.writerow([date, haftano] + [il_ilce])
else: # devretti veya kazanan il kaydı yok
bilenkisi = driver.find_element_by_id("sanstopu-bilenkisisayisi-5_1_BILEN")
if "Devir" in bilenkisi.text:
writer.writerow([date, haftano] + ["Devir"])
else:
writer.writerow([date, haftano] + ["Yok"])
driver.quit()
csvfile.close()
sanstopudata = pd.read_csv("sanstopu.csv", header=None, names=["tarih","hafta","İl/İlçe"])
sanstopudata.head()
tarih | hafta | İl/İlçe | |
---|---|---|---|
0 | 20160817 | 792 | ANTALYA / KEPEZ - İSTANBUL / BAĞCILAR - KOCAEL... |
1 | 20160810 | 791 | Devir |
2 | 20160803 | 790 | ANKARA / ALTINDAĞ - HATAY / İSKENDERUN |
3 | 20160727 | 789 | ESKİŞEHİR / SİVRİHİSAR - HATAY / ANTAKYA |
4 | 20160720 | 788 | ANKARA / KEÇİÖREN - ANKARA / SİNCAN - ELAZIĞ /... |
st_ililceliste = []
for ii in sanstopudata["İl/İlçe"].values:
if ii not in ["Devir", "Yok"]:
st_ililceliste += ii.split(" - ")
for a,b in Counter(st_ililceliste).most_common(10):
print(a,b)
ANKARA / ÇANKAYA 15 İSTANBUL / FATİH 14 İZMİR / KONAK 12 ANTALYA / MURATPAŞA 11 ANKARA / YENİMAHALLE 9 İSTANBUL / KADIKÖY 9 İSTANBUL / ŞİŞLİ 7 İSTANBUL / BEŞİKTAŞ 7 ANKARA / ALTINDAĞ 7 İSTANBUL / PENDİK 6
Şans Topu oyununda en şanslı ilçe Ankara Çankaya. Yenimahalle ve Kadıköy bu sefer beşinci sırada.
Bütün Sayısal Loto verisini çekmişken, çıkan sayıları (1-49) analiz etmek mümkün. Bu verilerle Sayısal Loto'nun hilesiz olup olmadığını da istatistiksel olarak test edebiliriz.
Sayılara ait sütunlar:
lotodata.iloc[:,2:8]
n1 | n2 | n3 | n4 | n5 | n6 | |
---|---|---|---|---|---|---|
0 | 13 | 18 | 19 | 20 | 38 | 49 |
1 | 2 | 18 | 27 | 31 | 33 | 38 |
2 | 2 | 14 | 22 | 23 | 38 | 47 |
3 | 7 | 12 | 14 | 34 | 40 | 46 |
4 | 12 | 16 | 27 | 36 | 46 | 48 |
5 | 6 | 11 | 21 | 39 | 40 | 48 |
6 | 4 | 35 | 39 | 40 | 42 | 46 |
7 | 6 | 7 | 11 | 16 | 24 | 35 |
8 | 4 | 10 | 20 | 22 | 27 | 33 |
9 | 14 | 16 | 26 | 37 | 38 | 45 |
10 | 7 | 9 | 30 | 33 | 36 | 45 |
11 | 4 | 6 | 14 | 20 | 36 | 37 |
12 | 4 | 8 | 15 | 27 | 33 | 47 |
13 | 3 | 4 | 6 | 21 | 27 | 42 |
14 | 8 | 14 | 25 | 33 | 37 | 48 |
15 | 9 | 11 | 17 | 28 | 35 | 47 |
16 | 5 | 7 | 9 | 18 | 25 | 42 |
17 | 6 | 23 | 26 | 29 | 46 | 47 |
18 | 13 | 14 | 23 | 27 | 32 | 33 |
19 | 1 | 4 | 22 | 29 | 37 | 44 |
20 | 5 | 10 | 18 | 26 | 45 | 48 |
21 | 10 | 13 | 16 | 23 | 44 | 47 |
22 | 6 | 8 | 12 | 20 | 36 | 46 |
23 | 1 | 20 | 34 | 35 | 37 | 42 |
24 | 2 | 3 | 16 | 23 | 33 | 44 |
25 | 5 | 11 | 15 | 19 | 20 | 31 |
26 | 17 | 19 | 25 | 28 | 32 | 34 |
27 | 1 | 8 | 9 | 22 | 24 | 26 |
28 | 17 | 36 | 38 | 41 | 43 | 47 |
29 | 6 | 13 | 18 | 21 | 23 | 24 |
... | ... | ... | ... | ... | ... | ... |
1001 | 14 | 21 | 27 | 35 | 42 | 46 |
1002 | 8 | 13 | 21 | 28 | 34 | 38 |
1003 | 1 | 6 | 10 | 35 | 43 | 49 |
1004 | 15 | 20 | 23 | 30 | 39 | 47 |
1005 | 1 | 8 | 16 | 28 | 39 | 40 |
1006 | 5 | 11 | 17 | 36 | 38 | 41 |
1007 | 3 | 5 | 10 | 22 | 23 | 31 |
1008 | 1 | 2 | 4 | 12 | 35 | 48 |
1009 | 14 | 17 | 28 | 33 | 35 | 49 |
1010 | 1 | 2 | 18 | 19 | 23 | 45 |
1011 | 19 | 32 | 33 | 41 | 46 | 49 |
1012 | 2 | 12 | 13 | 25 | 30 | 39 |
1013 | 11 | 15 | 21 | 33 | 37 | 38 |
1014 | 2 | 16 | 20 | 22 | 25 | 27 |
1015 | 18 | 28 | 29 | 32 | 43 | 44 |
1016 | 14 | 28 | 32 | 38 | 41 | 45 |
1017 | 3 | 4 | 19 | 26 | 27 | 37 |
1018 | 11 | 18 | 30 | 40 | 41 | 43 |
1019 | 13 | 22 | 33 | 38 | 39 | 40 |
1020 | 22 | 26 | 37 | 38 | 39 | 49 |
1021 | 5 | 11 | 24 | 29 | 41 | 45 |
1022 | 4 | 15 | 16 | 18 | 27 | 41 |
1023 | 3 | 17 | 36 | 41 | 46 | 47 |
1024 | 4 | 8 | 14 | 24 | 27 | 36 |
1025 | 2 | 14 | 24 | 25 | 30 | 36 |
1026 | 2 | 5 | 14 | 30 | 31 | 39 |
1027 | 7 | 11 | 16 | 18 | 25 | 26 |
1028 | 6 | 22 | 26 | 31 | 38 | 44 |
1029 | 3 | 14 | 16 | 23 | 27 | 43 |
1030 | 5 | 15 | 20 | 32 | 34 | 47 |
1031 rows × 6 columns
Bu sayıları tek bir liste haline getirelim:
sayilar = np.concatenate(lotodata.iloc[:,2:8].values)
Bir histogram oluşturarak her sayının sıklığına bakalım:
fig = pl.figure(figsize=(12,4))
pl.hist(sayilar, bins=49);
pl.xlabel("Çıkan sayı")
pl.ylabel("Kaç kere");
1-49 arası sayıların sayımları arasında değişkenlik var, ama buna bakarak sayıların olasılıkları farklı diyemeyiz. Eşit olasılık olsa bile, değişkenliğin çeşitli sebepleri olabilir:
En çok çıkan on sayı ve kaç kere çıktıkları:
Counter(sayilar).most_common(10)
[(38, 150), (18, 145), (21, 144), (16, 143), (1, 142), (36, 139), (26, 138), (40, 138), (47, 138), (17, 134)]
Bu dağılımlara bakarak Sayısal Loto hileli veya hilesiz demek mümkün mü? Bütün sayıların (1-49) eşit olasılıkta olduğunu varsayarak, buradaki gibi bir değişkenlik ortaya çıkabilir mi? Bu hipotezi test etmek için Pearson ki-kare testini uygulamamız gerekir. Ancak, her bir çekilişte sayıların birbirinden farklı çıkması mecburiyeti sebebiyle bu testin farklı bir versiyonunu uygulamamız gerek.
(Haigh, J. (1997), The Statistics of the National Lottery. Journal of the Royal Statistical Society: Series A (Statistics in Society), 160: 187–206. doi:10.1111/1467-985X.00056)
$W$ istatistiğini aşağıdaki gibi tanımlayalım.
$$ W = \frac{M(M-1)}{(M-m)Dm} \left( \sum_{i=1}^{M} X_i - \frac{m^2 D^2}{M}\right) $$Burada $M=49$ çekilebilecek sayılar, $m=6$ bir çekilişte kaç top çekildiği, $D$ çekiliş sayısı, $X_i$ $i$ numaralı topun kaç kere çekildiğidir.
M = 49
m = 6
D = len(sayilar)/6
X = [f[1] for f in sorted(Counter(sayilar).most_common())]
W = M*(M-1)/((M-m)*D*m) * (sum([x**2 for x in X]) - m**2 * D**2 / M )
print(W)
46.9436311551217
Bu yeni istatistik $\chi^2_{M-1}$ dağılımına uyar. Böylece hilesizlik hipotezinin p değerini bulabiliriz.
from scipy.stats import chi2
1-chi2.cdf(W,M-1)
0.51610614604308425
Sözlü olarak ifade edersek: Loto çekilişinin hilesiz (yani bütün sayıların eşit olasılıkta düştüğü) varsayımıyla, buradaki kadar veya daha büyük bir değişkenlik gözleme olasılığı %52'dir. Bu olasılık %5 veya daha düşük olsa hilesizlik varsayımını reddedebilirdik, ama bu durumda reddedemiyoruz. Sayısal Loto'da bazı sayıların daha yüksek olasılıklarla çıktığını düşünmek için bir sebep yok.