You are on page 1of 410

İstatistik ve Veri Analizi

Burak Bayramlı
Sayılar ve Kuramlar

https://burakbayramli.github.io/dersblog/sk/

Tüm Dosyalar, Kodlar

https://github.com/burakbayramli/classnotes
Olasılık, Dağılımlar, Giriş
Dağılımlar
Doğada yapılan çoğu ölçümlerin sıklık / frekans grafiğini alınca sonucun aşağıda
gibi çıkması ilginçtir.

Mesela herhangi bir şehirde, ilçede 2000 yetişkinin kilosunu ölçün. Grafiğini
alın kesinlikle yukarıdaki tepe şekli çıkacak. Ya da, 1000 kişinin boyunu ölçün,
aynı tepe şekli. Keskin nişancının hedefe attığı kurşunların hedefe yakınlığını
ölçüp sıklık grafiğine bakın. Gene aynı tepe şekli! Nasıl oluyor bu iş? Açıklama
için, normal dağılım eğrisinden bahsetmemiz gerekecek. Not: Frekans grafiği,
X sayısının ne kadar çıktığını sayıp, Y ekseni üzerinde bu sayıyı X’e tekabül ed-
erek kolon olarak göstermeye denir. Mesela, 60 kilo değeri 13 kere çıktı ise, X=60,
Y=13 gibi bir kolon çizilecektir.
Normal Dağılım Eğrisi
Normal dağılımın olasılık kavramı ile yakın bağları var. Bu konuda ünlü bir
deney zar atma deneyidir. Elimizde tek bir zar var, ve bu zarı arka arkaya atalım.
Sabrımız yeterse 1000 kere atalım. Sonuçta, frekans grafiği eşit bir dağılımda ola-
caktır.
Bunun sebeplerini anlamak zor değil. Her zar atış olayı birbirinden bağımsız, ve
her sayının üstte gelme ihtimali birbirine eşit olduğu için (1/6), her sayıdan eşit
miktarda gelecek. Tabii bu durumu görmek için deneyin birçok kere tekrarlan-
ması gerekiyor.
Şimdi deneyi biraz değiştirelim, bir yerine 2 zar atalım. Hatta 4 zar atalım, ve bu
sefer sıklık grafik hanesine yazmadan çıkan sayıları önce toplayalım. Bu çıkan
toplamın sıklık grafiğini alalım.
İşte bu sıklık grafiği göreceğiz ki, üstte görülen tepe grafiğine yaklaşıyor. Ne
kadar çok zar atarsak, bu benzerlik o kadar daha fazla olacaktır.
Sebep kabaca tahmin edilebilir, 1 ile 6 arası sayıların tek bir zardan gelme olasılığı
aynı, evet. Fakat toplamlara gelince, mesela iki zarlı örnekte, 10 sayısının olasılığı
2 sayısından daha yüksek. Çünkü, 10 sayısını 5-5, 4-6 ya da 6-4 ile alabiliyoruz. 2
sayısı sadece 1-1 ile geliyor.
Buradan şu sonuç çıkabilir: Eğer doğada ölçtüğümüz bir kavramın oluşmasında

1
birden fazla etken var ise, o ölçümlerin sıklığı her zaman çan (bell shape) şeklinde
olacaktır. Bir kişinin boyunu, kilosunu etkileyen pek çok diğer faktör olduğu
için bu ölçütlerin dağılımlarının normal çıktığı iddia edilebilir. Üstteki örnekteki
toplamların dağılımının çan eğrisine yaklaşması durumu istatistikte Merkezi Limit
Teorisi ile ispatlanmıştır.
Bu durumu hesap yapıp kendimiz de görebiliriz. İlk önce, random.org sitesin-
den rasgele sayı üreteceğiz. Bu site kimsenin kullanmadığı radyo kanallarından
atmosfer gürültüsü dinleyip, bu gürültüleri sayısal değere çevirerek rasgele sayı
üretiyor. Gerçek rasgele sayı üretmek pek kolay bir iş değil. Her ne kadar bil-
gisayarımızda rasgele sayı üreten birçok algoritma olsa bile, bu algoritmalar belli
bir sayı üretiminden sonra kendini tekrar etmeye başlıyorlar, bu sebeple onlara
yarı-rasgele (pseudorandom) sayılar ismi veriliyor. Gerçek rasgele sayılar için
dış bir kaynağa bağlanmak bir seçenek olabilir. Ama şunu da söylemek lazım,
simulasyon tekniklerinin tamamı için yarı-rasgele sayılar yeterlidir.
Neyse bahsedilen siteden rasgele sayıları üretip, bir veri dosyasına koyuyoruz,
kod ile bu sayıları okuyup, ilk önce teker teker sayıların sıklık grafiğini, ondan
sonra sayıları üçer üçer toplayıp, onların grafiğini alıp göstereceğiz.

A = np.loadtxt('rasgele.dat')
plt.hist(A, 50)
plt.savefig('stat_intro_08.png')

A = np.loadtxt('rasgele.dat');
B = []

i = 1;

while (i < 998):


toplam = 0
s = A[i]
toplam = toplam + s
s = A[i+1]
toplam = toplam + s
s = A[i+2]

2
toplam = toplam + s
B.append(toplam/3)
i = i + 3

plt.hist(B, 50);
plt.savefig('stat_intro_09.png')

Dağılım normal dağılıma benziyor.


Giriş konularını teker teker işlemeden önce derinleme bir dalış yapıp tüm kavram-
lara değinelim. İstatistiğin temel öğelerinden biri yoğunluk fonksiyonudur (prob-
ability density function), mesela

(x−µ)2
f(x) = N · e− 2σ2

1
ki N normalize edici bir faktör, √2πσ2
, σ, µ dışarıdan bizim tanımladığımız parame-
treler. N kısmı çarpılan bölümün biri bölen entegrali aslında, ki böylece tüm
yoğunluğun entegrali (yani tüm olasılık) 1 olabilsin. Bu şekilde pek çok fonksiyon
olasılık yoğunluğu haline getirebilir.
Farklı yoğunluk fonksiyonları var, hangisinin hangi tür veriye uyacağını bulmak
istatistikçinin önemli işlerinden. Yoğunluk çok boyutlu da olabilir.
Tek boyutlu bir yoğunluk fonksiyonun x-ekseni üzerindeki alanı her zaman 1’e
eşit olmalıdır (yani yoğunluğun −∞, ∞ üzerinden entegrali her zaman 1 sonu-
cunu vermeli). Olasılık teorisinin işlemesi için bu gerekli.
Yoğunluk fonksiyonları doğadan gelen bir tek ölçümü alırlar, boy, kilo gibi, ve
onun ’olasılık yoğunluğunu’ hesaplarlar. Üstteki örnek için mesela 3 ve 1 değerlerinin
yoğunluğunu hesaplayalım,

mu = 0
sigma = 1
def f(x): return (1 / (np.sqrt(2 * np.pi * np.power(sigma, 2)))) * \
(np.power(np.e, -(np.power((x - mu), 2) / (2 * np.power(sigma, 2)))))
print ('3 icin', f(3))
print ('1 icin', f(1))

3
3 icin 0.004431848411938008
1 icin 0.24197072451914337

1 değeri 3’ten daha düşük – çünkü bu 0 merkezli bir yoğunluk fonksiyonu, sıfıra
ne kadar yakınsa yoğunluk o kadar fazla. Bu fonksiyonun tasarlanış şekli böyle.
Eğer tüm olası değerleri x’e verip grafiklesek,

x = np.array(np.linspace(-3,3,num=50))
y = f(x)
plt.plot(x,y)
plt.savefig('stat_intro_03.png')

Dikkat: yoğunluk fonksiyonu olasılık değildir; bazı yoğunluk değerleri bazı sürekli
fonksiyonlarda 1’den fazla çıkabilir! Sürekli ortamda olasılık bir entegraldir, daha
önce söylediğimiz gibi tüm fonksiyon alanı 1. Altta bir normal dağılım yoğunluk
fonksiyonu solda, onun entegrali kümülatif dağılım fonksiyonu (CDF) sağda.

CDF bize mesela üstteki grafikte değerin 0 ila 1.5 arasında olma olasılığını veriyor.
CDF hesabı için istatistik yazılım paketlerinde muhakkak bir çağrı olur, mesela
scipy.stats ile,

4
import scipy.stats
print (scipy.stats.norm.cdf(1.5,0,1))

0.9331927987311419

1’ye yakın oldukca büyük bir sayı, grafiğe uygun. CDF her zaman 0’dan sorulan
değere kadar olan alanı verir, tüm alanın 1 olması bilgisinden hareketle bu öğeler
biraraya koyulup ek sonuçlara varılabilir, mesela değerin 1.5’tan büyük olma
olasılığı için 1-CDF(1.5). Eğer -2 ile 2 arası olma olasılığını istiyorsak CDF(2)-
CDF(-2).
Veriden Fonksiyon
Şimdi mesela elimizde bir grup kişinin 68 kiloya ne kadar yakın / uzak olduğunun
verisi var (68’ten az olanlar eksi değerli olacak tabii). Veriyi grafikleyelim,

import pandas as pd
df = pd.read_csv('boy68.csv')
df.hist()
plt.savefig('stat_intro_04.png')
plt.hold(False)

Dikkat veriyi grafiklemek için histogram kullandık, yani verinin “frekansını”


bastık, bu tür grafiklere göre mesela eğer 3 değeri 10 kere geldi, 1 değeri 2 kere
geldi ise 3’un üzerindeki sütun diğerinden daha yüksek olacaktır, çünkü onun
“frekansı” daha fazla.
Bir histogramın aslında yoğunluk fonksiyonunun verisel / ayrıksal hali olduğu
da düşünülebilir.
Şimdi biz analizci olarak bu grafiğe bakarız, ve deriz ki acaba biraz önceki f(x)
yoğunluğu bu veriye “uyar mı”? Uyar ise ne güzel, f(x) bir sürekli fonksiyon,
derli toplu, onun üzerinde pek çok işlem yapabiliriz, bu veriyle işlem yaparken
o fonksiyonu kullanmak bize bazı avantajlar sağlayabilir. Eğer temsil edemez ise
hangi başka yoğunluk edebilir? Vs.. İstatistik notlarımızda tüm bunların cevabını
bulacağız. Bazen yoğunlukların sabitleri olacak (mesela merkez 0 yerine başka
bir yerde olsun diyebilmek), ve bu sabitleri, hiperparametreleri veriden hesapla-

5
manın yolları var.. Veriden teoriksel yoğunluğa, oradan başka teorilere, oradan
tekrar veriye atlayabilmek istatistiğin özü.
Diyelim ki bir şekilde verinin Normal olduğuna karar verdik (bunun testleri,
metotu var tabii) o zaman veriye uygun µ, σ parametrelerini nasıl bulacağız?
Veriyi kullanıp bir hesap yaparak! Tahmin ediciler burada devreye giriyor,
P mesela
Normal dağılım için µ tahmin edici / kestirme hesaplayıcısı µ̂ = xi /n, yani
verinin ortalaması [5]!
Ayrıksal Dağılımlar
Normal dağılım, üstel dağılım birer sürekli fonksiyondurlar, tek boyutta x bir reel
sayıdır. Fakat ayrıksal olan dağılımlar da var, mesela Poisson,

f(x) = e−λ λx /x!

ki dışarıdan tanımlı parametre λ. Burada geçilen x tam sayı değerler, 1,2,3 gibi..
Ayrıksal olasılık kütle fonksiyonu (süreklideki olasılık yoğunluk yerine) sonuçları
birer olasılık olarak kabul edilebilir, çünkü tam sayılar bir nevi kutucuk, geniş
alan oluştururlar.

from scipy.special import factorial

def poisson_distribution(k, lam):


return (lam ** k * np.exp(-lam)) / factorial(k)

x = np.array(range(20))
y = poisson_distribution(x,lam=5)
plt.plot(x,y)
plt.savefig('stat_intro_12.png')

Poisson dağılımın sola doğru meyilli olabileceğini görüyoruz üstte, demek ki


veride bu tür bir şekil görürsek onu temsil için Poisson seçebiliriz.
Rasgele Değişkenler

6
Rasgele değişkenler çoğunlukla büyük harfle gösterilirler, mesela X ya da Y gibi
ve bir dağılıma / onun yoğunluk fonksiyonuna göbekten bağlantılıdırlar. On-
ları formül içinde görünce sanki her bakışınızda içlerinin başka bir rasgele sayı
ile doldurulduğunu düşünebiliriz, ama tabii ki bu “rasgelelik” o RD’nin bağlı
olduğu dağılıma göredir. Eğer X üstteki f(x) ile dağılmış dersek, o zaman sıfıra
yakın daha çok, 5’e yakın daha az değerler üretilir.
RD’leri formül içinde bile kullanabilirsiniz, mesela

3X + log X

diyebilirdim. Başka değişkenler Y, Z vs formüle ekleyebilirdim. RD’lerin bu


tür işlemleri sonucu başka tür RD’ler ortaya çıkabilir (yani sonuç RD’nin bağlı
olduğu dağılım farklı bir dağılım olabilir), İstatistik ayrıca bu sonuç dağılımlarının
ne olabileceği hakkında güzel dersler içerir.
Tekrarlamak gerekirse, f(x)’e verilen x ile X’in değerleri birbirine karışmasın. İlki
için bildiğimiz bir x’in olasılığını soruyoruz, mesela “3’ün olasılığı ne?” diğerinde
bize f(x)’e göre bir sayı üret diyoruz, ve 0.3, 0.1, 0., 0.5 gibi değerler geliyor, kırk
yılda bir de bir 3 geliyor belki.
Şimdi istatistiğin temelini oluşturan olasılık teorisinden bahsedelim.
Olasılık
Örneklem Uzayı (Sample Space)
Örneklem uzayı Ω bir deneyin mümkün tüm olasılıksal sonuçların (outcome)
kümesidir. Eğer deneyimiz ardı ardına iki kere yazı (T) tura (H) atıp sonucu
kaydetmek ise, bu deneyin mümkün tüm sonuçları şöyledir

Ω = {HH, HT , T H, T T }

Sonuçlar ve Olaylar (Outcomes and Events)


Ω içindeki her nokta bir sonuçtur (outcome). Olaylar Ω’nin herhangi bir alt
kümesidir ve sonuçlardan oluşurlar. Mesela üstteki yazı-tura deneyinde “iki
atışın içinden ilk atışın her zaman H gelmesi olayı” böyle bir alt kümedir, bu
olaya A diyelim, A = {HH, HT }.
Ya da bir deneyin sonucu ω fiziksel bir ölçüm , diyelin ki sıcaklık ölçümü. Sıcaklık
±, reel bir sayı olduğuna göre, Ω = (−∞, +∞), ve sıcaklık ölçümünün 10’dan
büyük ama 23’ten küçük ya da eşit olma “olayı” A = (10, 23]. Köşeli parantez
kullanıldı çünkü sınır değerini dahil ediyoruz.
Örnek
10 kere yazı-tura at. A = “en az bir tura gelme” olayı olsun. Tj ise j’inci yazı-tura
atışında yazı gelme olayı olsun. P(A) nedir?

7
Bunun hesabı için en kolayı, hiç tura gelmeme, yani tamamen yazı gelme olasılığını,
Ac ’yi hesaplamak, ve onu 1’den çıkartmaktır. c sembolü “tamamlayıcı (comple-
ment)” kelimesinden geliyor.

P(A) = 1 − P(Ac )

= 1 − P(hepsi yazı)

= 1 − P(T1 )P(T2 )...P(T10 )

 10
1
=1− ≈ .999
2

Rasgele Değişkenler (Random Variables)


Bir rasgele değişken X bir eşlemedir, ki bu eşleme X : Ω → R her sonuç ile bir reel
sayı arasındaki eşlemedir.
Kabaca anlatmak gerekirse rasgele değişken X’in, bağlı olduğu dağılımın zar
atılmış değerini içerdiği, ve bu değerlerden bazılarını filtreyebildiği, düşünülebilir.
Her rasgele değişken tek bir dağılıma bağlıdır, ve X’e ne zaman referens eder-
sek onun içinin bu dağılımdan gelen bir sayı ile doldurulduğunu hayal etmek
gerekir, tabii ki çoğu dağılımda bazı sayılar daha olasıdır, ve bu içi doldurmanın
çoğunlukla bu olası sayılardan olacağı düşünülebilir.
Olasılık derslerinde bir noktadan sonra artık örnekleme uzayından bahsedilmez,
ama bu kavramın arkalarda bir yerde her zaman devrede olduğunu hiç aklımızdan
çıkartmayalım.
Örnek
10 kere yazı-tura attık diyelim. VE yine diyelim ki X(ω) rasgele değişkeni her ω
sıralamasında (sequence) olan tura sayısı. Mesela eğer ω = HHT HHT HHT T ise
X(ω) = 6. Tura sayısı eşlemesi ω sonucunu 6 sayısına eşledi.
Örnek
Rasgele değişken X iki zar atınının toplamı olabilir.

P(X = 2) = P(iki tane 1 gelme şansı) = 1/36

P(X = 3) = P((1, 2), (2, 1)) = 2/36

..
.

8
Örnek
Ω = {(x, y); x2 + y2 6 1}, yani küme birim çember ve içindeki reel sayılar (unit
disc). Diyelim ki bu kümeden rasgele seçim yapıyoruz. Tipik bir sonuç ω =
(x, y)’dir. Tipik rasgele değişkenler ise X(ω) = x, Y(ω) = y, Z(ω) = x + y olabilir.
Görüldüğü gibi bir sonuç ile reel sayı arasında eşleme var. X rasgele değişkeni bir
sonucu x’e eşlemiş, yani (x, y) içinden sadece x’i çekip çıkartmış. Benzer şekilde
Y, Z değişkenleri var.
Toplamsal Dağılım Fonksiyonu (Cumulative Distribution Function -CDF-)
Tanım
X rasgele değişkeninin CDF’i FX : R → [0, 1] tanımı

FX (x) = P(X > x)

Eğer X ayrıksal ise, yani sayılabilir bir küme {x1 , x2 , ...} içinden değerler alıyorsa
olasılık fonksiyonu (probability function), ya da olasılık kütle fonksiyonu (prob-
ability mass function -PMF-)

fX (x) = P(X = x)

Bazen fX , ve FX yerine sadece f ve F yazarız.


Tanım
R+∞
Eğer X sürekli (continuous) ise, yani tüm x’ler için fX (x) > 0, −∞ f(x) dx = 1
olacak şekilde bir fX mevcut ise, o zaman her a 6 b için

Zb
P(a < X < b) = fX (x) dx
a

Bu durumda fX olasılık yoğunluk fonksiyonudur (probability density function


-PDF-).

Zx
FX = fX (t) dt

Ayrıca FX (x)’in türevi alınabildiği her x noktasında fX (x) = FX0 (x) demektir.
Dikkat! Eğer X sürekli ise o zaman P(X = x) = 0 değerindedir. f(x) fonksiyonunu
P(X = x) olarak görmek hatalıdır. Bu sadece ayrıksal rasgele değişkenler için
işler. Sürekli durumda olasılık hesabı için belli iki nokta arasında entegral hesabı
yapmamız gereklidir. Ek olarak PDF 1’den büyük olabilir, ama PMF olamaz.
PDF’in 1’den büyük olabilmesi entegrali bozmaz mı? Unutmayalım, entegral
hesabı yapıyoruz, noktasal değerlerin 1 olması tüm 1’lerin toplandığı anlamına
gelmez.

9
Olasılık yoğunluk fonksiyonundaki yoğunluk kelimesini tekrar vurgulamak iyi
olur. Özellikle sürekli dağılım bağlamında bu kavramı hakiki yoğunluk gibi
düşünmek iyi olur. Mesela tamamı aynı maddeden olan bir küp düşünelim,
yoğunluğu 2. Bu küpün neresine bakarsak bakalım yoğunluk hep aynı olur, 2.
Yoğunluk bir bakıma belli bir alanı temsil eden bir özet. Sonra bu küpün kütlesini
bulmak için habire bir sürü 2’yi üst üste koyup toplamıyoruz; kütle hesabı için
bir çarpım yapıyoruz / entegral alıyoruz.
Örnek olarak çan eğrisi / normal dağılımdan sayılar üretelim. Bu dağılımda
“ağırlık” ortadadır. Rasgele sayı üretip histograma bakalım,

mu=10;sigma=0.1
data = np.random.normal(mu,sigma,100)
hst = plt.hist(data, normed=True,bins=6)
print hst[0]

[ 1.79234778 2.81654651 4.60889429 2.17642231 1.15222357 0.25604968]

Görüldüğü gibi 1’den büyük değerler var, ve “yoğunluk” ortadaki iki kutuda.
Olasılık yoğunluk hesabını formülsel yapsak, mesela 10 noktasının ağırlığı nedir
desek,

print norm.pdf(10,mu,sigma)

3.98942280401

Şimdi olasılık değerleri, P(a < X < b) ifadesi, alan hesabı ve rasgele değişkenler
arasındaki bağlantıyı biraz daha detaylandırmak gerekirse; X bir rasgele değişken,
nokta (kesin) değeri olmasa da denklemde kullanılabiliyor, toplanıp çıkartılabiliyor,
vs. Bu değişkene “değeri sorulduğunda” bu değer o X’in bağlı olduğu dağılımın
zar atması sonucunda gelecektir. Bu zar atışı ise olasılık fonksiyonunun yüksek
değer verdiği x değerlerini daha fazla üretecektir doğal olarak. Bunu kavram-
sal olarak söylüyoruz tabii, istatistiki problemlerde illa bu zar atışını yapmamız
gerekmeyebilir.

Mesela üstteki dağılım için 100 ve çevresindeki değerlerinin olasılığı çok yüksek,
mesela grafiğe bakarsak, kabaca, fX (100) = 0.027, ya da fX (120) = 0.015. Demek
ki bu dağılıma bağlı bir X, o çevreden daha fazla değer üretir.
Rasgele değişkene bağlı olasılık hesabı için ise, mesela P(X < 120) diyelim, bu
ifade ile ne diyoruz? Sorduğumuz şudur, zar atışlarının belli değer altında gelmesi

10
olasılığı... Bu hesap tabii ki bir alan hesabıdır, x eksenindeki belli aralıklar, bölgelerin
toplam olasılığının ne olacağı o bölgenin tam üzerindeki yoğunluğun toplamı
olacaktır, aynen tek değerlerin olasılığının o tek değerin yoğunluk değeri ol-
ması gibi. Yani bu tür olasılık hesapları direk fX (x) üzerinden yapılacaktır. Zar
atıldığında 100’den küçük değerlerin gelme olasılığı nedir? Alana bakarsak 0.5,
yani 1/2, tüm alanın yarısı. Bu normal, çünkü 100’den küçük değerler dağılımın
yarısını temsil ediyor. 200’den küçük değerler gelme olasılığı nedir, yani P(X <
200)? Olasılık 1. fX alanının tamamı. Yani kesin. Çünkü yoğunluk fonksiy-
onunun tamamı zaten 200’den küçük değerler için tanımlı. “Yoğunluk orada”.
Tanım
X rasgele değişkeninin CDF’i F olsun. Ters CDF (inverse cdf), ya da yüzdelik
dilim fonksiyonu (quantile function)

−1
F (q) = inf x : F(x) 6 q

ki q ∈ [0, 1]. Eğer F kesinlikle artan ve sürekli bir fonksiyon ise F−1 (q) tek bir x
sayısı ortaya çıkarır, ki F(x) = q.
Eğer inf kavramını bilmiyorsak şimdilik onu minimum olarak düşünebiliriz.
F−1 (1/4) birinci çeyrek
F−1 (1/2) medyan (median, ya da ikinci çeyrek),
F−1 (3/4) üçüncü çeyrek
olarak bilinir.
d
İki rasgele değişken X ve Y dağılımsal olarak birbirine eşitliği, yani X = Y eğer
FX (x) = FY (x), ∀x. Bu X, Y birbirine eşit, birbirinin aynısı demek değildir. Bu
değişkenler hakkındaki tüm olasılıksal işlemler, sonuçlar aynı olacak demektir.
Uyarı! “X’in dağılımı F’tır” beyanını X ∼ F şeklinde yazmak bir gelenek. Bu biraz
kötü bir gelenek aslında çünkü ∼ sembolü aynı zamanda yaklaşıksallık kavramını
belirtmek için de kullanılıyor.
Tanım
x1 , .., xn verilerini içeren örneklemin (sample) ortalaması

1X
x̄ = xi (1)
n

Dikkat bu örneklemdeki verinin ortalaması. Hiçbir dağılım hakkında hiçbir faraziye


yapmadık. Ayrıca tanım kullandık, yani bu ifadenin ne olduğu tamamen bize
bağlı.
Örneklem ortalaması sadece tek merkezi bir tepesi olan (unimodal) dağılımlar

11
için geçerlidir. Eğer bu temel varsayım geçerli değilse, ortalama kullanarak yapılan
hesaplar bizi yanlış yollara götürür. Ayrıca bir dağılımı simetrik olup olmadığı
da ortalama ya da medyan kullanılıp kullanılmaması kararında önemlidir. Eğer
simetrik, tek tepeli bir dağılım var ise, ortalama ve medyan birbirine yakın ola-
caktır. Fakat veri başka türde bir dağılım ise, o zaman bu iki ölçüt birbirinden çok
farklı olabilir.
Dağılımlar
Bernoulli Dağılımı
X’in bir yazı-tura atışını temsil ettiğini düşünelim. O zaman P(X = 1) = p, ve
P(X = 0) = 1 − p olacaktır, ki p ∈ [0, 1] olmak üzere. O zaman X’in dağılımı
Bernoulli deriz, X ∼ Bernoulli(p) diye gösteririz. Olasılık fonksiyonu, x ∈ {0, 1}.

f(x; p) = px (1 − p)(1−x)

Yani x ya 0, ya da 1. Parametre p, 0 ile 1 arasındaki herhangi bir reel sayı.

E(X) = p

Var(X) = p(1 − p)

Uyarı!
X bir rasgele değişken; x bu değişkenin alabileceği spesifik bir değer; p değeri ise
bir parametre, yani sabit, önceden belirlenmiş reel sayı. Tabii istatistiki problem-
lerde (olasılık problemlerinin tersi olarak düşünürsek) çoğunlukla o sabit parame-
tre bilinmez, onun veriden hesaplanması, kestirilmesi gerekir. Her halükarda,
çoğu istatistiki modelde rasgele değişkenler vardır, ve onlardan ayrı olarak parame-
treler vardır. Bu iki kavramı birbiriyle karıştırmayalım.
Binom Dağılımı (Binomial Distribution)
Her biri birbirinden bağımsız ve birbiriyle aynı Bernoulli Dağılımına sahip deneyler-
den n tane yapıldığını farzedelim, ki bu deneylerin sadece iki sonucu olacak
(1/0. başarı/başarısızlık, vs). Bu deneylerin p’sı aynı olacak. O zaman n deney
içinden toplam kaç tanesinin başarılı olduğunu gösteren X rasgele değişkeni Bi-
nom Dağılımına sahiptir denir.
Bu dağılımın yoğunluğu
 
n x
f(x; p, n) = p (1 − p)n−x
x

n!
= px (1 − p)n−x
x!(n − x)!

12
Bu fonksiyonun parametreleri p, n değerleridir. Beklenti ve varyans

µ = E(X) = np

σ2 = Var(X) = np(1 − p)

Birörnek (Uniform) Dağılım

X birörnek, Uniform(a, b) olarak dağılmış deriz, ve bu X ∼ Uniform(a, b) olarak


yazılır eğer

1
b−a
x ∈ [a, b] icin
f(x) =
0 diger

işe ve a < b olacak şekilde. CDF hesabı olasılık eğrisinin entegralini temel alır,
düz dağılım bir a, b arasında 1/b − a yüksekliğinde bir dikdörtgen şeklinde
olacağı için, bu dikdörtgendeki herhangi bir x noktasında CDF dağılımı, yani
o x’in başlayıp sol tarafın alanının hesabı basit bir dikdörtgensel alan hesabıdır,
yani x − a ile 1/b − a’nin çarpımıdır, o zaman

 0 x<a
x−a
F(x) = x ∈ [a, b]
 b−a
1 x>b

Beklenti E[X] = 1.
Multinom (Multinomial) Dağılım

13
Çok boyutlu X rasgele değişkeni, ki boyutu k olarak tanımlayalım, X ∼ Mult(m, p)
olarak dağılmıştır deriz, eğer bu dağılım k sınıf, kategori içinden birinin seçildiği
durumda m deney içinden kaç tanesinin hangi kategorilerde olduğunu temsil
ediyorsa, ve p çok boyutludur. Multinom, binom dağılımının çok kategorili ha-
lidir denebilir, ya da binom, multinomun k = 2 halidir. Olasılıklar,

P(X1 = m1 , ..., Xk = mk ) = f(x; m, p)

ki mk , k’inci kategoriden kaç tane görüldüğü. Olasılık yoğunluk fonksiyonu,

m!
f(x; m, p) = px1 1 · ·px1 k
x1 ! · ·!xk !

Beklenti E(X) = p. Her kategori, hücre i için tabii ki E(Xi ) = p, varyans ise
Var(Xi ) = mpi (1−pi ). Kovaryans Covar(Xi , Xj ) = −mpi pj . Bunun türetilmesini
ilerideki bir bölümde göreceğiz.

Poisson Dağılımı
Sayım verilerini (count data) modellemek için bu dağılım çok kullanılır. Tanımı,

λx
f(x) = P(X = x) = e−λ
x!

Poisson dağılımını tanımlayan λ sabitidir. Belli bir Poisson yoğunluk fonksiy-


onu göstermek için f(x; λ) gibi bir tanım görebilirsiniz. Bu dağılımın önemli bir
özelliği ortalama ve varyansının aynı olmasıdır.
Normal (Gaussian) Dağılım
X ∼ N(µ, σ2 ) ve PDF

1 1 2
f(x) = √ exp − 2 (x − µ) , x ∈ R
σ 2π 2σ

ki µ ∈ R ve σ > 0 olacak şekilde. Bazıları bu dağılımı

14

1 1
= √ exp − (x − µ)σ−2 (x − µ)
σ 2π 2

olarak gösterebiliyor, çünkü bu şekilde (birazdan göreceğimiz) çok boyutlu Gaus-


sian formülü ile alaka daha rahat gözüküyor.
İleride göreceğiz ki µ bu dağılımın “ortası”, ve σ onun etrafa ne kadar “yayıldığı”
(spread). Normal dağılım olasılık ve istatistikte çok önemli bir rol oynar. Doğadaki
pek çok olay yaklaşıksal olarak Normal dağılıma sahiptir. Sonra göreceğimiz
üzere, mesela bir rasgele değişkenin değerlerinin toplamı her zaman Normal
dağılıma yaklaşır (Merkezi Limit Teorisi -Central Limit Theorem-).
Eğer µ = 0 ve σ = 1 ise X’in standart Normal dağılım olduğunu söyleriz. Ge-
leneğe göre standart Normal dağılım rasgele değişkeni Z ile gösterilmelidir, PDF
ve CDF φ(z) ve Φ(z) olarak gösterilir.
Φ(z)’nin kapalı form (closed-form) tanımı yoktur. Bu, matematikte “analitik bir
forma sahip değil” demektir, formülü bulunamamaktadır, bunun sebebi ise Nor-
mal PDF’in entegralinin analitik olarak alınamıyor oluşudur.
Bazı faydalı püf noktaları
1. Eğer X ∼ N(µ, σ2 ) ise, o zaman Z = (X − µ)/σ ∼ N(0, 1).
2. Eğer Z ∼ N(0, 1) ise, o zaman X = µ + σZ ∼ N(µ, σ2 )
3. Eğer Xi ∼ N(µi , σ2i ), i = 1, 2, ... ve her Xi diğerlerinden bağımsız ise, o zaman

X
n X
n X
n 
2
Xi = N µi , σ
i=1 i=1 i=1

Tekrar X ∼ N(µ, σ2 ) alırsak ve 1. kuraldan devam edersek / temel alırsak şu da


doğru olacaktır.

P(a < X < b) =?

 
a−µ X−µ b−µ
=P < <
σ σ σ
     
a−µ b−µ b−µ a−µ
=P <Z< =Φ −Φ
σ σ σ σ

İlk geçişi nasıl elde ettik? Bir olasılık ifadesi P(·) içinde eşitliğin iki tarafına aynı
anda aynı toplama, çıkarma operasyonlarını yapabiliriz.
Son ifadenin anlamı şudur. Eğer standart Normal’ın CDF’ini hesaplayabiliy-
orsak, istediğimiz Normal olasılık hesabını yapabiliriz demektir, çünkü artık X
içeren bir hesabın Z’ye nasıl tercüme edildiğini görüyoruz.

15
Tüm istatistik yazılımları Φ(z) ve Φ(z)−1 hesabı için gerekli rutinlere sahiptir.
Tüm istatistik kitaplarında Φ(z)’nin belli değerlerini taşıyan bir tablo vardır. Ders
notlarımızın sonunda da benzer bir tabloyu bulabilirsiniz.
Örnek
X ∼ N(3, 5) ise P(X > 1) nedir? Cevap:

1−3
P(X > 1) = 1 − P(X < 1) = 1 − P(Z < √ )
5

= 1 − Φ(−0.8944) = 1 − 0.19 = .81

Soru P(a < X < b) formunda a kullanmadı, sadece b olduğu için yukarıdaki
form ortaya çıktı. Python ile

from scipy.stats.distributions import norm


print norm.cdf(-0.8944)
print 1-norm.cdf(-0.8944)
0.18555395624
0.81444604376

Soru
Φ(1.13) nedir?

Kümülatif olasılık fonksiyonuna geçilen z değerlerinin bir diğer ismi ise z-skoru.
Bu değerleri anlamanın bir yolu (skora çevirilmiş) orijinal değerlerin “kaç stan-
dart sapma uzakta” olduğunu göstermesidir. Bundan sonra ölçümüz standart
sapma haline geliyor, ve bu değer sola ya da sağa çekildikçe ona tekabül eden
alan (üstte sarı renkle gösterilen kısım), yani olasılık azalıp çoğalıyor. Grafikte
mesela “1.13 standart sapma” yani z-skor nereyi gösteriyor deyince, görülen şekil
/ olasılık ortaya çıkıyor. Tabii temel aldığımız değer baştan z-skorunun ken-
disi ise dağılım standart dağılım ve standart sapma 1 olduğu için “kaç standart
sapma” ile z-skoru birbirine eşit. z-Skorları hakkında ek bir anlatım bu bölümün
sonunda bulunabilir.
Örnek

16
Şimdi öyle bir q bul ki P(X < q) = .2 olsun. Yani Φ−1 (.2)’yi bul. Yine X ∼ N(3, 5).
Cevap
Demek ki tablodan .2 değerine tekabül eden eşik değerini bulup, üstteki formül
üzerinden geriye tercüme etmemiz gerekiyor. Normal tablosunda Φ(−0.8416) =
.2,

q−µ q−µ
.2 = P(X < q) = P(Z < ) = Φ( )
σ σ
O zaman

q−µ q−3
−0.8416 = = √
σ 5

q = 3 − 0.8416 5 = 1.1181

Entegral ile Normalize Etmek


Normal Dağılımın formülünü türetmek ve aynı anda normalize etmenin nasıl
olduğunu anlamak için alttakilere bakalım. Basit bir formülden başlayarak türetelim.
2
Daha önce [3]’te e−x Nasıl Entegre Edilir kısmında gördük,

Z +∞
2 √
e−x dx = π
−∞

olduğunu görmüştük. Dikkat edersek bu integral bir formülün olasılıksal dağılım


olup olmadığını kontrol etmek için kullandığımız integrale benziyor. Eğer inte-√
gral 1 çıkarsa onun
√ olasılıksal dağılım oldu ğunu biliyoruz. Üstteki sonuç π,
fakat iki tarafı π’ye bölersek, sağ taraf 1 olur ve böylece solda bir dağılım elde
ederiz. Yani

Z +∞
1 2
√ e−x dx = 1
−∞ π

formülünde entegralin sağındaki kısım bir dağılımdır. Bu formülü dönüştürerek


Gaussian’a erişebiliriz. Üstteki formülün orta noktası (mean) sıfır, varyansı (vari-
ance), yani σ2√= 1/2 (bunu da ezberlemek lazım ama o kadar dert değil). O
zaman σ = 1/ 2.
İlk amacımız σ = 1’e √ erişmek olsun (çünkü oradan herhangi bir σ’ya atlayabil-
iriz), bunun için x’i 2’e bölmek lazım, tabii aynı√ anda onun etkisini sıfırlamak
için normalize eden sabiti dengelemek amacıyla 2’ye bölmek lazım,

Z +∞
1 x 2
√ e−( 2 ) dx

=
−∞ 2π

17
σ = 1’e erişince oradan herhangi bir σ için, σ değişkenine bölelim, yine hem e
üstüne hem sabite bu eki yapalım,

Z +∞
1 √x 2
= √ e−( 2σ ) dx
−∞ σ 2π

Şimdi herhangi bir ortalama µ için bu değişkeni formüle sokalım, bunun için µ’yu
x’den çıkarmak yeterli

Z +∞
1 x−µ 2
√ e−( 2σ ) dx

=
−∞ σ 2π

e üstündeki kare alma işlemini açarsak,

Z +∞
1 (x−µ)2
= √ e− 2σ2 dx
−∞ σ 2π

Böylece integral içindeki kısım tek boyutlu Gaussian formuna erişmiş oluyor.
Gamma Dağılımı
Y rasgele değişkeninin, verilmiş r > 0 ve λ > 0 üzerinden Gamma yoğunluk
fonksiyonuna sahip olduğu söylenir, eğer bu fonksiyon

λr r−1 λy
fγ = y e
Γ (r)

y>0

Peki Γ sembolü nerede geliyor? Bu bir fonksiyondur; Herhangi bir r > 0 için
Gamma fonksiyonu Γ (r) şu şekilde gösterilir,
Z∞
Γ (r) = yr−1 e−y dy
0

olarak tanımlı ise.


Eğer Y Gamma olarak dağılmış ise, beklenti E(Y) = r/λ, ve Var(Y) = r/λ2 .
İki Değişkenli Dağılımlar
Tanim
Sürekli ortamda (X, Y) rasgele değişkenleri
R∞ Riçin yoğunluk fonksiyonu f(x, y) tanımlanabilir

eğer i) f(x, y) > 0, ∀(x, y) ise, ve ıı)R R −∞ −∞ f(x, y) dx dy = 1 ise ve her küme
A ⊂ R × R için P((X, Y) ∈ A) = A f(x, y) dx dy. Hem ayrıksal hem sürekli
durumda ortak (joint) CDF FX,Y (x, y) = P(X 6 x, Y 6 y) diye gösterilir.

18
Bu tanımda A kümesi olarak tanımlanan kavram uygulamalarda bir olaya (event)
tekabül eder. Mesela
Örnek
(X, Y)’in birim kare üzerinde birörnek (uniform) olsun. O zaman


1 eğer 0 6 x 6 1, 0 6 y 6 1 ise
f(x, y) =
0 diğer durumlarda

P(X < 1/2, Y < 1/2)’yi bul.


Cevap
Burada verilen A = {X < 1/2, Y < 1/2} bir altkümedir ve bir olaydır. Olayları
böyle tanımlamamış mıydık? Örneklem uzayının bir altkümesi olay değil midir?
O zaman f’i verilen altküme üzerinden entegre edersek, sonuca ulaşmış oluruz.
Örnek
Eğer dağılım kare olmayan bir bölge üzerinden tanımlıysa hesaplar biraz daha
zorlaşabilir. (X, Y) yoğunluğu


cx2 y eğer x2 6 y 6 1
f(x, y) =
0 diğer

Niye c bilinmiyor? Belki problemin modellemesi sırasında bu bilinmez olarak


ortaya çıkmıştır. Olabilir. Bu değeri hesaplayabiliriz, çünkü f(x, y) yoğunluk ol-
malı, ve yoğunluk olmanın şartı f(x, y) entegre edilince sonucun 1 olması.
Önce bir ek bilgi üretelim, eğer x2 6 1 ise, o zaman −1 6 x 6 1 demektir. Bu
lazım çünkü entegrale sınır değeri olarak verilecek.

ZZ Z1 Z1
1= f(x, y) dy dx = c x2 y
−1 x2

Z1 Z1 Z1
2 1 x4
=c x y dy dx = x2 ( − ) dx = 1
−1 x2 −1 2 2

Z1
1 − x4
=c x2 ( ) dx = 1
−1 2

Z1
c
= x2 − x6 dx = 1
2 −1

Devam edersek c = 21/4 buluruz.

19
Şimdi, diyelim ki bizden P(X > Y)’yi hesaplamamız isteniyor. Bu hangi A bölgesine
tekabül eder? Elimizdekiler

−1 6 x 6 1, x2 6 y, y 6 1

Şimdi bunlara bir de y 6 x eklememiz lazım. Yani ortadaki eşitsizliğe bir öğe
daha eklenir.

−1 6 x 6 1

x2 6 y 6 x

y61

x2 6 y’yi hayal etmek için x2 = y’yi düşünelim, bu bir parabol olarak çizilebilir,
ve parabolun üstünde kalanlar otomatik olarak x2 6 y olur, bu temel irdelemel-
erden biri.

Aynı şekilde y 6 x için y = x’i düşünelim, ki bu 45 derece açıyla çizilmiş düz


bir çizgi. Çizginin altı y 6 x olur. Bu iki bölgenin kesişimi yukarıdaki resimdeki
gölgeli kısım.
Ek bir bölge şartı 0 6 x 6 1. Bu şart resimde bariz görülüyor, ama cebirsel olarak
bakarsak y > x2 olduğunu biliyoruz, o zaman y > 0 çünkü x2 muhakkak bir
pozitif sayı olmalı. Diğer yandan x > y verilmiş, tüm bunları yanyana koyarsak
x > 0 şartı ortaya çıkar.
Artık P(X > Y) hesabı için hazırız,

Z1 Zx Z1  Zx 
21 2 21 2
P(X > Y) = x y dy dx = x y dy dx
4 0 x2 4 0 x2

Z1
21 x2 − x4 3
= x2 dx =
4 0 2 20

20
“Hafızasız” Dağılım, Üstel (Exponential) Dağılım
Üstel dağılımın hafızasız olduğu söylenir. Bunun ne anlama geldiğini anlatmaya
uğraşalım. Diyelim ki rasgele değişken X bir aletin ömrünü temsil ediyor, yani
bir p(x) fonksiyonuna bir zaman “sorduğumuz” zaman bize döndürülen olasılık,
o aletin x zamanı kadar daha işlemesinin olasılığı. Eğer p(2) = 0.2 ise, aletin 2 yıl
daha yaşamasının olasılığı 0.2.
Bu hafızasızlığı, olasılık matematiği ile nasıl temsil ederiz?

P(X > s + t |X > t) = P(X > s), ∀s, t > 0

Yani öyle bir dağılım var ki elimizde, X > t bilgisi veriliyor, ama (kalan) zamanı
hala P(X > s) olasılığı veriyor. Yani t kadar zaman geçtiği bilgisi hiçbir şeyi
değiştirmiyor. Ne kadar zaman geçmiş olursa olsun, direk s ile gidip aynı olasılık
hesabını yapıyoruz.
Şartsal (conditional) formülünü uygularsak üstteki şöyle olur

P(X > s + t, X > t)


= P(X > s)
P(X > t)

ya da

P(X > s + t, X > t) = P(X > s)P(X > t)

Bu son denklemin tatmin olması için X ne şekilde dağılmış olmalıdır? Üstteki


denklem sadece X dağılım fonksiyonu üstel (exponential) olursa mümkündür,
çünkü sadece o zaman

e−λ(s+t) = e−λs e−λt

gibi bir ilişki kurulabilir.


Örnek
Diyelim ki bir bankadaki bekleme zamanı ortalama 10 dakika ve üstel olarak
dağılmış. Bir müşterinin i) bu bankada 15 dakika beklemesinin ihtimali nedir? ıı)
Bu müşterinin 10 dakika bekledikten sonra toplam olarak 15 dakika (ya da daha
fazla) beklemesinin olasılığı nedir?
Cevap
i) Eğer X müşterinin bankada beklediği zamanı temsil ediyorsa

P(X > 15) = e−15·1/10 = e−3/2 ≈ 0.223

21
ıı) Sorunun bu kısmı müşteri 10 dakika geçirdikten sonra 5 dakika daha geçirmesinin
olasılığını soruyor. Fakat üstel dağılım “hafızasız” olduğu için kalan zamanı alıp
yine direk aynı fonksiyona geçiyoruz,

P(X > 5 >= e−5·1/10 = e−1/2 ≈ 0.60

Kısmi (Marginal) Dağılımlar


Sürekli rasgele değişkenler için kısmı yoğunluk
Z
fX (x) = f(x, y) dx

ve
Z
fY (y) = f(x, y) dy

Üstteki integraller gerçek bir dağılım fonksiyonu f(x, y) verilince alt ve üst limit
te tanımlamak zorundadır. Çünkü kısmı yoğunluk için bir veya daha fazla değişkeni
“integralle dışarı atmak (integrate out)” ettiğimiz söylenir, eğer ayrıksal (discrete)
ortamda olsaydık bu atılan değişkenin tüm değerlerini göze alarak toplama ya-
pan bir formül yazardık. Sürekli ortamda integral kullanıyoruz, ama tüm değerlerin
üzerinden yine bir şekilde geçmemiz gerekiyor. İşte alt ve üst limitler bunu
gerçekleştiriyor. Bu alt ve üst limitler, atılan değişkenin “tüm değerlerine” bak-
ması gerektiği için −∞, +∞ olmalıdır. Eğer problem içinde değişkenin belli değerler
arasında olduğu belirtilmiş ise (mesela alttaki örnekte x > 0) o zaman entegral
limitleri alt ve üst sınırını buna göre değiştirebilir.
Örnek
fX,Y (x, y) = e−(x+y) , olsun ki x, y > 0. O zaman fX (x)
Z∞
−x
fX (x) = e e−y dy = e−x · 1 = e−x
0

Örnek


x + y eğer 0 6 x 6 1, 0 6 y 6 1
f(x, y) =
0 diğer

Z1 Z1 Z1
1
fY (y) = (x + y) dx = x dx + y dx = +y (1)
0 0 0 2

Tanım

22
İki rasgele değişken A, B bağımsızdır eğer tüm A, B değerleri için

P(X ∈ A, Y ∈ B) = P(X ∈ A)P(Y ∈ B)

eşitliği doğru ise. Bu durumda X q Y yazılır.


Teori
X, Y’nin birleşik PDF’i fX,Y olsun. O zaman ve sadece fX,Y (x, y) = fX (x)fY (y) ise
X q Y doğrudur.
Örnek
Diyelim ki X, Y bağımsız, ve ikisinin de aynı yoğunluğu var.


2x eğer 0 6 x 6 1
f(x) =
0 diğerleri

P(X + Y < 1)’i hesaplayın.


Cevap
Bağımsızlığı kullanarak birleşik dağılımı hesaplayabiliriz


4xy eğer 0 6 x 6 1, 0 6 y 6 1
f(x, y) = fX (x)fY (y) =
0 diğerleri

Şimdi bu birleşik yoğunluk üzerinden istediğimiz bölgeyi hesaplarız, bölgeyi


tanımlayan X + Y 6 1 ifadesi.
ZZ
P(X + Y 6 1) = f(x, y) dy dx
x+y61

Entegralin limitinin üstteki hali sembolik, hesap için bu yeterli değil, eğer x +
y 6 1 ise, y 6 1 − x demektir, ve bölge y = 1 − x çizgisinin altı olarak kabul
edilebilir. x, y zaten sıfırdan büyük olmalı, yani sola doğru yatık çizginin altı ve
y, x eksenlerinin üstü kısmını oluşturan bir üçgen,

Z 1 Z 1−x Z Z 1  Z 1−x 
= 4yx dy dx = 4 x y dy dx
0 0 0 0

Numaraya dikkat, hangi değişken üzerinden entegral aldığımıza bakarak, onun


haricindekileri sabit kabul ederek bu “sabitleri” entegral dışına atıyoruz, böylece
işimizi kolaylaştırıyoruz. Hesabı tamamlarsak,

Z1
(1 − x)2 1
4 x dx =
0 2 6

23
Çok Değişkenli (Multivariate) Dağılımlar ve IID Örneklemler (Samples)
X = (X1 , ..., Xn ) olsun, ki (X1 , ..., Xn )’lerin herbiri bir rasgele değişken, o zaman
X’e rasgele vektör (random vector) ismi verilir. f(x1 , ..., xn )’in PDF’i temsil ettiğini
düşünelim. Bu PDF’i baz alarak aynen iki değişkenli (bivariate) örneklerde olduğu
gibi, benzer tekniklerle kısmi olan, koşullu dağılımları, vs. hesaplamak mümkündür.
Çok Değişkenli Normal
Tek değişkenli Normal dağılımın iki parametresi vardı, µ, σ. Çok değişkenli for-
mda µ bir vektör, σ yerine ise Σ matrisi var. Önce rasgele değişkeni tanımlayalım,
 
Z1
Z =  ... 
 
Zk

ki Z1 , ..., Zk ∼ N(0, 1). Z’nin yoğunluğu

Y
1X 2
k k
1
f(z) = f(zi ) = exp − z
i=1
(2π) k/2 2 j=1 j


1 1
= exp − zT z
(2π)k/2 2

Bu durumda Z’nin standart çok değişkenli Normal dağılıma sahip olduğu söylenir,
ve Z ∼ N(0, I) olarak gösterilir. Buradaki 0 değeri içinde k tane sıfır olan bir vektör
olarak, I ise k × k birim (identity) matrisi olarak anlaşılmalıdır.
Daha genel olarak bir vektör X’in çok değişkenli Normal dağılımına sahip olduğunu
söyleriz, ve bunu X ∼ N(µ, Σ) olarak gösteririz, eğer dağılımın yoğunluğu

1 1
f(x; µ, Σ) = exp − (x − µ)T Σ−1 (x − µ)
(2π) det(Σ)1/2
k/2 2

ki k yine veri noktalarının boyutudur, 2 boyutlu bir Gaussian için k = 2. Σ kesin


artı (positive definite) bir matristir. Hatırlayalım, bir matris artı kesindir eğer tüm
sıfır olmayan x vektörleri için xT Σx > 0 ise.
Not: Karekök kavramı tek sayılardan matrislere de aktarılabilir. Bir matris B’nin
A’nin karekökü olduğu söylenir, eğer B · B = A ise.
Devam edersek, eğer Σ artı kesin ise bir Σ1/2 matrisini olduğu gösterilebilir, ki bu
matrise Σ’nin karekökü ismi verilir, ve bu karekökün şu özellikleri vardır, 1) Σ1/2
simetriktir, 2) Σ = Σ1/2 Σ1/2 = I ve Σ−1/2 = (Σ1/2 )−1 .

import numpy.linalg as lin


def gauss(m,v,x):

24
n,d = x.shape
S = lin.inv(v)
x = x-m
y = exp(-0.5*np.diag(dot(x,np.dot(S,x.T))))
return y * (2*pi)**(-d/2.0) / ( np.sqrt(lin.det(v)) + 1e-6)

x = np.array( [[1.,1.]] )
v = np.array( [[2.,0],[0,2.]] )
m = np.array([1.,1.])
print gauss(m, v, x)
[ 0.07957743]

Maksimum olurluk ile elde edilen eldeki n veri noktası için µ, Σ’nin tahmin edi-
cileri µ̂, Σ̂,

1X
n
µ̂ = xk
n k=1

1X
n
Σ̂ = (xk − µ̂)(xk − µ̂)T
n k=1

Ortalamanın maksimum olurluk kestirmesi örneklem ortalaması, aynen tek boyutlu


durumda olduğu gibi. Kovaryans matrisi Σ için tahmin edici (xk − µ̂)(xk − µ̂)T ,
yani n tane matrisin aritmetik ortalaması [4, sf. 112]. Bunlar gayet akla yatkın
sonuçlar.
z-Skorları
Bu değerler bazen kafa karışıklığı yaratabiliyor, çünkü z-değeri, z-”skoru” gibi
kelimeler geçince sanki bu z büyüklükleri bir olasılık değeriymiş gibi bir anlam
çıkabiliyor. Bu doğru değil, z değerleri kümülatif fonksiyonlara
Rz geçilen şeyler.
Yani z = 0.08 “skorunun” olasılığını hesaplamak için φ(z) = 0 p(t) dt ile hesabını
yapmak lazım. Bir diğer karışıklık sebebi mesela z0.05 = −1.64 gibi bir ifade. Bu-
rada z-skoru −1.64 değeridir, z altına yazılan değer bir notasyonel püf noktadır,
ve aslında φ(z) sonucunun ta kendisi, yani φ(−1.64) = 0.05, bu bazı hesaplar için
görmesi kolay olsun diye z0.05 olarak yazılıyor.

from scipy.stats.distributions import norm


print norm.cdf(-1.64)
0.0505025834741

Bu yüzden, P(z1 < Z < z2 ) gibi bir ifadede mesela, Z’nin iki tarafındaki her iki
değer birer z-değeri, olasılık değerleri değil. Olasılık değeri P(·) hesabı sonu-
cunda elde edilecek.
Tabii z-skorları ile ona bağlı olasılık değeri arasında birebir bağlantı var, fakat
z-değerinin “kendisi” olasılık değeri değildir.
Rasgele Değişkenler, Yoğunluklar

25
Şimdi konuların üzerinden bir daha geçelim; rasgele değişken, X, Y gibi büyük
harflerle gösterilen büyüklükler “bir zar atış sonucu içleri doldurulan” değişkenlerdir.
Bu zar atışı her zaman X’in, Y’nin bağlı olduğu dağılıma göre olacaktır. Eğer
X ∼ N(10, 2) ise, bir formülün / hesabın içinde X gördüğümüz zaman çoğunlukla
o noktaya 10’a yakın değerler olacağını biliriz. Tabii ki “kesin” her zaman ne
olacağını bilmeyiz, zaten bir modelde noktasal değer (tipik cebirsel değişkenler)
yerine rasgele değişken kullanmanın sebeplerinden biri budur.
Rasgele değişkenlerin matematiksel formüllerde kullanılması C = X + Y şeklinde
olabilir mesela. O zaman elde edilen yeni değişken de bir rasgele değişken olur.
Bu tür formüller envai şekle girebilir, hatta rasgele değişken içeren formüllerin
türevi bile alınabiliyor, tabii bunun için özel bir Calculus gerekli, İto’nun Calcu-
lus’y bu tür işlerle uğraşıyor.
Elimizde şunlar var; olasılık fonksiyonu bir matematiksel denklem, öne değerler
geçiyoruz, ve bu değerlerin olasılıklarını gayet direk, mekanik bir formülden ce-
vap olarak alıyoruz. Rasgele değişkenler ise bu yoğunluk fonksiyonlarını bir an-
lamda “tersten işletiyor”, o dağılıma “zar attırıyor” (hatta Simulasyon denen bir
derste tam da bu öğretiliyor, yani yoğunluklara yarı-rasgele sayılar üzerinden
zar attırmak!), ve kümülatif olasılık fonksiyonuna geçilen değerler bu sefer dışarı
çıkıyor. Tabii yoğunluğun ne olduğuna göre bazı değerler daha çok, bazıları daha
az çıkıyor. Hesapsal olarak bir rasgele değişkene / dağılıma zar attırmak için özel
kodlamalar, yarı-rasgele sayı üretimi gereklidir, biz kavramsal ve cebirsel olarak
onların neyi temsil ettiğinden bahsediyoruz.
İki kavramdan daha bahsetmek bu noktada faydalı. 1) Nüfus (Population) 2)
Örneklem (Sample). Nüfus, üzerinde istatistiksel analiz yaptığımız kitlenin tamamı.
Eğer insanların boyları hakkında istatistiki analiz yapıyor olsaydık tüm insan-
lar nüfus olurdu. Nüfusun bazen hangi dağılımda olduğu bilinmiyor olabilir,
biliniyor olsa da bazen bu dağılımın parametreleri bilinmiyor olabilir. Örneklem,
nüfus içinden alınan rasgele ölçümlere verilen isimdir, X1 , .., Xn olarak gösterilebiliyor,
bu durumda nüfusun dağılımının “zar attığı” ve her zar atışının rasgele değişkenlerden
birinin içini doldurduğu düşünebilir. Örneklem nüfustan geldiği için dağılımının
aynen nüfus gibi olduğu kabul edilir. Bu bağlantıdan yola çıkılarak birçok istatis-
tiki analiz yapmak mümkündür.
İlginç iki teori daha, hatta bu teoriler İstatistiğin belkemiğini oluşturur, Büyük
Sayılar Kanunu ve Merkezi Limit Teorisi. Diyelim ki X1 , X2 , ..., Xn bir nüfustan
gelen örneklem, ve her veri noktası bağımsız ve dağılımı aynı (nüfus gibi), bu
durumda basit ortalama X̄ = (X1 + X2 + ... + Xn )/n → µ olur, yani basit ortalama
nüfus ortalamasına yaklaşır! Burada ne söylendiğine iyi dikkat, hakkında hiçbir
şey bilmediğimiz nüfusun µ’şu hakkında bir analiz yapabiliyoruz.
Merkezi Limit Teorisi biraz daha √ detay ekler, X̄ = (X1 + X2 + ... + Xn )/n or-
talaması µ standart sapması σ/n olan bir Normal dağılıma yaklaşır. Bu teo-
riler, özellikle ikincisi kullanılarak örneklem (eldeki ufak veri) ve büyük nüfus
arasında bağlantı kurulabilir o tam bilinemeyen gerçek durum hakkında eldeki
örnek verisi ile bir çok analiz yapmak mümkün olur.

26
Kaynaklar
[1] Wikipedia, Confidence interval, http://en.wikipedia.org/wiki/Confidence_
interval
[2] Janert, Data Analysis with Open Source Tools
[3] Bayramli, Çok Değişkenli Calculus Ders 18
[4] Duda, Hart, Pattern Clasification
[5] Bayramli, Büyük Sayılar, Veri, Parametre Tahmin Ediciler (Estimators)

27
Beklenti, Varyans, Kovaryans ve Korelasyon
Beklenti (Expectation)
Bu değer, dağılım f(x)’in tek sayılık bir özetidir. Yani beklenti hesabına bir taraftan
bir dağılım fonksiyonu girer, diğer taraftan tek bir sayı dışarı çıkar.
Tanım
Sürekli dağılım fonksiyonları için E(X)
Z
E(X) = xf(x) dx

ayrıksal dağılımlar için

X
E(X) = xf(x)
x

Hesabın, her x değerini onun olasılığı ile çarpıp topladığına dikkat. Bu tür bir
hesap doğal olarak tüm x’lerin ortalamasını verecektir, ve dolaylı olarak dağılımın
ortalamasını hesaplayacaktır. Ortalama µx olarak ta gösterilebilir.
E(X)’in bir tanım olduğuna dikkat, yani bu ifade tamamen bizim yarattığımız,
ortaya çıkarttığımız bir şey, matematiğin baz kurallarından gelerek türetilen bir
kavram değil. Notasyonel basitlik için üstteki toplam / entegral yerine
Z
= x dF(x)

R
diyeceğiz, bu notasyonel bir kullanım sadece, unutmayalım, reel analizde x dF(x)’in
özel bir anlamı var (hoca tam diferansiyel dF’den bahsediyor) [2, sf. 69].
Beklentinin tanımının kapsamlı / eksiksiz olması için E(X)’in “mevcudiyeti” için
de bir şart tanımlamak gerekir, bu şart şöyle olsun,
Z
|x|dFX (x) < ∞
x

işe beklenti mevcut demektir. Tersi sözkonusu ise beklenti mevcut değildir.
Örnek

X ∼ Unif(−1, 3)

olsun.

1
Z Z Z3
1
E(X) = x dF(x) = xfX (x) dx = x dx = 1
4 −1

Örnek
Cauchy dağılımının fX (x) = {π(1+x2 )}−1 olduğunu söylemiştik. Şimdi beklentiyi
hesaplayalım. Parçalı entegral tekniği lazım, u = x, dv = 1/1 + x2 deriz, ve o
zaman v = tan−1 (x) olur, bkz [6]. Demek ki
Z Z∞
2 x dx
|x| dF(x) =
π 0 1 + x2

2 nereden çıktı? Çünkü |x| kullanıyoruz, o zaman sınır değerlerinde sadece sıfırın
sağına bakıp sonucu ikiyle çarpmak yeterli. Bir sabit olduğu için π ile beraber
dışarı çıkıyor. Şimdi
Z Z
udv = uv − vdu

üzerinden
Z∞
= [x tan −1
(x)]∞
0 − tan−1 (x)dx = ∞
0

Yani üstteki hesap sonsuzluğa gider. O zaman üstteki tanımımıza göre Cauchy
dağılımının beklentisi yoktur.
Y rasgele değişkeninin varyansı (variance)
Ayrısak olarak diyelim ki her biri pj olasılığa sahip n tane değer yi arasından, ve
beklenti E(Y) = µ ise, varyans bir tür “yayınımın ortalamasıdır”. Yani ortalama
olarak ortalamadan (!) ne kadar sapılır sorusunun cevabını verir,

X
n
Var(Y) = (yi − µ)2 pi
i=1

Kare alma işlemi yapıldı çünkü sapmanın eksi mi artı mı olduğu bizi ilgilendirmiyor,
sadece onun mutlak değeri, büyüklüğü bizi ilgilendiriyor. pi ile çarptık çünkü
mesela bazı sapmaların değeri büyük olabilir, ama eğer o sapmaların ortaya çıkma
olasılığı düşük ise bu sapmalar toplama, yani varyansa, daha az etki edecektir.
Değerlerin pi ile çarpılıp sonuçların toplanması beklenti hesabını çağrıştırabilir,
ve evet, matematiksel olarak varyans bir tür beklenti hesabıdır. O sebeple genel
bir şekilde alttaki gibi belirtilir,

Var(Y) = E((Y − E(Y))2 )

2
İfadede toplama ve bölme gibi işlemler olmadığına dikkat; onun yerine kare
ifadeleri üzerinde beklenti ifadesi var. Yani Y’nin beklentisini rasgele değişkenin
kendisinden çıkartıp kareyi alıyoruz, ve bu işlemin Y’den gelen tüm zar atışları
üzerinden beklentisi bize varyansı veriyor. Bir rasgele değişken görünce onun
yerine “dağılımdan üretilen sayı” düşünmek faydalıdır, ki bu gerçek dünya şartlarından
(ve büyük miktarda olunca) veri noktalarını temsil eder.
Varyans formülünü açarsak, ileride işimize yarayacak başka bir formül elde ede-
biliriz,

Var(Y) = E(Y 2 − 2YE(Y) + (E(Y)2 ))

= E(Y 2 ) − 2E(Y)E(Y) + (E(Y)2 )

Var(Y) = E(Y 2 ) − (E(Y)2 )

Tanım
y1 , .., yn örnekleminin varyansı (literatürde S2 olarak geçebiliyor,

1X
S2 = (yi − ȳ)2 (2)
n

Standart sapma veri noktaların ”ortalamadan farkının ortalamasını” verir. Tabii


bazen noktalar ortalamanın altında, bazen üstünde olacaktır, bizi bu negatiflik,
pozitiflik ilgilendirmez, biz sadece farkla alakalıyız. O yüzden her sapmanın
karesini alırız, bunları toplayıp nokta sayısına böleriz.
İlginç bir cebirsel işlem şudur ve bize verinin üzerinden tek bir kez geçerek (one
pass) hem sayısal ortalamayı hem de sayısal varyansı hesaplamamızı sağlar. Eğer
ȳ tanımını üstteki formüle sokarsak,

1X 2 1X 2 2X
= y + m − yi ȳ
n i i n i n i

1 X 2 ȳ2 n 2ȳn
= y + − ȳ
n i i n n

1X 2
= y + ȳ2 − 2ȳ2
n i i

1X 2
= y − ȳ2
n i i

3
ya da

X
n
1
X
n 2
= y2i − yi (5)
i=1
n i=1

Bu arada standard sapma varyansın kareköküdür, ve biz karekök olan versiyon


ile çalışmayı tercih ediyoruz. Niye? Çünkü o zaman veri noktalarının ve yayılma
ölçüsünün birimleri birbiri ile aynı olacak. Eğer veri setimiz bir alışveriş sepetindeki
malzemelerin lira cinsinden değerleri olsaydı, varyans bize sonucu ”kare lira”
olarak verecekti ve bunun pek anlamı olmayacaktı.
Kovaryans ve Korelasyon
Harvard Joe Blitzstein dersinden alınmıştır
Bugün “kovaryans günü”, bu tekniği kullanarak nihayet bir toplamın varyansını
bulabileceğiz, varyans lineer değildir (kıyasla beklenti -expectation- lineerdir).
Bu lineer olmama durumu bizi korkutmayacak tabii, sadece yanlış bir şekilde
lineerlik uygulamak yerine probleme farklı bir şekilde yaklaşmayı öğreneceğiz.
Diğer bir açıdan, hatta bu ana kullanımlardan biri, kovaryans iki rasgele değişkeni
beraber / aynı anda analiz etmemize yarayacak. İki varyans olacak, ve onların
alakasına bakıyor olacağız, bu sebeple bu analize kovaryans deniyor zaten.
Tanım

Cov(X, Y) = E((X − E(X))(Y − E(Y))) (1)

Burada X, Y aynı uzayda tanımlanmış herhangi iki rasgele değişken. Üstteki


diyor ki rasgele değişken X, Y’in kovaryansı X’ten ortalaması çıkartılmış, Y’ten
ortalaması çıkartılmış halinin çarpılması ve tüm bu çarpımların ortalamasının
alınmasıdır.
Tanım böyle. Şimdi bu tanıma biraz bakıp onun hakkında sezgi / anlayış geliştirmeye
uğraşalım. Tanım niye bu şekilde yapılmış, başka bir şekilde değil?
İlk önce eşitliğin sağ tarafındaki bir çarpımdır, yani “bir şey çarpı bir başka şey”.
Bu “şeylerden” biri X ile diğeri Y ile alakalı, onları çarparak ve çarpımın bir
özelliğinden faydalanarak şunu elde ettik; artı çarpı artı yine artı değerdir, eksi
çarpı artı eksidir, eksi çarpı eksi artıdır. Bu şekilde mesela “aynı anda artı” ol-
mak gibi kuvvetli bir bağlantı çarpımın artı olması ile yakalanabilecektir. Aynı
durum eksi, eksi de için geçerli, bu sefer her iki rasgele değişken aynı şekilde
negatiftir. Eksi çarpım sonucu ise sıfırdan az bir değerdir, “kötü korelasyon”
olarak alınabilir ve hakikaten de eksi artı çarpımının işareti olduğu için iki değişkenin
ters yönlerde olduğunu gösterir. Demek ki bu araç / numara hakikaten faydalı.
Unutmayalım, üstteki çarpımlardan birisinin büyüklüğü X’in ortalamasına bağlı
olan bir diğer, Y aynı şekilde. Şimdi X, Y’den bir örneklem (sample) aldığımızı

4
düşünelim. Veri setinin her veri noktası bağımsız özdeşçe dağılmış (i.i.d) du-
rumda. Yani X, Y değişkenlerine “gelen” xi , yi ikilileri her i için diğerlerinden
bağımsız; fakat her ikilinin arasında bir bağlantı var, yani demek ki bu rasgele
değişkenlerin baz aldığı dağılımların bir alakası var, ya da bu iki değişkenin bir
ortak dağılımı (joint distribution) var.
Not: Eğer X, Y bağımsız olsaydı, o zaman

Cov(X, Y) = E((X − E(X)))E(Y − E(Y))

olarak yazılabilirdi, yani iki beklentinin ayrı ayrı çarpılabildiği durum... Ama biz
bu derste bağımsızlığın olmadığı durumla ilgileniyoruz..
Korelasyon kelimesinden bahsedelim hemen, bu kelime günlük konuşmada çok
kullanılıyor, ama bu ders bağlamında korelasyon kelimesinin matematiksel bir
anlamı olacak, onu birazdan, kovaryans üzerinden tanımlayacağız.
Bazı ilginç noktalar:
Özellik 1
varyansı nasıl tanımlamıştık?

Var(X) = E((X − E(X))2 )

Bu denklem aslında

Cov(X, Y) = E((X − E(X))(Y − E(Y)))

denkleminde Y yerine X kullandığımızda elde ettiğimiz şeydir, yani

Cov(X, X) = E((X − E(X))(X − E(X)))

Cov(X, X) = E((X − E(X))2 )

= Var(X)

Yani varyans, bir değişkenin “kendisi ile kovaryansıdır”. İlginç değil mi?
Özellik 2

Cov(X, Y) = Cov(Y, X)

İspatı kolay herhalde, (1) formülünü uygulamak yeterli.

5
Teori

Cov(X, Y) = E((X − E(X))(Y − E(Y))) = E(XY) − E(X)E(Y)

İspat
Bu ispat çok kolay, eşitliğin sol tarafındaki çarpımı parantezler üzerinden açarsak,
ve beklenti lineer bir operatör olduğu için toplamın terimleri üzerinde ayrı ayrı
uygulanabilir,

E(XY) − E(X)E(Y) − E(X)E(Y) + E(X)E(Y)

= E(XY) − E(X)E(Y)

Çarpımı uygularken mesela E(−X · E(Y)) gibi bir durum ortaya çıktı, burada
E(Y)’nin bir sabit olduğunu unutmayalım, çünkü beklenti rasgele değişkene uygu-
lanınca tek bir sayı ortaya çıkartır, ve vu E(Y) üzerinde bir beklenti daha uygu-
lanınca bu “içerideki” beklenti sabitmiş gibi dışarı çıkartılabilir, yani −E(X)E(Y).
Devam edelim, E(XY)−E(X)E(Y) ifadesini gösterdik, çünkü çoğu zaman bu ifade
hesap açısından (1)’den daha uygundur. Ama (1) ifadesi anlatım / sezgisel kavrayış
açısından daha uygun, çünkü bu ifade X’in ve Y’nin kendi ortalamalarına izafi
olarak belirtilmiştir, ve akılda canlandırılması daha rahat olabilir. Fakat matem-
atiksel olarak bu iki ifade de aynıdır.
İki özellik bulduk bile. Bir özellik daha,
Özellik 3

Cov(X, c) = 0

Bu nereden geldi? (1)’e bakalım, Y yerine c koymuş olduk, yani bir sabit. Bu
durumda (1)’in (Y − E(Y)) kısmı c − E(c) = c − c = 0 olur [aslında bayağı absürt
bir durum], ve bu durumda (1) tamamen sıfıra dönüşür, sonuç sıfır.
Özellik 4
Cov(cX, Y) = c · Cov(X, Y)
İspat için alttaki formülde

Cov(X, Y) = E(XY) − E(X)E(Y)

X yerine cX koymak yeterli, c her iki terimde de dışarı çıkacaktır, ve grubun


dışına alıncan bu özelliği elde ederiz.
Özellik 5

6
Cov(X, Y + Z) = Cov(X, Y) + Cov(X, Z)

İspat için bir üstteki özellikte yaptığımızın benzerini yaparız.


En son iki özellik oldukça faydalıdır bu arada, onlara ikili-lineerlik (bilinearity)
ismi veriliyor. İsim biraz renkli / sükseli bir isim, söylemek istediği şu aslında,
bu son iki özellikte sanki bir kordinatı sabit tutup diğeri ile işlem yapmış gibi
oluyoruz, yani bir kordinat sabit olunca diğeri “lineermiş gibi” oluyor; Mesela
c’nin dışarı çıktığı durumda olduğu gibi, bu özellikte Y’ye hiçbir şey olmadı, o
değişmeden kaldı. Aynı şekilde 5. özellikte X hiç değişmeden eşitliğin sağına
aktarıldı sanki, sadece “Z durumu için” yeni bir terim ekledik.
4. ve 5. özellik çok önemlidir, bunları bilirsek bir ton hesabı yapmadan hızlıca
türeterek hesaplar kolaylaştırılabilir.
Özellik 6

Cov(X + Y, Z + W) = Cov(X, Z) + Cov(X, W) + Cov(Y, Z) + Cov(Y, W)

Şimdi 5. özelliği hatırlayalım, orada gösterilen sanki bir nevi basit cebirdeki
dağıtımsal (distributive) kuralın uygulanması gibiydi sanki, yani (a + b)(c + d)’i
açtığımız gibi, 5. özellik te sanki kovaryansı çarpıp topluyormuş gibi “açıyordu”.
En temelde gerçekten olan bu değil ama nihai sonuç benzer gözüktüğü için akılda
tutması kolay bir metot elde etmiş oluyoruz. Her neyse, 6. özellik için aslında 5.
özelliği tekrar tekrar uygulamak yeterli. Bu arada 5. özellik Cov(X, Y + Z) için
ama Cov(Y + Z, X) yine aynı sonucu veriyor.
Bu arada 6. özellik çok çetrefil toplamlar üzerinde de uygulanabilir, mesela

X
m X
n 
Cov ai Xi , bi Yi
i=1 j=1

Bu son derece karmaşık gözüküyor, fakat çözümü için aynen 6. özellikte olduğu
gibi 5. özelliği yine tekrar tekrar uygulamak yeterli (4. özellik ile de sabiti dışarı
çıkarırız, vs).
Çoğu zaman üstteki gibi pür kovaryans içeren bir açılımla çalışmak, içinde bek-
lentiler olan formüllerle uğraşmaktan daha kolaydır.
Şimdi toplamlara dönelim; kovaryanslara girmemizin bir sebebi toplamlarla iş
yapabilmemizi sağlaması. Mesela, bir toplamın varyansını nasıl hesaplarız?
Özellik 7

Var(X1 + X2 )

Şimdilik iki değişken, ama onu genelleştirip daha fazla değişkeni kullanabiliriz.

7
Çözelim. 1. özellik der ki varyans değişkenin kendisi ile kovaryansıdır, yani
Var(X) = Cov(X, X). O zaman Var(X1 + X2 ) = Cov(X1 + X2 , X1 + X2 ). Böylece
içinde toplamlar içeren bir kovaryans elde ettik ama bunu çözmeyi biliyoruz
artık. “Dağıtımsal” işlemleri yaparken Cov(X1 , X1 ) gibi ifadeler çıkacak, bunlar
hemen varyansa dönüşecek. Diğer taraftan Cov(X1 , X2 ) iki kere gelecek, yanı

Var(X1 + X2 ) = Var(X1 ) + Var(X2 ) + 2Cov(X1 , X2 )

Bu alanda bilinen tekerleme gibi bir başka deyiş, “eğer kovaryans sıfırsa toplamın
varyansı varyansların toplamıdır”. Hakikaten kovaryans sıfır olunca üstteki den-
klemden düşecektir, geriye sadece varyansların toplamı kalacaktır. Kovaryans ne
zaman sıfırdır? Eğer X1 , X2 birbirinden bağımsız ise. Tabii bu bağımsızlık her za-
man ortaya çıkmaz.
İkiden fazla değişken olunca? Yine tüm varyansların ayrı ayrı toplamı, ve ko-
varyanslar da sonda toplanacak,

X
Var(X1 + .. + Xn ) = Var(X1 ) + .. + Var(Xn ) + 2 Cov(Xi , Xj )
i<j

Sondaki toplamın indisinde bir numara yaptık, sadece 1 ile 2, 2 ile 3, vs. eşlemek
için, ve mesela 3 ile 1’i tekrar eşlememek için. Tekrar dedik çünkü Cov(X1 , X3 ) =
Cov(X3 , X1 ). Eğer indisleme numarası kullanmasaydık, 2 ile çarpımı çıkartırdık
(ona artık gerek olmazdı),

X
.. + Cov(Xi , Xj )
i6=j

Şimdi, korelasyon konusuna gelmeden önce, bağımsızlık kavramını iyice anladığımızdan


emin olalım.
Teori
Eğer X, Y bağımsız ise bu değişkenler bağımsızdır, yani Cov(X, Y) = 0.
DİKKAT! Bu mantık çizgisinin tersi her zaman doğru olmayabilir, yani bağımsızlık
kesinlikle Cov(X, Y) = 0 demektir, ama her Cov(X, Y) = 0 olduğu zaman ortada
bir bağımsızlık var diyemeyiz. Bunu bir örnekle görelim.

Z ∼ N(0, 1), X = Z, Y = Z2

Şimdi X, Y kovaryansının hesabı yapalım

Cov(X, Y) = E(XY) − E(X)E(Y) = E(Z3 ) − E(Z)E(Z2 )

8
En sondaki terim sıfırdır, çünkü hem E(Z) ve E(Z3 ) sıfırdır [hoca burada standart
normalin tek sayılı (odd) moment’leri hep sıfırdır dedi]. O zaman şu sonucu
çıkartıyoruz, X, Y arasında korelasyon yok.
Ama bağımlılık var mı? Var. Çünkü hem X hem Y Z’nin birer değişkeni, yani
bu durumda X’i bilmek bize Y’yi tamamen bilmemizi sağlıyor (sadece ek olarak
bir kare alıyoruz). Tabii bağımlılık illa herşeyin bilinmesi demek değildir, bi-
raz bağımlılık ta olabilir, ama biraz bağımlılık bile varsa, bağımsızlık var diye-
meyiz. Aynı şey ters yön için de geçerli, Y bilinince X’in “büyüklüğünü” bilebil-
iriz, karekök işlemi olduğu için -/+ işareti bilemeyiz ama skalar bir büyüklüğü
elde edebiliriz. Yani ters yönde de bağımsızlık yoktur.
Faydalı bir Eşitlik [1, sf 120]

Var(aX + b) = a2 Var(X)

Ya da b = 0 olduğu durumda (hatta ne olursa olsun)

Var(aX) = a2 Var(X)

İspat
µ = E(X) olsun ve E(aX+b) = aµ+b olduğunu hatırlayalım. Varyans tanımından
hareketle,

Var(aX + b) = E (aX + b − E[aX + b])2


 

= E (aX + b − aµ + b)2
 

= E (aX − aµ)2
 

= E a2 (X − µ)2
 

= a2 E (X − µ)
 

= a2 Var(X)

Korelasyon
Tanım

9
Cov(X, Y)
Corr(X, Y) = (2)
SD(X)SD(Y)

Bu arada hatırlarsak üstte SD ile gösterilen standart sapma, varyansın karesidir.


Bu tanım genelde kullanılan tanımdır. Fakat ben daha farklı bir tanımı tercih
ediyorum. Standardize etmeyi hatırlıyoruz değil mi? Bir rasgele değişkenden
ortalamasını çıkartıp standart sapmaya bölünce standardize ediyorduk. Bunu
kullanarak aslında korelasyonu alttaki gibi tanımlayabiliriz,
 
X − E(X) Y − E(Y)
Corr(X, Y) = Cov , (3)
SD(X) SD(Y)

Yani korelasyonun anlamı aslında şudur: X, Y değişkenlerini standardize et, on-


dan sonra kovaryanslarını al (üstteki ifadeye Pearson korelasyonu ismi de ver-
ilir).
Niye standardize edilmiş kovaryans içeren ifadeyi tercih ediyoruz? Çünkü, diye-
lim ki X, Y değişkenleri bir uzaklık ölçüsünü temsil ediyor, ve birimleri mesela
nanometre. Fakat bir başkası gelip aynı ölçümü, atıyorum, ışık yılı olarak kul-
lanmaya başlarsa problem çıkabilir. Yani eğer birim yoksa ve ben “X, Y korelasy-
onum 42” dersem, bunun ne olduğunu anlamak zordur. 42 önümüzdeki veriye
göre küçük müdür, büyük müdür? Bilemeyiz. Yani 42 sayısı tabii ki evrendeki
tüm soruların cevabıdır [hoca bir filme atfen espri yapıyor, orada 42 sayısının özel
bir anlamı vardı], ama önümüzdeki problem için, nedir?
Fakat üstteki formül ölçü birimsiz (dimensionless) bir sonuç verir, yani bir ölçü
biriminden bahsetmeden birine rahatça aktarabileceğimiz bir bilgidir. Niye bir-
imsiz oldu? Çünkü X’in birimi cm olsa, X − E(X) yine cm, SD(X) varyansın
karekökü olduğu için cm2 ’nin karekökü yine cm, cm bölü cm birim ortadan
kalkar.
Bu arada (3) niye (2) ile aynıdır? Eğer bir rasgele değişkenden bir sabiti çıkartırsam
onun başka bir değişken ile kovaryansını değiştirmiş olmam. Ki standardize
etme işlemi bunu yapar. O zaman niye bu çıkartma işlemini yaptım? Çünkü
standardize etme işlemini özellikle kullanmak istedim - standardizasyon bilinen
ve rahatça kullanılabilen bir işlem. Standart sapmayı bölmeye gelirsek, şimdiye
kadar gördüğümüz özelliklerden biri, bölümü dışarı alabileceğimizi gösteriyor,
böyle olunca (2) ifadesini aynen elde ediyorum.
Önemli bir nokta daha: korelasyon her zaman −1 ve +1 arasındadır.
Teori

−1 6 Corr(X, Y) 6 1

Yani ölçü biriminden bağımsız olması avantajına ek olarak hep aynı skalada olan
bir değerin rapor edilmesi de faydalıdır. Eğer korelasyon 0.99 bulursam bunun

10
hemen yüksek bir korelasyon olduğunu bilirim.
Bu arada, Çauchy-Schwarz eşitsizliğinden bahsedeyim -ki bu eşitsizlik tanımı
tüm matematikteki en önemli eşitsizliklerden biridir- eğer korelasyon formülünü
lineer cebirsel şekilde ifade etseydim direk Cauchy-Schwarz eşitsizliğini elde ed-
erdim.
İspat
Önce “WLOG çerçevesinde” X, Y’nin önceden standardize edilmiş olduğunu kabul
edelim. [WLOG ne demek? Matematikçiler ispatlar sırasında bunu bazen kul-
lanırlar, genelleme kuvvetinde bir kayıp olmadan (without loss of generality)
takip eden şeyi kullanabiliriz demektir, yani “bir başka şey kullanıyorum, ama
teori bu çerçevede de hala geçerli” demek isterler].
Önceden standardize edildiğini kabul etmek niye fark yaratmıyor? Çünkü bunu
gördük, standart olmayan değişkenleri standardize edince yine aynı sonucu elde
ediyorum, yani bir şey farketmiyor.
Var(X + Y)’i hesaplayalım.

Var(X + Y) = Var(X) + Var(Y) + 2Cov(X, Y) (4)

Şimdi sembol olarak ρ = Corr(X, Y) kullanalım,


Standardize ettiğimizi kabul etmiştik, o zaman Var(X) = 1, Var(Y) = 1. Ayrıca
(3)’te gördüğümüz üzere, standardize durumda kovaryans korelasyona eşittir, o
zaman Cov(X, Y) = ρ, yani 2Cov(X, Y) = 2ρ. Tüm ifade,

Var(X + Y) = 1 + 1 + 2ρ = 2 + 2ρ

Peki farkların varyansı, Var(X − Y) nedir? Bir numara kullanalım, Var(X − Y)’i
Var(X + (−Y)) olarak görelim,

Var(X − Y) = Var(X) + Var(Y) − 2Cov(X, Y) = 2 − 2ρ

Aslında bu son ifade ispatı tamamlamış oldu, çünkü varyans negatif olmayam
bir şeydir, yani

0 6 Var(X + Y) = 2 + 2ρ

0 6 Var(X − Y) = 2 − 2ρ

Bu iki eşitsizliği kullanarak

11
−2 6 2ρ

−2 6 −2ρ

ve

−1 6 ρ

ρ61

Multinom Dağılımın Kovaryansı


Kovaryansı multinom dağılımı bağlamında ele alalım, bildiğimiz gibi multinom
dağılımı bir vektördür [ve binom dağılımının daha yüksek boyuttaki halidir, bi-
nom dağılımı bildiğimiz gibi n deney içinde kaç tane başarı sayısı olduğunu
verir], ve vektörün her hücresinde “vs. kategorisinde kaç tane vs var” gibi bir
değer taşınır, ki bu her hücre bağlamında “o kategori için zar atılsa kaç tane başarı
elde edilir” gibi okunabilir.
Biz ise bu hücrelerden iki tanesini alıp aralarındaki kovaryasyona bakmak istiy-
oruz. Gayet doğal bir istek.
Notasyon
Elimizde k tane obje var,

(X1 , .., Xk ) ∼ Mult(n, ~p)

Dikkat, p bir vektör, tabii ki, çünkü binom durumunda p tek sayı idi, şimdi “pek
çok p”ye ihtiyaç var.
Her i, j için Cov(Xi , Xj )’yi hesapla.
Eger i = j ise Cov(Xi , Xi ) = Var(Xi ) = npi (1 − pi ).
ki son ifade binom dağılımının varyansıdır. Bu basit durum tabii ki, ilginç olan
i 6= j olmadığı zaman.
Tek örnek seçelim, mesela Cov(X1 , X2 ), buradan gelen sonuç gayet kolayca genelleştirilebilir.
Hesaba başlamadan önce kabaca bir akıl yürütelim; Cov(X1 , X2 ) için artı mı eksi
mi bir değer elde ederdik acaba? Multinom dağılımı hatırlayalım, belli sayıda
“şey” yine belli sayıda kategori arasında “kapışılıyor”, yani bu kategoriler arasında
bir yarış var. O zaman herhangi iki kategorinin kovaryansının negatif olmasını
bekleriz.
Çözüm için (4) formülünü kullanacağım, ama seçici bir şekilde,

12
Var(X + Y) = Var(X) + Var(Y) + 2Cov(X, Y)

içinde Var(X+Y), Var(X), Var(Y)’i biliyorsam, geriye bilinmeyen Cov(X, Y) kalır.


Kısaltma amacıyla c = Cov(X, Y) diyelim,

Var(X1 + X2 ) = np1 (1 − p1 ) + np2 (1 − p2 ) + 2c

Şimdi X1 + X2 ’nin ne olduğunu düşünelim, bu yeni rasgele değişken “ya kate-


gori 1 ya da 2” sonucunu taşıyan bir değişkendir, ki bu da yeni bir “birleşik”
binom değişkenidir. Bu değişkenin p’sı toplamı olduğu iki kategorinin p’sinin
toplamıdır, yani p1 + p2 . O zaman bu yeni değişkenin varyansı,

Var(X1 + X2 ) = n(p1 + p2 )(1 − (p1 + p2 ))

Eh artık denklemdeki her şeyi biliyoruz, sadece c’yi bilmiyoruz, ona göre herşeyi
düzenleyelim,

n(p1 + p2 )(1 − (p1 + p2 )) = np1 (1 − p1 ) + np2 (1 − p2 ) + 2c

Burada biraz haldir huldür işlem lazım [bu kısmı okuyucu isterse yapabilir],
sonuç

Cov(X1 , X2 ) = −np1 p2

Genel olarak

Cov(Xi , Xj ) = −npi pj , ∀i 6= j

Dikkat edelim, bu sonuç her zaman negatiftir (çünkü p değerleri olasılık değerleridirler,
yani pozitif olmak zorundadırlar)
Örnek
Binom değişkenin varyansını hesaplayalım şimdi. Bunu daha önce yapmıştık
ama göstergeç (indicator) rasgele değişkenleri kullanarak yapmıştık bunu, şimdi
elimizde yeni bir araç var, onu kullanalım. Varacağımız sonuç Var(X) = npq
olacak. Tanımlar,

X ∼ Bin(n, p), X = X1 + .. + Xn

ki Xi değişkenleri i.i.d. Bernoulli.


Aslında her Xi değişkeni bir göstergeç değişkeni gibi görülebilir. Diyelim ki bir
A olayı için göstergeç değişken IA olsun. Bu durumda

13
I2A = IA

I3A = IA

Değil mi? Göstergeç sadece 1/0 olabiliyorsa onun karesi, küpü aynı şekilde olur.
Bunu vurguluyorum, çünkü bazen atlanıyor.
Peki IA IB ? Ki A, B ayrı ayrı olaylar. Gayet basit,

IA IB = IA∩B

Bu normal değil mi? Eşitliğin solundaki çarpım sadece her iki değişken de 1 işe 1
sonucunu verir, bu ise sadece A, B olayları aynı anda olduğu zaman mümkündür,
ki bu aynı anda olmak küme kesişmesinin tanımıdır.
Bernoullli durumuna dönelim, her Bernoulli için

Var(Xi ) = EX2j − E(Xj )2

X2j = Xj ’dir, bunu biraz önce gördük, ve Binom değişkenleri göstergeç gibi görüyoruz,
o zaman EX2j = E(Xj ) = p.

Var(Xi ) = p − p2 = p(1 − p) = pq

Tüm binom dağılımın varyansı,

Var(X) = npq

Bu kadar basit. Çünkü Cov(Xi , Xj ) = 0, ∀i 6= j, yani her bernoulli deneyi bir-


birinden bağımsız, o sebeple binom varyansı için tüm bernoulli varyanslarını
toplamak yeterli, eğer varyansı pq olan n tane bernoulli varsa, binom varyansı
npq.
Örnek
Daha zor bir örneği görelim.

X ∼ HGeom(w, b, n)

Bu bir hipergeometrik dağılım. Parametreleri şöyle yorumlayabiliriz, bir kutu


içinde w tane beyaz top var, b tane siyah top var, ve biz bu kutudan n büyüklüğünde
bir örneklem alıyoruz, ve ilgilendiğimiz örneklemdeki beyaz topların dağılımı.
[dersin gerisi atlandi]

14
Matrisler İle Kovaryans Hesabı
Eğer verinin kolonları arasındaki ilişkiyi görmek istersek, en hızlı yöntem ma-
tristeki her kolonun (değişkenin) ortalamasını kendisinden çıkartmak, yani onu
“sıfırda ortalamak” ve bu matrisin devriğini alarak kendisi ile çarpmaktır. Bu
işlem her kolonu kendisi ve diğer kolonlar ile noktasal çarpımdan geçirecektir
ve çarpım, toplama sonucunu nihai matrise yazacaktır. Çarpımların bildiğimiz
özelliğine göre, artı değer artı değerle çarpılınca artı, eksi ile eksi artı, eksi ile
artı eksi verir, ve bu bilgi bize ilinti bulma hakkında güzel bir ipucu sunar. Poz-
itif sonucun pozitif korelasyon, negatif ise tersi şekilde ilinti olduğu sonucuna
böylece kolayca erişebiliriz.
Tanım

1
S= (X − E(X))T (X − E(X)))
n

Pandas ile çov çağrısı bu hesabı hızlı bir şekilde yapar,

print df.cov()

Sepal Length Sepal Width Petal Length Petal Width


Sepal Length 0.685694 -0.039268 1.273682 0.516904
Sepal Width -0.039268 0.188004 -0.321713 -0.117981
Petal Length 1.273682 -0.321713 3.113179 1.296387
Petal Width 0.516904 -0.117981 1.296387 0.582414

Eger kendimiz bu hesabi yapmak istersek,

means = df.mean()
n = df.shape[0]
df2 = df.apply(lambda x: x - means, axis=1)
print np.dot(df2.T,df2) / n

[[ 0.68112222 -0.03900667 1.26519111 0.51345778]


[-0.03900667 0.18675067 -0.319568 -0.11719467]
[ 1.26519111 -0.319568 3.09242489 1.28774489]
[ 0.51345778 -0.11719467 1.28774489 0.57853156]]

Verisel kovaryansın sayısal gösterdiğini grafiklemek istersek, yani iki veya daha
fazla boyutun arasındaki ilişkileri grafiklemek için yöntemlerden birisi verideki
mümkün her ikili ilişkiyi grafiksel olarak göstermektir. Pandas scatter_matrix
bunu yapabilir. Iris veri seti üzerinde görelim, her boyut hem y-ekseni hem x-
ekseninde verilmiş, ilişkiyi görmek için eksende o boyutu bulup kesişme nokta-
larındaki grafiğe bakmak lazım.

import pandas as pd
df = pd.read_csv('iris.csv')
df = df.ix[:,0:4]
pd.scatter_matrix(df)
plt.savefig('stat_summary_01.png')

15
İlişki olduğu zaman o ilişkiye tekabül eden grafikte “düz çizgiye benzer” bir
görüntü olur, demek ki değişkenlerden biri artınca öteki de artıyor (eğer çizgi
soldan sage yukarı doğru gidiyorsa), azalınca öteki de azalıyor demektir (eğer
çizgi aşağı doğru iniyorsa). Eğer ilinti yok ise bol gürültülü, ya da yuvarlak
küreye benzer bir şekil çıkar. Üstteki grafiğe göre yaprak genişliği (petal width)
ile yaprak boyu (petal length) arasında bir ilişki var.
Tanım
X, Y rasgele değişkenlerin arasındaki kovaryans,

Cov(X, Y) = E(X − E(X))(Y − E(Y))

Yani hem X hem Y’nin beklentilerinden ne kadar saptıklarını her veri ikilisi için,
çıkartarak tespit ediyoruz, daha sonra bu farkları birbiriyle çarpıyoruz, ve bek-
lentisini alıyoruz (yani tüm olasılık üzerinden ne olacağını hesaplıyoruz).
Ayrı ayrı X, Y değişkenleri yerine çok boyutlu X kullanırsak, ki boyutları m, n ol-
sun yani m veri noktası ve n boyut (özellik, öğe) var, tanımı şöyle ifade edebiliriz,

Σ = Cov(X) = E((X − E(X))T (X − E(X)))

Phi Korelasyon Katsayısı


Phi katsayısı iki tane ikisel değişkenin birbiriyle ne kadar alakalı, bağlantılı olduğunu
hesaplayan bir ölçüttür. Mesela x, y değişkenleri için elde olan (x1 , y1 ), (x2 , y2 ), ..
verilerini kullanarak hem x = 1 hem y = 1 olan verileri sayıp toplamı n11 ’e
yazarız, y = 1, x = 0 icin n10 , aynı şekilde diğer kombinasyonlara bakarak alttaki
tabloyu oluştururuz [5],

16
Phi korelasyon katsayısı

n11 n − n1• n•1


φ= √ (6)
n0• n1• n•0 n•1

ile hesaplanır. Bu ifadeyi türetmek için iki rasgele değişken arasındaki korelasy-
onu hesaplayan formül ile başlıyoruz,

E(x − E(X))(y − E(Y))


Corr(X, Y) = p
Var(X) · Var(Y)

E(XY) − E(X)E(Y)
=p
Var(X) · Var(Y)

X, Y değişkenlerinin Bernoulli dağılımına sahip olduğunu düşünelim, çünkü 0/1


değerlerine sahip olabilen ikisel değişkenler bunlar, o zaman

n1• n0• n1• n•1 n•0 n•1 n11


E[X] = , Var[X] = , E[Y] = , Var[Y] = , E[XY] =
n n2 n n2 n2

olacaktır. E(XY) nasıl hesaplandı? Ayrıksal dağılımlar için beklenti formülünün


iki değişken için şöyle ifade edildiğini biliyoruz,

XX
E[XY] = xi · yj · P{X = xi , Y = yj }
i j

Bu ifadeyi tabloya uyarlarsak, ve tablodaki hesapların üstteki ifadeler için tah-


min ediciler olduğunu biliyoruz, iki üstteki sonucu elde edebileceğimizi görürüz,
çünkü tek geçerli toplam xi yi her iki değişken de aynı anda 1 olduğunda geçerlidir.
Bu değerleri yerine geçirince (6) elde edilir.
Phi katsayısının bir diğer ismi Matthews korelasyon katsayısı. Bu hesabı mesela
bir 0/1 tahmini üreten sınıflayıcının başarısını ölçmek için kullanabiliriz, gerçek,
test 0/1 verileri bir dizinde, üretilen tahminler bir diğerinde olur, ve Phi katsayısı
ile aradaki uyumu raporlarız. Sonuç -1,+1 arasında olacağı için sonuca bakarak
irdeleme yapmak kolaydır, bu bir başarı raporu olarak algılanabilir. Ayrıca Phi
hesabının, AUC hesabı gibi, dengesiz veri setleri üzerinde (mesela 0’a kıyasla

17
çok daha fazla 1 olan veriler, ya da tam tersi) üzerinde bile hala optimal olarak
çalıştığı [4] bulunmuştur.
Bazı örnekler,

from sklearn.metrics import matthews_corrcoef


y_true = [+1, +1, +1, -1]
y_pred = [+1, -1, +1, +1]
print (matthews_corrcoef(y_true, y_pred) )

-0.333333333333

Ya da

a = [[0, 0],[0, 0],[0, 0],[0, 0],[0, 0],[1, 0],\


[1, 0],[1, 0],[0, 1],[0, 1],[1, 1],[1, 1],\
[1, 1],[1, 1],[1, 1],[1, 1],[1, 1],[1, 1],\
[1, 1], [1, 1],[1, 1],[1, 1],[1, 1],[1, 1],\
[1, 1],[1, 1],[1, 1]]
a = np.array(a)
print (matthews_corrcoef(a[:,0], a[:,1]))

0.541553390893

Medyan ve Yüzdelikler (Percentile)


Üstteki hesapların çoğu sayıları toplayıp, bölmek üzerinden yapıldı. Medyan ve
diğer yüzdeliklerin hesabı (ki medyan 50. yüzdeliğe tekabül eder) için eldeki tüm
değerleri ”sıraya dizmemiz” ve sonra 50. yüzdelik için ortadakine bakmamız
gerekiyor. Mesela eğer ilk 5. yüzdeliği arıyorsak ve elimizde 80 tane değer var
ise, baştan 4. sayıya / vektör hücresine / öğeye bakmamız gerekiyor. Eğer 100
eleman var ise, 5. sayıya bakmamız gerekiyor, vs.
Bu sıraya dizme işlemi kritik. Kıyasla ortalama hesabı hangi sırada olursa olsun,
sayıları birbirine topluyor ve sonra bölüyor. Zaten ortalama ve sapmanın istatis-
tikte daha çok kullanılmasının tarihi sebebi de aslında bu; bilgisayar öncesi çağda
sayıları sıralamak (sorting) zor bir işti. Bu sebeple hangi sırada olursa olsun,
toplayıp, bölerek hesaplanabilecek özetler daha makbuldü. Fakat artık sıralama
işlemi kolay, ve veri setleri her zaman tek tepeli, simetrik olmayabiliyor. Örnek
veri seti olarak ünlü dellstore2 tabanındaki satış miktarları kullanırsak,

print np.mean(data)

213.948899167

print np.median(data)

214.06

print np.std(data)

125.118481954

18
print np.mean(data)+2*np.std(data)
464.185863074

print np.percentile(data, 95)


410.4115

Görüldüğü gibi üç nokta hesabı için ortalamadan iki sapma ötesini kullanırsak,
464.18, fakat 95. yüzdeliği kullanırsak 410.41 elde ediyoruz. Niye? Sebep ortala-
manın kendisi hesaplanırken çok üç değerlerin toplama dahil edilmiş olması ve
bu durum, ortalamanın kendisini daha büyük seviyeye doğru itiyor. Yüzdelik
hesabı ise sadece sayıları sıralayıp belli bazı elemanları otomatik olarak üç nokta
olarak addediyor.
Grupların Ortalamalarını ve Varyanslarını Birleştirmek
Bazen elimizde bir verinin farklı parçaları üzerinde hesaplanmış ortalama, varyans
sonucu olabilir, ve bu hesapları bu parçaların toplamı için birleştirmemiz gereke-
bilir. Belki paralel süreçler var, verinin parçaları üzerinde eşzamanlı çalışıyorlar,
bir ortalama, varyans hesaplıyorlar, ve nihai sonucun bu alt sonuçlar üzerinden
raporlanması lazım [3].
İşlenen veri setinin tamamı, birleşmiş (pooled) veri D = {x1 , x2 , .., xN } olsun, ki
N veri noktası sayısı. Bu verinin ortalaması a = (x1 + x2 + .. + xN )/N, varyansı √
v = ((x1 − a)2 + (x2 − a)2 + ... + (xN − a)2 )/N. Standart sapma tabii ki σN = v.
Veriyi ayrı işledik diyelim, veri şu şekilde ayrıldı D1 = {x1 , x2 , .., xj }, D2 = {xj+1 , xj+2 , .., xj+k },
D3 = {xj+k+1 , xj+k+2 , .., xj+k+m }. Yani her veri grubunun büyüklüğü sırasıyla
j, k, m ve toplam veri noktaları n = j + k + m.
P
DP ’nin ortalaması aP = n1 n i=1 xi . Her grup D1 , D2 , D3 ’un ortalaması a1 , a2 , a3
benzer şekilde bulunabilir. Bu durumda “ortalamaların ortalaması”, yani nihai
ortalama aP şöyle bulunabilir,

aP = (ja1 + ka2 + ma3 )/n

Varyansa ulaşmak için kareler toplamı, grup varyanslarına bakalım şimdi, DP


için kareler toplamı

X
n
SP = x2i (7)
i=1

Gruplar D1 , D2 , D3 için toplamlar S1 , S2 , S3 benzer şekilde tanımlanıyor, ve nihai


toplam bu gruplar üzerinden SP = S1 + S2 + S3 olarak tanımlanabiliyor.
Tum veri DP icin varyans

1X
n
vP = (xi − aP )2
n i=1

19
Bu ifadeyi acarsak

1X 2
n
= (xi − 2xi ap + a2p )
n i=1

1X 2 1X 1X 2
n n n
= xi − 2xi ap + a
n i=1 n i=1 n i=1 p

1
Pn 1
Pn
n i=1 xi = ap olduğunu hatırlarsak, ve n i=1 ap tabii ki yine ap o zaman

1X 2
n
= Sp /n − 2a2p + a
n i=1 p

1
Pn
n i=1 a2p benzer sekilde tekrar ap ,

= Sp /n − 2a2p + a2p

vP = Sp /n − a2p (8)

Bu durumda parçaların ayrı varyans formülleri de üstteki gibi yazılabilir,

v1 = S1 /j − a21 , v2 = S2 /k − a22 , v3 = S3 /m − a23 (9)

Amacımız vp ’yi ufak parçaların varyansları v1 , v2 , v3 üzerinden hesaplamak.


Simdi (7,8,9) formullerini kullanarak vp su sekilde de yazilabilirdi,

vp = (S1 + S2 + S3 )/n

Ya da

nvp = S1 + S2 + S3 − na2p

Açarsak

nvp = j(v1 + a1 )2 + k(v2 + a2 )2 + m(v3 + a3 )2 − na2p (10)

Şu da söylenebilir,

nvp = jv1 + kv2 + mv3 + ja21 + ka22 + ma23 − na2p

20
Şimdi (10) formülüne nasıl erisebileceğimizi düşünelim. Alttaki iki kavramdan
hareketle bunu yapabilir miyiz acaba?
Varyansların ortalamasını

av = (jv1 + kv2 + mv3 )/n (11)

ve ortalamaların varyansını

va = [j(a1 − ap )2 + k(a2 − ap )2 + m(a3 − ap )2 ]/n

diye tanımlayalım. Üstteki formülü açalım,

nva = j(a1 − ap )2 + k(a2 − ap )2 + m(a3 − ap )2

= ja21 + ka22 + ma23 − 2ap (ja1 + ka2 + ma3 ) + na2p

Ortadaki terim nap = ja1 + ka2 + ma3 olduguna gore

= ja21 + ka22 + ma23 − 2ap (nap ) + na2p

= ja21 + ka22 + ma23 − 2na2p + na2p

nva = ja21 + ka22 + ma23 − na2p

Varyansların ortalaması (11) formülünü hatırlayalım şimdi

nav = jv1 + kv2 + mv3

Üstteki iki formülü toplarsak nvp ’ye erisebilir miyiz acaba?

nva + nav = ja21 + ka22 + ma23 − na2p + jv1 + kv2 + mv3

j, k, m’nin çarptığı terimleri onların altında gruplarsak,

= j(a21 + v1 ) + k(a22 + v2 ) + m(a23 + v3 ) − na2p +

Evet bu hakikaten mümkün, (10) formülüne erişmiş olduk. Demek ki ayrı gru-
plardan elde edilen varyanslar ve ortalamarını alıp, bu varyansların ortalamasını

21
ve ortalamaların varyanslarını hesaplayıp birbirine toplayınca tüm verinin nihai
varyansına erişmiş oluyoruz.
Kod üzerinde görelim, [3]’teki veriyi kullandık,

d1 = np.array([32, 36, 27, 28, 30, 31])


d2 = np.array([32, 34, 30, 33, 29, 36, 24])
d3 = np.array([39, 40, 42])
n1,n2,n3 = len(d1),len(d2),len(d3)
dp = np.hstack([d1,d2,d3])
m1,m2,m3,mp = d1.mean(), d2.mean(), d3.mean(),dp.mean()
v1,v2,v3,vp = d1.var(), d2.var(), d3.var(),dp.var()
print (m1,m2,m3,mp)
print (v1,v2,v3,vp)
ap = (n1*m1 + n2*m2 + n3*m3) / (n1+n2+n3)
mean_of_var = (n1*v1 + n2*v2 + n3*v3) / (n1+n2+n3)
var_of_means = (n1*(m1-ap)**2 + n2*(m2-ap)**2 + n3*(m3-ap)**2) / (n1+n2+n3)
print (mean_of_var)
print (var_of_means)
print (mean_of_var + var_of_means)
30.666666666666668 31.142857142857142 40.333333333333336 32.6875
8.555555555555554 13.26530612244898 1.5555555555555554 22.83984375
9.303571428571427
13.536272321428578
22.839843750000007

Not: Birleştirirken n1 ,n2 sayıları ile çarpım var, bu aşırı büyük sayılara sebep ol-
maz mı? Olabilir doğru, ki kısmen bu sebeple artımsal hesap yapıyorduk, fakat
hala büyük sayılardan kaçmak mümkün, mesela genel ortalama hesaplarken n1 ,n2
ile çarpıp n1 + n2 ile bölüyor olabiliriz, fakat bu hesapta tek gerekli olan aslında
n1 ve n2 ’nin birbirine olan izafi büyüklüğüdür. Eğer ni /100 kullansak birleştirme
işlemi yine aynı çıkardı. O zaman bir teknik tüm ni ’leri en büyük olan ile bölmek,
böylece 1’den ufak sayılarla iş yaparız, ve sonuç yine aynı çıkar.
Box Whisker Grafikleri
Tek boyutlu bir verinin dağılımını görmek için Box ve Whisker grafikleri fay-
dalı araçlardır; medyan (median), dağılımın genişliğini ve sıradışı noktaları (out-
liers) açık şekilde gösterirler. İsim nereden geliyor? Box yani kutu, dağılımın
ağırlığının nerede olduğunu gösterir, medyanın sağındada ve solunda olmak
üzere iki çeyreğin arasındaki kısımdır, kutu olarak resmedilir. Whiskers kedi-
lerin bıyıklarına verilen isimdir, zaten grafikte birazcık bıyık gibi duruyorlar. Bu
uzantılar medyan noktasından her iki yana kutunun iki katı kadar uzatılır sonra
verideki ”ondan az olan en büyük” noktaya kadar geri çekilir. Tüm bunların
dışında kalan veri ise teker teker nokta olarak grafikte basılır. Bunlar sıradışı
(outlier) oldukları için daha az olacakları tahmin edilir.
BW grafikleri iki veriyi dağılımsal olarak karşılaştırmak için
içeren Quintus Curtius Snodgrass veri setinin değişik olduğunu ispatlamak için
bir sürü hesap yapmışlardır, bir sürü matematiksel işleme girmişlerdir, fakat basit
bir BW grafiği iki setin farklılığını hemen gösterir.

22
BW grafikleri iki veriyi dağılımsal olarak karşılaştırmak için birebirdir. Mesela
Larsen and Marx adlı araştırmacılar çok az veri içeren Quintus Curtius Snod-
grass veri setinin değişik olduğunu ispatlamak için bir sürü hesap yapmışlardır,
bir sürü matematiksel işleme girmişlerdir, fakat basit bir BW grafiği iki setin
farklılığını hemen gösterir.
Python üzerinde basit bir BW grafiği

spread= rand(50) * 100


center = ones(25) * 50
flier_high = rand(10) * 100 + 100
flier_low = rand(10) * -100
data =concatenate((spread, center, flier_high, flier_low), 0)
plt.boxplot(data)
plt.savefig('stat_feat_01.png')

Bir diğer örnek Glass veri seti üzerinde

data = loadtxt("glass.data",delimiter=",")
head = data[data[:,10]==7]
tableware = data[data[:,10]==6]
containers = data[data[:,10]==5]

print head[:,1]

data =(containers[:,1], tableware[:,1], head[:,1])

plt.yticks([1, 2, 3], ['containers', 'tableware', 'head'])

plt.boxplot(data,0,'rs',0,0.75)
plt.savefig('stat_feat_02.png')

[ 1.51131 1.51838 1.52315 1.52247 1.52365 1.51613 1.51602 1.51623


1.51719 1.51683 1.51545 1.51556 1.51727 1.51531 1.51609 1.51508
1.51653 1.51514 1.51658 1.51617 1.51732 1.51645 1.51831 1.5164
1.51623 1.51685 1.52065 1.51651 1.51711]

23
Kaynaklar
[1] Ross, Introduction to Probability and Statistics for Engineers, 3rd Edition
[2] Wasserman, All of Statistics
[3] Rudmin, Calculating the Exact Pooled Variance, https://arxiv.org/abs/
1007.1012
[4] Boughorbel, Optimal classifier for imbalanced data using Matthews Correlation
Coefficient metric, http://journals.plos.org/plosone/article/file?
id=10.1371/journal.pone.0177678&type=printable
[5] Cross Validated, Relation between the phi, Matthews and Pearson correlation coeffi-
cients?, https://stats.stackexchange.com/questions/59343/relation-
between-the-phi-matthews-and-pearson-correlation-coefficients
[6] Bayramli, Diferansiyel Denklemler, Ters Trigonometrik Formüller

24
Koşulsal Olasılık ve Koşulsal Beklenti (Conditional Probability, Conditional Ex-
pectation)
Olasılık teorisinin en faydalı tekniklerinden biri koşulsal olasılık ve koşulsal bek-
lentidir. Bunun iki sebebi var. Birincisi pratikte çoğunlukla elimizde bir bilgi
geçtiği durumda olasılık ve beklenti hesabı yaptığımız, yani istediğimiz hesapların
“koşullu” olması. İkincisi olasılık ya da beklenti hesabında bu hesabı ilk önce bir
başka rasgele değişkene koşullamanın çok faydalı olması.
Diyelim ki tavla oynarken iki zar atıyoruz, temel olasılıktan biliyoruz ki her se-
ferinde 36 mümkün sonuçlardan biri ortaya çıkacak, mesela (1,2) ya da (5,5),
vs, o zaman, eğer zar hileli değilse her sonucun olasılığı 1/36. Şimdi diyelim
ki ilk zarın 4 geldiğini gördük, ve birisi diğer zarın üstünü kapattı, ve bu bilgi
ışığında bize iki zarın toplamının 6 olma olasılığının ne olduğunu sordu. İlk
zarın 4 olduğu bilgisi verildiğine göre toplamı gözönüne almadan önce altı tane
mümkün sonucu düşüürüz,, (4,1), (4,2), (4,3), (4,4), (4,5), (4,6). Bu seçeneklerin
herbirinin ortaya çıkma ihtimali birbirine eşit. Biraz önceki sonuçları olaylar
olarak düşünürsek, E’yi iki zarın toplamının 6 olması olayı, F’yi ilk zarın 4 olma
olayı olarak tanımlayabiliriz, bu durumda aradığımız sonuç,

P(E|F)

olarak gösterilir. Bu formülün açılımı

P(EF)
P(E|F) = (1)
P(F)

P(EF) hem E hem F olaylarının aynı anda olma olasılığı, yani E kümesi ve F
kümesinin kesişimi. Bölendeki P(F) bir anlamda P(E|F) hesabını F bazında yapma
amaçlı; çünkü F olduğunu “biliyoruz” ve artık örneklem uzayımız F haline geliyor,
bu uzay içinde E’nin olma olasılığına bakıyoruz. Not: Hesabın geçerli olması için
P(F) > 0 olmalı tabii ki.
Biraz önceki örnek için aradığımız cevap 1/6 çünkü altı mümkün sonuç içinde
sadece (4,2) olayı bizi ilgilendiriyor.
Bağımsız Olaylar
İki olay E, F’nin birbirinden bağımsız olduğu söylenir, eğer

P(EF) = P(E)P(F)

ise. (1) denklemi üzerinden bu

P(E|F) = P(E)

1
sonucunu verir, bu sonuç akla yatkın olmalı, eğer E, F bağımsız ise, F’in verilmiş
olması bize E hakkında hiçbir şey söylemez.
Bayes Formülü
Yine E ve F olayları var, ki EF hem E, hem de F’nin olma durumu, o zaman E

E = EF ∪ EFc

olarak gösterilebilir çünkü bir öğenin R içinde olması için ya E ve F içinde olması,
ya da E içinde olması ama F içinde olmaması lazımdır. EF ve EFc birbirlerinin
tam tersi, karşılıklı dışarlayan (mütually exclusive) olaylar oldukları için alttaki
doğru olacaktır,

P(E) = P(EF) + P(EFc )

= P(E|F)P(F) + P(E|Fc )P(Fc )

= P(E|F)P(F) + P(E|Fc )(1 − P(F))

Üstteki son formül P(E)’nin bir ağırlıklı ortalama olduğunu söylüyor; ağırlıklar
F’in olma ve olmama olasılığı, ve bu ağırlıklar F’nin olduğu ve olmadığının ver-
ildiği durumdaki E olasılıklarının ağırlıklı ortalamasını alıyorlar.
Örnek
Bir hastalık için bir labaratuarun test tekniğinin yüzde 95 başarısı var. Fakat bu
test bazen “yanlış pozitif” cevabı da verebiliyor; hasta olmayan kişilerin yüzde
1’i için, yani 0.01 olasılıkla test hasta diyebiliyor. Eğer toplumun yüzde 0.5’inde
bu hastalığın olduğu biliniyorsa, herhangi bir kişinin testi pozitif geldiğinde o
kişinin gerçekten hasta olma olasılığı nedir?
Cevap
D test edilen kişinin hasta olma olayı diyelim, E testin pozitif olması. Aradığımız
P(D|E) olasılığı.

P(DE)
P(D|E) =
P(E)

P(E|D)P(D)
= (2)
P(E|D)P(D) + P(E|Dc )P(Dc )

(0.95)(0.005)
(0.95)(0.005) + (0.01)(0.995)

2
95
= ≈ 0.323
294

Yapılan bazı hareketlere dikkat: 4 üstteki denklemde P(DE)’yi onun bir altında
P(E|D)P(D), yani P(ED)’ye çevirdik, çünkü P(DE) ile P(ED) aynı şey.
Ayrıca çözüme yaklaşma şeklimiz istenen P(D|E) için P(E|D) ve onunla alakalı
olan rakamları kullanmak; problemde bildiğimiz E’nin verildiği durum değil,
onun tersi, D’nin verildiği durum. Yani test tekniği hakkında elimizde bazı bil-
giler var, bu bilgiler ışığında test pozitif verirse bu sonuca ne kadar inanalım diy-
oruz bir anlamda.
(2) formülü, onun ikiden fazla seçenek için ayrıksal, ya da sürekli olarak genelleştirilmiş
hali Bayes Formülü olarak biliniyor.
Rasgele Degiskenler
Hatırlayalım, iki olay E, F için P(F) > 0 ise, F’in verildiği durumda (koşul) E’nin
olasılığı

P(EF)
P(E|F) =
P(F)

O zaman X, Y ayrıksal rasgele değişkenler ise Y = y verildiği durumda X’in


koşulsal olasılık kütle fonksiyonunu (conditional probability mass function) şöyle
tanımlayabiliriz,

pX (x|y) = P(X = x|Y = y)

P(X = x, Y = y)
=
P(Y = y)

p(x, y)
=
pY (y)

ki tüm y değerleri için P(Y = y) > 0 olmalı. Benzer şekilde Y = y verildiği


durumda X’in koşulsal olasılık dağılım fonksiyonu, ki yine tüm y değerleri için
P(Y = y) > 0 olacak şekilde,

FX|Y (x|y) = P(X 6 x|Y = y)

X
pX (a|y)
a6x

Son olarak Y = y verildigi durumda X’in kosulsal beklentisi,

3
X
E(X|Y = y) = xP(X = x|Y = y)
x

X
= xpX (x|y)
x

Yani herşey daha önce normal olasılık tanımlarında olduğu gibi, sadece şimdi
tüm ifadeler Y = y olayına koşullu. Bunun söyleyebiliyoruz çünkü eğer X Y’den
bağımsız olsaydı

pX (x|y) = P(X = x|Y = y)

= P(X = x)

olurdu, ve bu formülü üstteki formüllerde koşullu olanın yerine koyduğumuzda


normal olasılık denklemlerini elde ederdik.
Örnek
p(x, y)’in X, Y rasgele değişkenlerinin ortak olasılık kütle fonksiyonu olduğunu
farz edelim, ve

p(1, 1) = 0.5, p(1, 2) = 0.1, p(2, 1) = 0.1, p(2, 2) = 0.3

olsun. Y = 1’in verili olduğu durumda X’in olasılık kütle fonksiyonunu hesaplayın.
Çözüm
Y sadece 1 olabileceğine göre, pX|Y (1|1) ve pX|Y (2|1)’i hesaplanırsa iş biter. Bu
değerleri ayrı ayrı bulacağız çünkü dağılım bir formül değil, üstteki gibi sunulan
ayrıksal olasılıklarla her ihtimal ayrı çözülmeli.

P(X = 1, Y = 1)
pX|Y (1|1) = P(X = 1|Y = 1) =
P(Y = 1)

p(1, 1) 5
= =
pY (1) 6

pY (1)’i nasil bulduk? Soyle,

X
pY (1) = p(x, 1) = p(1, 1) + p(2, 1) = 0.6
x

Ayrıca iki üstte 5/6 oldu çünkü 0.5/0.6 = 5/6. Devam edelim,

4
p(2, 1) 1
pX|Y (2|1) = =
pY (1) 6

Sürekli Durum
Sürekli rasgele değişkenler için koşullu olasılık yoğunluk fonksiyonları

fX,Y (x, y)
fX|Y (x|y) =
fY (y)

Eğer koşullu yoğunluk üzerinden olay hesabı yapmak istersek, ve fY (y) > 0
olduğunu farzederek,
Z
P(X ∈ A|Y = y) = fX|Y (x|y) dx
A

Örnek


x + y eğer 0 6 x 6 1, 0 6 y 6 1
f(x, y) =
0 diğer

P(X < 1/4|Y = 1/3) nedir?


Cevap
Üstteki olasılık hesabı için fX|Y fonksiyonuna ihtiyacımız var,

1
fY (y) = +y
2

olsun. Ana formülümüz neydi?

fX,Y (x, y)
fX|Y (x|y) =
fY (y)

x+y
= 1
2
+y

Z 1/4 1 1
x+ 3 32
+ 13 14
P(X < 1/4|Y = 1/3) = 1 1
dx = 1
=
0 2
+ 3 2
+ 13 32

Beklentileri Koşullayarak Hesaplamak


E(X|Y) beklenti hesabını düşünelim, bu hesap Y’nin bir fonksiyonu olacaktır bir
bakıma, yani her y için E(X|Y = y) farklı bir sonuç verecektir. Önemli nokta,

5
E(X|Y)’nin kendisi de bir rasgele değişkendir. Koşulsal beklentinin çok önemli
özelliklerinden biri her X, Y rasgele değişkeni için

E(X) = E(E(X|Y))

eşitliğinin doğru olmasıdır. Biraz değişik bir notasyona göre,

EY (EX|Y (X|Y)) = E(X)

İspat
Ayrıksal durum için,
X 
EY (EX|Y (X|Y)) = EY x · P(X = x|Y)
x

XX 
= x · P(X = x|Y = y) P(Y = y)
y x

XX
= x · P(X = x|Y = y)P(Y = y)
y x

X X
= x P(X = x|Y = y)P(Y = y)
x y

X X
= x P(X = x, Y = y)
x y

X
= xP(X = x)
y

= E(X)

Soru
Bir maden işçisi kaza sonrası bir madende tıkalı kalıyor. Dışarı çıkabilmesi için
önünde üç değişik kapı var; birinciyi seçerse 2 saat yürüdükten sonra dışarı
çıkacak. Eğer ikinciyi seçerse 3 saat yürüdükten sonra tekrar madene dönecek.
Üçüncüyü seçerse bu sefer 5 saat yürüdükten sonra madene dönecek. İşçi hangi
kapının onu dışarı çıkartacağını bilmiyor, herhangi bir kapıyı eşit olasılıkla seçecek.
İşçinin dışarı çıkma süresinin beklentisi nedir?
Cevap

6
X değişkeni işçinin dışarı çıkma süresini belirten rasgele değişken olsun, Y ise
işçinin ilk seçtiği kapı.

E(X) = E(X|Y = 1)P(Y = 1) + E(X|Y = 2)P(Y = 2) + E(X|Y = 3)P(Y = 3)

1 
E(X) = E(X|Y = 1) + E(X|Y = 2) + E(X|Y = 3) (3)
3

Buraya kadar basit: Fakat sorudaki puf noktaya dikkat, eger kapi 2 ay da 3 se-
cilirse isci tekrar madene donuyor, yani bastaki haline geri gelmis oluyor. O za-
man

E(X|Y = 1) = 2

E(X|Y = 2) = 3 + E(X)

E(X|Y = 3) = 5 + E(X)

Üstteki iki denklemi (3) içine koyarsak,

1 
E(X) = 2 + 3 + E(X) + 5 + E(X)
3

E(X) = 10

İşçinin dışarı çıkma beklentisi 10 saattir.


Kaynaklar
[1] Ross, Introduction to Probability Models, 10th Edition

7
Büyük Sayılar, Veri
Büyük Sayılar Kanunu (Law of Large Numbers)
Bu kanun, örneklem (sample) ile rasgele değişkenler, yani matematiksel olasılık
dağılımları arasında bir bağlantı görevi görür. Kanun kabaca bildiğimiz günlük
bir gerçeğin matematiksel ispatıdır. Yazı-tura atarken yazı çıkma ihtimalinin
1/2 olduğunu biliyoruz; herhalde çoğumuz bu yazı-tura işlemin ”bir çok kere”
tekrarlandığı durumda, toplam sonucun aşağı yukarı yarısının yazı olacağını
bilir.
Matematiksel olarak, farzedelim ki her yazı-tura atışı bir deney olsun. Deneylerin
sonucu X1 , X2 ...Xn olarak rasgelen değişkenlerle olsun, bu değişkenlerin dağılımı
aynı (çünkü aynı zar), ve birbirlerinden bağımsızlar (çünkü her deney diğerinden
alakasız). Değişkenlerin sonucu 1 ya da 0 değeri taşıyacak, Yazı=1, Tura=0.
Büyük Sayılar Kanunu tüm bu deney sonuçlarının, yani rasgele değişkenlerin av-
erajı alınırsa, yani X̄ = X1 + .. + Xn ile, elde edilen sonucun Xi ’lerin (aynı olan)
beklentisine yaklaşacağının söyler, yani n büyüdükçe X̄n ’in 1/2’ye yaklaştığını
ispatlar, yani E[Xi ] = 1/2 değerine. Notasyonel olarak E(Xi ) = µ olarak da
gösterilebilir.
Özetlemek gerekirse, bir olasılık dağılımına sahip olan, görmediğimiz bir “yer-
lerde” olan bir dağılımdan bir örneklem alıyoruz, örneklem bir zar atma işlemi
gibi (simülasyon ile bu değişkenleri de doldurabilirdik), sonra bu değişkenlerin
averajını alıyoruz, ve bu averajın o görmediğimiz bilmediğimiz “gerçek” dağılımın
µ değerine yaklaştığını görüyoruz.
Formülsel olarak, herhangi bir  > 0 için,

lim P(|X̄ − µ| 6 ) = 1
n→∞

ya da

lim P(|X̄n − µ| > ) = 0


n→∞

ya da

P(|X̄n − µ| > ) → 0

Burada ne söylendiğine dikkat edelim, Xi dağılımı ne olursa olsun, yanı ister Bi-
nom, ister Gaussian olsun, örneklem üzerinden hesaplanan sayısal ortalamanın
(empirical mean) formülsel olasılık beklentisine yaklaştığını söylüyoruz! Xi ’ler
en absürt dağılımlar olabilirler, bu dağılımların fonksiyonu son derece çetrefil,
tek tepeli (unimodal) bile olmayabilir, o formüller üzerinden beklenti için gereken
entegralin belki analitik çözümü bile mevcut olmayabilir! Ama yine de ortalama,

1
o dağılımların beklentisine yaklaşacaktır. İstatistik ile olasılık teorisi arasındaki
çok önemli bir bağlantı bu.
Sonuç şaşırtıcı, fakat bir ek daha yapalım, sezgisel (intuitive) olarak bakarsak
aslında sonuç çok şaşırtıcı olmayabilir. Niye? Diyelim ki genel veri N(µ, σ2 )
şeklinde bir Normal dağılımdan geliyor ve örneklem de bu sebeple aynı dağılıma
sahip. Bu durumda örneklemdeki veri noktalarının µ’ya yakın değerler olmasını
beklemek mantıklı olmaz mı? Çünkü bu dağılım “zar atınca” ya da bir genel
nüfustan bir “örnek toplayınca” (ki bunu bir anlamda istatistiksel bir zar atışı
olarak görebiliriz) onu µ, σ2 ’e göre atacak. Örneklemi zar atışı sonuçları olarak
gördüğümüze göre elde edilen verilerin bu şekilde olacağı şaşırtıcı olmamalı. Ve
bu zar atışlarının ortalamasının, son derece basit bir aritmetik bir işlemle hesa-
planıyor olsa bile, µ’ye yaklaşması normal olmalı.
Bu arada, bu argümana tersten bakarsak Monte Carlo entegralinin niye işlediğini
görebiliriz, bkz [3].
Özellikle örneklem ile genel nüfus (population) arasında kurulan bağlantıya dikkat
edelim. İstatiğin önemli bir bölümünün bu bağlantı olduğu söylenebilir. Her
örneklem, bilmediğimiz ama genel nüfusu temsil eden bir dağılımla aynı dağılıma
sahip olan Xi ’dir dedik, ve bu aynılıktan ve bağımsızlıktan yola çıkarak bize
genel nüfus hakkında bir ipucu sağlayan bir kanun geliştirdik (ve birazdan is-
patlayacağız).
Ispata başlayalım.
X1 , X2 , .., Xn bagimsiz degiskenler olsun.

E(Xi ) = µ

Var(Xi ) = σ

1X
n
X̄n = Xi
n i=1

X̄n de bir rasgele değişkendir, çünku X̄n değişkeni her Xi dağılımıyla alakalı.
İspata devam etmek için X̄n dağılımının beklentisini bulmamız gerekiyor.

1X
n
E(X̄n ) = E( Xi )
n i=1

E doğrusal bir işleç (linear operatör) olduğu için dışarıdan içeri doğru nüfuz eder.

2
1X
n
1
= E(Xi ) = nµ = µ
n i=1 n

Dikkat edelim, bu ortalamanın beklentisi, ortalamanın kendisinin hangi değere


yaklaşacağını hala göstermiyor. Eğer öyle olsaydı işimiz bitmiş olurdu :) Daha
yapacak çok iş var.
Şimdi X̄n dağılımının standart sapmasını da bulalım. Diğer bir olasılık kuramına
göre

Y = a + bX

Var(Y) = b2 Var(X)

oldugunu biliyoruz. O zaman,

1X
n
X̄n = Xi
n i=1

1X 1 X
n n
Var(X̄n ) = Var( Xi ) = 2 Var(Xi )
n i=1 n i=1

1 X 2
n
1 σ2
Var(X̄n ) = 2 σ = 2 nσ2 = (3)
n i=1 n n

Artık Çebişev kuramını kullanmaya hazırız. Ispatlamaya calistigimiz neydi? n →


∞ iken,

P(|X̄n − µ| > ) → 0

Çebişev’den

Var(X̄n )
P(|X̄n − µ| > ) 6
2

σ2
P(|X̄n − µ| > ) 6 →0
n2

σ2 /n2 ’in sıfıra gitmesi normal çünkü n sonsuza gidiyor.


Peki P(|X̄n − µ| > )’nin sıfıra gittiğini gösterdik mi?

3
σ2 /n2 ’nin sıfıra gittiğini gösterdik. σ2 /n2 de P(|X̄n −µ| > )’den büyük olduğuna
göre, demek ki o da sıfıra iner.
Çebişev Eşitsizliğinin ispatı ek bölümde bulunabilir.

Büyük Sayılar Kanunu örneklem ortalamasının ve varyansının Xi ’in beklentisi
ve varyansı ile bağlantı kurar. Merkezi Limit Teorisi bir adım daha atar, ve der ki
“X̄’in dağılımı Gaussian dağılım olmalıdır yani normal eğrisi şeklinde çıkmalıdır!”.
Teorinin detayları bu bölümde bulunabilir.
Merkezi Limit Teorisi (Central Limit Theorem -CLT-)
Büyük Sayılar Kanunu örneklem ortalamasının gerçek nüfus beklentisine yaklaşacağını
ispatladı. Örneklem herhangi bir dağılımdan gelebiliyordu. CLT bu teoriyi bir
adım ilerletiyor ve diyor ki kendisi de bir rasgele değişken olan örneklem ortala-
ması X̄ Normal dağılıma sahiptir! Daha detaylandırmal gerekirse,
Diyelim ki X1 , .., Xi örneklemi birbirinden bağımsız, aynı dağılımlı ve ortalaması
µ, standart sapması σ olan (ki o da aynı dağılıma sahip) bir nüfustan geliyorlar.
Örneklem ortalaması X̄,√ki bu rasgele değişkenin beklentisinin µ, ve (3)’e göre
standart sapmasının σ/ n olduğunu biliyoruz. Dikkat: X̄’in kendisinden değil,
beklentisinden bahsediyoruz, BSK’deki aynı durum, yani ortalama dağılımının√or-
talaması. Teori der ki n büyüdükçe X̄ dağılımı (bu sefer kendisi) bir N(µ, σ/ n)
dağılımına yaklaşır.
Bu ifade genelde standart normal olarak gösterilir, herhangi bir normal dağılımı
standart normal’e dönüştürmeyi daha önce görmüştük zaten, beklentiyi çıkartıp
standart sapmaya bölüyoruz, o zaman örneklem dağılımı X̄,

X̄ − µ
Z= √
σ/ n

dağılımına yaklaşır diyoruz, ki Z = N(0, 1) dağılımıdır, beklentisi sıfır, standart


sapması 1 değerindedir.
Bu teorinin ispatını şimdilik vermeyeceğiz.
Parametre Tahmin Ediciler (Estimators)
Maksimum Olurluk (maximum likelihood) kavramını kullanarak ilginç bazı sonuçlara
erişmek mümkün; bu sayede dağılım fonksiyonları ve veri arasında bazı sonuçlar
elde edebiliriz. Maksimum olurluk nedir? MO ile verinin her noktası teker
teker olasılık fonksiyonuna geçilir, ve elde edilen olasılık sonuçları birbiri ile
çarpılır. Çoğunlukla formül içinde bilinmeyen bir(kaç) parametre vardır, ve bu
çarpım sonrası, içinde bu parametre(ler) olan yeni bir formül ortaya çıkar. Bu
nihai formülün kısmi türevi alınıp sıfıra eşitlenince cebirsel bazı teknikler ile bil-
inmeyen parametre bulunabilir. Bu sonuç eldeki veri bağlamında en mümkün
(olur) parametre değeridir. Öyle ya, mesela Gaussian N(10, 2) dağılımı var ise,

4
60,90 gibi değerlerin “olurluğu” düşüktür. Gaussin üzerinde örnek,

1 1 2
f(x; µ, σ) = √ exp − 2 (x − µ) , x ∈ R
σ 2π 2σ

Çarpım sonrası

Y
1 1
f(x1 , .., xn ; µ, σ) = √ exp − 2 (xi − µ)2
σ 2π 2σ
P
(2π)−n/2 (xi − µ)2
= exp −
σn 2σ2

Üstel kısım −n/2 nereden geldi? Çünkü bölen olan karekökü üste çıkardık, böylece
−1/2 oldu, n çünkü n tane veri noktası yüzünden formül n kere çarpılıyor. Veri
noktaları xi içinde. Eğer log, yani ln alırsak exp’den kurtuluruz, ve biliyoruz ki
log olurluğu maksimize etmek normal olurluğu maksimize etmek ile aynı şeydir,
çünkü ln transformasyonu monoton bir transformasyondur. Ayrıca olurluk içbukeydir
(concave) yani kesin tek bir maksimumu vardır.

P
1 (xi − µ)2
ln f = − n ln(2π) − n ln σ −
2 2σ2

Türevi alıp sıfıra eşitleyelim

P
∂(ln f) (xi − µ)2
= =0
∂µ 2σ2
P
xi
µ̂ =
n

Bu sonuç (1)’deki formül, yani örneklem ortalaması ile aynı! Fakat buradan
hemen bir bağlantıya zıplamadan önce şunu hatırlayalım - örneklem ortalaması
formülünü biz tanımladık. “Tanım” diyerek bir ifade yazdık, ve budur dedik.
Şimdi sonradan, verinin dağılımının Gaussian olduğunu farzederek, bu verinin
mümkün kılabileceği en optimal parametre değeri nedir diye hesap ederek aynı
formüle eriştik, fakat bu bir anlamda bir güzel raslantı oldu.. Daha doğrusu
bu aynılık Gaussian / Normal dağılımlarının “normalliği” ile alakalı muhakkak,
fakat örnekleme ortalaması hiçbir dağılım faraziyesi yapmıyor, herhangi bir dağılımdan
geldiği bilinen ya da bilinmeyen bir veri üzerinde kullanılabiliyor. Bunu un-
utmayalım. İstatistikte matematiğin lakaytlaşması (sloppy) kolaydır, o sebeple
neyin tanım, neyin hangi faraziyeye göre optimal, neyin nüfus (population) neyin
örneklem (sample) olduğunu hep hatırlamamız lazım.
Devam edelim, maksimum olurluk ile σ̂ hesaplayalım,

5
P
∂(ln f) n (xi − µ)2
=− + =0
∂σ σ 2σ3

Cebirsel birkac duzenleme sonrasi ve µ yerine yeni hesapladigimiz µ̂ kullanarak,

P
2 (xi − µ̂)2
σ̂ =
n

Bu da örneklem varyansı ile aynı!


Yansızlık (Unbiasedness)
Tahmin edicilerin kendileri de birer rasgele değişken olduğu için her örneklem
için değişik değerler verirler. Diyelim ki θ için bir tahmin edici θ̂ hesaplıyoruz,
bu θ̂ gerçek θ için bazı örneklemler için çok küçük, bazı örneklemler için çok
büyük sonuçlar (tahminler) verebilecektir. Kabaca ideal durumun, az çıkan tah-
minlerin çok çıkan tahminleri bir şekilde dengelemesi olduğunu tahmin edebili-
riz, yani tahmin edicinin üreteceği pek çok değerin θ’yı bir şekilde “ortalaması”
iyi olacaktır.

Bu durumu şöyle açıklayalım, madem tahmin ediciler birer rasgele değişken, o


zaman bir dağılım fonksiyonları var. Ve üstteki resimde örnek olarak θˆ1 , θˆ2 olarak
iki tahmin edici gösteriliyor mesela ve onlara tekabül eden yoğunluklar fθˆ1 , fθˆ1 .
İdeal durum soldaki resimdir, yoğunluğun fazla olduğu yer gerçek θ’ya yakın
olması. Bu durumu matematiksel olarak nasıl belirtiriz? Beklenti ile!
Tanım
Y1 , .., Yn üzerindeki θ tahmin edicisi θ̂’den alınmış rasgele örneklem. Eğer tüm
θ’lar için E(θ̂) = θ işe, bu durumda tahmin edicinin yansız olduğu söylenir.
Örnek olarak maksimum olurluk ile önceden hesapladığımız σ̂ tahmin edicisine
bakalım. Bu ifade

1X
σ̂2 = (Yi − µ̂)2
n

ya da

6
1X
σ̂2 = (Yi − Ȳ)2
n i

ile belirtildi. Tahmin edici σ̂2 , σ2 için yansız midir? Tanımımıza göre eğer tahmin
edici yansız ise E(σ̂2 ) = σ2 olmalıdır.
Not: Faydalı olacak bazı eşitlikler, daha önceden gördüğümüz

Var(X) = E(X2 ) − (E(X)2 )

ve sayısal ortalama Ȳ’nin beklentisi E(Ȳ) = E(Yi ), ve Var(Ȳ) = 1/nVar(Yi ).


Başlayalım,

1X
 
2
E(σ̂ ) = E (Yi − Ȳ)2
n i

Parantez içindeki 1/n sonrasındaki ifadeyi açarsak,

X X
(Yi − Ȳ)2 = (Yi2 − 2Yi Ȳ + Ȳ 2 )
i i

X X
= Yi2 − 2 Yi Ȳ + nȲ 2
i i

P P
Yi ’nin hemen yanında Ȳ görüyoruz. Fakat Ȳ’nin kendisi zaten 1/n i Yi de-
i
mek değil midir?
P Ya da, toplam içinde her i için değişmeyecek Ȳ’yi toplam dışına
çekersek, Ȳ i Yi olur, bu da Ȳ · nȲ demektir ya da nȲ 2 ,

X
= Yi2 − 2nȲ 2 + nȲ 2
i

X
= Yi2 − nȲ 2
i

Dikkat, artık −nȲ 2 toplama işleminin dışında. Şimdi beklentiye geri dönelim,
 X 
1 2 2
=E Yi − nȲ
n i

1/n dışarı çekilir, beklenti toplamdan içeri nüfuz eder,


X 
1
= E(Yi2 ) − nE(Ȳ )2
n i

7
Daha önce demiştik ki (genel bağlamda)

Var(X) = E(X2 ) − (E(X)2 )

Bu örnek için harfleri değiştirirsek,

Var(Yi ) = E(Yi2 ) − E(Yi )2

Yani

E(Yi2 ) = Var(Yi ) + E(Yi )2

E(Yi ) = µ oldugunu biliyoruz,

E(Yi2 ) = Var(Yi ) + µ2

Aynısını E(Ȳ 2 ) için kullanırsak,

E(Ȳ 2 ) = Var(Ȳ) + E(Ȳ)2

E(Ȳ) = µ,

E(Ȳ 2 ) = Var(Ȳ) + µ2

X 
1 2 2
= Var(Yi ) + µ − n(Var(Ȳ) + µ )
n i

Var(Yi ) = σ, ve başta verdiğimiz eşitlikler ile beraber

X
σ2

1 2 2 2
= (σ + µ ) − n( + µ )
n i
n
P
Tekrar hatırlatalım, i sadece ilk iki terim için geçerli, o zaman, ve sabit değerleri
n kadar topladığımıza göre bu aslında bir çarpım işlemi olur,

σ2
 
1 2 2 2
= nσ + nµ − n( + µ )
n n

σ2
= σ2 + µ2 − − µ2
n

8
σ2
= σ2 −
n

nσ2 σ2
= −
n n

nσ2 − σ2
=
n

σ2 (n − 1)
=
n

n−1
= σ2
n
Görüldüğü gibi eriştiğimiz sonuç σ2 değil, demek ki bu tahmin edici yansız değil.
Kontrol tamamlandı.
Fakat eriştiğimiz son denklem bize başka bir şey gösteriyor, eğer üstteki sonucu
n
n−1
ile çarpsaydık, σ2 elde etmez miydik? O zaman yanlı tahmin ediciyi yansız
n
hale çevirmek için, onu n−1 ile çarparız ve

n 1X
(Yi − Ȳ)2
n−1n i

1 X
= (Yi − Ȳ)2
n−1 i

Üstteki ifade σ2 ’nin yansız tahmin edicisidir.


Hesap için kullandığınız kütüphanelerin yanlı mı yansız mı hesap yaptığını bilmek
iyi olur, mesela Numpy versiyon 1.7.1 itibariyle yanlı standart sapma hesabı yapıyor,
fakat Pandas yansız olanı kullanıyor (Pandas versiyonu daha iyi)

import pandas as pd
arr = np.array([1,2,3])
print 'numpy', np.std(arr)
print 'pandas', float(pd.DataFrame(arr).std())
numpy 0.816496580928
pandas 1.0

Kaynaklar
[1] Wolfram Mathworld, Maximum Likelihood, http://mathworld.wolfram.
com/MaximumLikelihood.html
[2] Introduction to Probability and Statistics Using R
[3] Bayramli, Istatistik, Monte Carlo, Entegraller, MCMC

9
Örneklem Dağılımları (Sampling Distributions)
Bir (ve en önemli) örneklem dağılımını daha önce gördük, ki bu Normal dağılımdır.
X̄ = (X1 + X2 + ... + Xn )/n ortalaması ortalaması µ ve standard sapması σ/n2 olan
bir Normal dağılıma yaklaşır. Tabii bu dağılım standardize edilebilir, vs. Fakat
rasgele değişkenler üzerinde pek çok işlem mümkündür, ve bu işlemlerin bazıları
artık ünlü olan yeni / başka dağılımlar ortaya çıkartmışlardır. Bu dağılımlar
önemlidir, çünkü mesela bazı uygulamalarda veri noktalarının karesini alırız, ve
bu karesi alınmış normal noktaların bambaşka bir dağılımı vardır! Bu önemlidir
çünkü veri noktalarının normalliği faraziyesinden hareketle kare alma işlemi gerek-
tiren her ne hesap ise onun doğruluğunu bu sonuç dağılıma sorarak kontrol ede-
biliriz!
Devam edelim.
Ȳ−µ Ȳ−µ

σ/ n
ve √
S/ n
Karşılaştırması

Diyelim ki normal olarak dağıldığını bildiğimiz bir nüfustan Y1 , .., Yn rasgele örneklemini
topladık, ve amacımız bilinmeyen gerçek µ hakkında bazı sonuçlara varmak.
Eğer varyans σ2 biliniyorsa, bu noktadan sonra ne yapacağımız gayet açık: daha
önce gördüğümüz gibi bir karar kuralı ortaya çıkartmak, ya da güven aralığı
Ȳ−µ
hesaplamak çok kolay, ki bu tekniklerin temelinde Z = σ/ √ dağılımının stan-
n
dart normal fZ (z)’ye yaklaşması yatıyor.
2
Fakat pratikte
Pn σ genellikle bilinmez, o zaman nüfus varyansının tahmin edicisi
2 1 2
S = n−1 i=1 (Yi − Ȳ) kullanılır, ki bu maksimum olurluk tahmin edicisinin
yansız (unbiased) versiyonu. Fakat buradaki önemli soru şu: σ2 yerine S2 koyma
Z oranını nasıl etkiler? Daha önce büyük örneklemler için bir fark olmadığından
bahsettik. Peki küçük örneklemler için?
Küçük n için bu iki oranının birbirinden farklı olduğununun keşfi William Sealy
Gossett adlı araştırmacıya ait. 1899’da Oxford’dan Kimya ve Matematik bölümünden
mezun olduktan sonra Gossey, Guiness adlı şirkette çalışmaya başladı. Ürünlerin
üzerinde yapacağı deneylerden aldığı veriler lojistik bazı sebepler dolaşışıyla çok
azdı, ve “gerçek” σ2 ’nin bilinmesi mümkün değildi. Çoğu zaman n 4 ya da 5’den
Ȳ−µ
bile az oluyordu. Bu gibi durumlarla uğraşa uğraşa Gossey S/ √ ’nin beklendiği
n
gibi çan eğrisi fZ (z) şeklinde değil, daha “etekleri kabarık” başka bir dağılım gibi
gözüktüğünü farketti, yani sıfırdan çok küçük ya da ondan çok büyük oranların
ihtimali çok düşük değildi.

1
Üstteki histogram S kullanarak hesaplanmıştır, n = 4 olmak üzere 500 deney
üzerinden hesap yapılmıştır. İki dağılımın birbirinden uzaklaştığı görülüyor.
Genel olarak düşünmek gerekirse, olasılık dağılımları iki büyük kategori altına
düşer. Aşağı yukarı bir düzine kadarı gerçek dünyadan alınabilecek her ölçümü
olduğu haliyle iyi modelleme kabiliyetine sahiptir; mesela normal, binom, Pois-
son, üstel dağılımlar gibi. Diğer yandan daha az sayıda (ama bir o kadar önemli)
dağılımlar n tane rasgele değişkenin üzerinden hesaplanan fonksiyonların nasıl
davrandığını çok iyi modeller. İşte bu dağılımlara örneklem dağılımları ismi ver-
ilir ve tipik kullanım alanları çıkarsama (inference) yapmaktır.
Normal dağılımı her iki kategoriye de aittir. Hem ayrı ayrı ölçümleri modelle-
Ȳ−µ
mek, hem de σ/ √ ’in olasılıksal davranışını modellemek için kullanılır. İkinci
n
kullanımı normal dağılımın bir örneklem dağılımı olarak kullanılmasına örnektir.
Normal dağılımdan sonra en önemli üç örneklem dağılımı Öğrenci t Dağılımı,
chi kare dağılımı ve F dağılımıdır. Son iki dağılım t oranını temsil eden fT (t)’yi,
Ȳ−µ
yani T = S/ √ ’yi türetmek için gerekli.
n

Türetmek
Şaşırtıcı gelebilir ama t dağılımının yoğunluk fonksiyonunu türetmek pek kolay
bir iş değildir, ilk başta kolay yapılabilirmiş gibi geliyor, çünkü Merkezi Limit
Ȳ−µ
Teorisinin temelini oluşturan σ/ √ ’in yoğunluğunu türetmek nisbeten basit, mo-
n
Ȳ−µ
√ ifadesinden Ȳ−µ
ment üreten fonksiyonlar ile yapılabiliyor. Fakat σ/ n
√ ifadesine
S/ n
geçmek çok daha zor, çünkü bu durumda T iki tane rasgele değişkeninin bir oranı
haline gelmiştir.
t Dağılımının ispatı için şu basamaklar gerekiyor; Önce standart normal ras-
gele değişkenlerin karelerinin toplamının gamma dağılımın özel bir hali olan
chi kare dağılımı olduğunu göstermek. Daha sonra normal dağılmış olan bir
nüfustan alınan n örneklemden elde edilen Ȳ ve S2 ’nin birbirinden bağımsız ras-
gele değişkenler olduğunu göstermek, ve n−1S2
’nin chi kare olarak dağıldığını is-
patlamak. Daha sonra sıra birbirinden bağımsız iki chi kare yoğunluk fonksiy-
onunun arasındaki oranı türetmeye gelecek, ki bu bir F dağılımıdır. En son olarak
Ȳ−µ
T 2 = ( S/ √ )2 ifadesinin birbirinden bağımsız iki chi kare dağılımının oranı olduğunu
n

2
göstermek ki T 2 ifadesi F dağılımının özel bir halidir.
Chi Kare, χ2 Dağılımı
Tanım
P
Z1 , .., Zp bağımsız standart Normal rasgele değişkenler ise, U = pi=1 Z2p ki bu
dagilima p derecede serbestliğe (değrees of freedom) olan chi kare dağılımı (chi
square distribution, yani χ2 ) ismi verilir.
Teori
U, p derece serbestliğe sahip bir χ2 dağılıma sahip ise, ki yoğunluk

1 (p/2)−1 −u/2
fU (u; p) = u e
Γ ( p2 )2p/2

u>0

Z∞
Γ (a) = ta−1 e−t dt
0

Üstteki yoğunluğun r = m/2 ve λ = 1/2 olan bir Gamma dağılımı olduğu da


söylenebilir. Fonksiyonunun parametresi sadece p’dir. İspat için [1, sf. 388].

E[U] = p

Var[U] = 2p

F Dağılımı
Diyelim ki U ve V birbirinden bağımsız, ve sırasıyla m ve n derece serbestliğe
sahip iki chi kare dağılımı. O zaman V/mU/n
olarak hesaplanan yeni bir rasgele
değişkenin dağılımı, m, n derece serbestliğe sahip bir F dağılımı olarak ifade
edilir.
Teori
Z 2
Rasgele değişken U/n , ki U bir chi kare dağılımıdır, 1,n derece serbestliğe sahip
bir F dağılımına sahiptir.
İspatı burada vermiyoruz.
Teori (1)
Y1 , .., Yn ortalaması µ, varyansı σ2 olan bir normal dağılımdan alınan n örneklem
olsun. O zaman

3
a. S2 ve Ȳ birbirinden bağımsızdır
2 P
b. (n−1)S
σ2
= σ12 n 2
i=1 (Yi − Ȳ) ) hesabı n − 1 derece serbestliğe sahip bir chi kare
dağılımıdır.
İspat için [1, sf. 388].
Ȳ−µ
Nihayet √
S/ n
ifadesinin yoğunluğunu bulmak için tüm altyapıya sahibiz.
Tanım
Z bir standart normal rasgele değişken, U ise n derece serbestlikteki bir chi kare
rasgele değişken olsun. O zaman n derece serbestliği olan Öğrenci t oranı (Stu-
dent’s t ratio)

Z
Tn = q (2)
U
n

olarak belirtilir.
Teori
Y1 , .., Yn , bir µ, σ normal bir dağılımdan alınmış bir rasgele örneklem olsun. O
zaman

Ȳ − µ
Tn−1 = √
S/ n

n − 1 serbestlik derecesine sahip bir t Dağılımıdır.


İspat
Ȳ−µ

S/ n
ifadesini şu şekilde yazabiliriz,

√ Ȳ−µ
Ȳ − µ σ/ n
√ =q
S/ n (n−1)S2
σ2 (n−1)

Değil mi? Alttaki karekök içindeki bölendeki n−1’ler birbirini iptal eder, karekök
Ȳ−µ
kare ifadelerini iptal eder, ve geriye kalan S/σ, ters çevirilip σ/S olarak σ/ √ ’yi
n
çarpacaktır, onun bölümdeki σ’sini iptal edecektir, ve nihai bölüme S yerleştirilmiş
olur, ve eşitliğin solundaki ifadeye erişiriz. Fakat bu dönüştürücü bölüm ifadesi
sayesinde eşitliğin sağ tarafında yeni bir formüle eriştik; karekök ifadesi içine
2
bakarsak üstteki (b) teorisiyle uyumlu olarak (n−1)S σ2
görüyoruz, ki bu ifade bir
chi kare dağılımı.
Diğer yandan eşitliğin sağındaki bölüm kısmı bir standart normal. Yani (2)’de
tarif edilen duruma erişmiş oluyoruz, üstteki ifade bu tanıma göre bir t Dağılımı.

4
t Dağılımı (Student’s t)
X, n derece bağımsızlıkta t dağılımına sahiptir, ve dağılımı

Γ ( n+1
2
)
fT (t) = (n+1)/2


n t2
nπΓ ( 2 ) 1 + n

Aslında Normal dağılımı t dağılımının v = ∞ olduğu hale tekabül eder. Cauchy


dağılımı da t’nin özel bir halidir, n = 1 halidir. Bu durumda yoğunluk fonksiy-
onu

1
f(x) =
π(1 + x2 )

Bu formül hakikaten bir yoğunluk mudur? Kontrol için entegralini alalım,


Z∞ Z∞
1 dx
f(x) dx =
−∞ π −∞ 1 + x2

Çoğunlukla entegre edilen yerde “1 artı ya da eksi bir şeyin karesi” türünde bir
ifade görülürse, yerine geçirme (subsitution) işlemi trigonometrik olarak yapılır.

x = tan θ, θ = arctan x

1 + x2 = 1 + tan2 θ = sec2 θ

dx/dθ = sec2 θ

O zaman
Z∞ Z∞ Z∞
1 dx 1 1 2 1
= = sec θ dθ = 1 dθ =
π −∞ 1 + x2 π −∞ sec2 θ π −∞

1 ∞ 1
= θ|−∞ = [arctan(∞) − arctan(−∞)]
π π

1 π π
= [ − (− )] = 1
π 2 2
Kaynaklar
[1] Larsen, Introduction to Mathematical Statistics and Its Applications
[2] Runger, Applied Statistics and Probability for Engineers

5
Güven Aralıkları
Diyelim ki X1 , .., Xi örneklemi birbirinden bağımsız, aynı dağılımlı ve ortalaması
µ, standart sapması σ ve yine aynı olan bir nüfus dağılımından geliyor. O za-
man biliyoruz ki, Merkezi Limit Teorisi (Central Limit Theorem) teorisine göre, n
arttıkça örneklem ortalaması X̄ = n1 X1 + .. + Xn , ortalaması µ, standart sapması
σ/n2 olan bir normal dağılıma yaklaşıyor.
Peki veriyi (yani örneklemi) ve CLT’yi kullanarak µ hakkında bir tahmin yapa-
bilir miyiz? Yani Büyük Sayılar Kanunua göre µ hakkında noktasal tahmin ya-
pabiliriz fakat, belki ondan bir adım ötesi, bir “güven aralığı” hesaplamaktan
bahsediyoruz. Bu tahmin “gerçek µ, %95 ihtimalde şu iki değer arasındadır”
türünde bir tahmin olacak.
Dikkat: burada verinin yüzde kaçının belli bir aralıkta olup olmadığından bah-
setmiyoruz, tahminsel hesabı yapılan ortalamanın hangi güven seviyesinde bir
aralıkta olup olmadığından bahsediyoruz. Verinin güven aralığı hakkındaki not-
lar bu yazının sonunda.
Bu aralığın hesabı için önce X̄’i standardize edelim, yani N(0, 1) haline çevirelim,

X̄ − µ
Z= √
σ/ n

Z-skorlarını işlediğimiz yazıda

P(z1 < Z < z2 ) = Φ(z1 ) − Φ(z2 )

gibi bir ifade gördük. Eşitliğin sağ tarafı aslında bir alan hesabıdır, sürekli fonksiy-
onlarda olasılık bir entegral, ya da iki kümülatif yoğunluk fonksiyonunun farkı.
Güven aralığı için bize lazım olan da bir olasılık, hatta “kesin” bir olasılık, %95
olasılığı. Demek ki eşitliğin sağ tarafı .95 olacak. .95 hesabı için, normal eğrisini
düşünürsek, sağından ve solundan 0.25 büyüklüğünde iki parçayı “kırpmamız”
lazım. O zaman 0.975 olasılığının z değeri ile, 0.025 olasılığının z değeri arasındaki
olasılıkta olmamız lazım. Bu hesaplarda baz alınan zα/2 değeri ve bu 100 · α/2 üst
yüzdelik kısmına, örneğimizde 0.975 kısmına tekabül ediyor. Normal dağılımın
simetrisi sebebiyle onun eksisi alınmış hali öteki (soldaki) parçayı verir, yani
−zα/2 .

1
Z-skoru hesaplarken tabloya danışmıştık, şimdi tabloya tersinden bakacağız, kesişme
noktasında 0.975 diyen yeri bulup kordinatları alacağız, ki bu değer 1.96.

from scipy.stats.distributions import norm


print norm.ppf(0.975)

1.95996398454

Bazı İstatistik kaynaklarında “sihirli değer” şeklinde tarif edilen bir değer bu,
gözlerimiz kamaşmasın, geldiği yer burası işte. Şimdi formülü buna göre değiştirelim,

 
X̄ − µ
P − zα/2 6 √ 6 zα/2 =1−α
σ/ n

P(·) içinde biraz düzenleme, tüm terimleri σ/ n ile çarpalım, X̄ çıkartalım, ve −1
ile çarpalım,
 
σ σ
P X̄ − zα/2 √ 6 µ 6 X̄ + zα/2 √ =1−α (1)
n n

Güven aralığı ifadesine aslına erişmiş olduk. Eğer %95 kesinlikten bahsediyor
olsaydık, ve nüfusun gerçek varyansı σ2 biliniyor olsaydı, P(·) içine bu değerleri
geçecektik, X̄ zaten verinin aritmetik ortalamasından ibarettir, bu bize µ’nun sol-
unda ve sağında bazı değerler döndürecekti. Bu değerler bizim güven aralığımız
olacaktı. Mesela veri 64.1, 64.7, 64.5, 64.6, 64.5, 64.3, 64.6, 64.8, 64.2, 64.3 şeklinde,
n = 10 çünkü 10 nokta var, σ = 1 olarak verilmiş. Ortalamayı hesaplıyoruz,
64.46. α = 0.05 için
 
1 1
P 64.46 − 1.96 √ 6 µ 6 64.46 + 1.96 √ = 0.95
10 10
 
P 63.84 6 µ 6 65.08 = 0.95

2
Yani %95 güven aralığı 63.84 6 µ 6 65.08.
Neler yaptık? CLT bilgisinden hareketle X̄ hakkında bir şeyler biliyorduk. Fakat
X̄’in kesin hangi normal dağılıma yaklaştığını bilmek için nüfus paremetreleri
µ, σ da bilinmelidir. Diğer yandan eğer tek bilinmeyen µ ise, teoriyi bu bil-
inmez etrafında tamamen tekrar şekillendirip / değiştirip CLT’yi bilinmeyen µ
etrafında bir güven aralığı yaratmak için kullandık.
Not: Eğer σ bilinmiyor ise onu da veriden hesaplarız, S2 tahmin edicisi ile, yanlız
bu durumda S2 te bir dağılıma sahip olacaktır, χ2 dağılımı, ve üstte P() içindeki
bölüm bir Normal rasgele değişkeni bolu χ2 bölümü haline gelir, ki bu bölüm
Öğrenci t dağılımı adında başka bir dağılıma sahiptir! O zaman üstteki cebirsel
hareketleri bunu hesaba katarak yapmak gerekir. Bunun detaylarını ilerideki bir
bölümde göreceğiz.
Kac Tane n?
Hatırlarsak güven aralığını üstteki şekilde hesaplayabilmemizin sebebi CLT sayesinde
X̄’in normal dağılıma yaklaşıyor olmasıydı. Ve, teoriyi tekrar düşünürsek yaklaşma
n → ∞ olduğu zaman oluyordu. Buradan X̄’in normalliğinin “büyükçe” n
değerleri için daha geçerli olacağı sonucuna varabiliriz. Peki n ne kadar büyük
olmalı? Literatüre göre CLT’nin genellikle n > 30 durumunda geçerli olduğu
söylenir. Tabii nüfus dağılımının ne olduğu da önemlidir, eğer nüfus normal
ise, ya da genel olarak simetrik tek tepeli dağılım ise örneklem daha ufak kalsa
da bazı sonuçlara varabiliriz. Eğer nüfus dağılımı çok yamuk (skewed), etekleri
geniş dağılım ise o zaman daha büyük örneklem daha iyi olur.
Soru
İÖ 800 yıllarında İtalya’da Etrusyalı (Etruscan) toplumu vardı, bilinmeyen bir se-
beple bu insanlar geldikleri gibi birdenbire ortadan kayboluverdiler. Bilimciler
bu toplumun İtalyalılar ile fizyolojik, genetik ve kültürel olarak bağlantısı olup
olmadığını hep merak etmiştir. Bazıları hafa ölçülerine bakarak sonuçlara var-
maya uğraşmıştır. Arkeolojik kazılarda yapılan ölçümlerde 84 Etrusyalının kafası
ölçülmüştür. Ayrıca bugünkü İtalyanların kafa ölçümlerinin normal dağılımda
µ = 132.4mm, σ = 6.0mm olduğu bilinmektedir. İki toplum arasındaki bağlantı
kurmak için, veriye bakarak kafa ölçümü ortalaması için bir %95 güvenlik aralığı
oluşturabiliriz, ve eğer bugünkü İtalyanların ölçüsü o aralığa düşmüyorsa, Etrusyalılarla
bağlantılarının olmadığını iddia edebiliriz.

import pandas as pd
dfetr = pd.read_csv('../stat_035_tests/etrus.csv')
print (float(dfetr.mean()-1.96*(6.0/np.sqrt(84))))
print (float(dfetr.mean()+1.96*(6.0/np.sqrt(84))))

142.524107721075
145.09035011025028

Bugünkü İtalyanların kafa ortalaması µ = 132.4 bu aralığa düşmüyor. Diğer


bir deyişle, 84 tane örneklemden gelen örneklem ortalaması 143.8 büyük bir ih-

3
timalle µ = 132.4, σ = 6.0 boyutlarındaki bir normal dağılımdan gelmemiştir.
Buna göre, büyük bir ihtimalle Etrusyalılar İtalyanların atası değildir.
Bilinmeyen σ
Güven Aralıkları bölümünden devam edelim. Bilinmeyen µ durumunu gördük.
Eğer σ bilinmiyorsa, bu durumda σ yerine örneklem varyansı S kullanılabilir,

1X
S2 = (Xi − X̄)2
n

ki üstteki değerin karekökü S olacaktır. σ yerine S kullanmanın büyük n değerlerinde


CLT’yi etkilemediği ispat edilmiştir [5]. Fakat daha küçük örneklem durumunda
t Dağılımı daha uygun olur.
T Dağılımı
Daha önce Z oranını temel alarak güven aralıkları ya da hipotez testleri oluşturmuştuk.
Bu işlemler için standart normal dağılımın üst ve alt yüzdelikleri hakkında bazı
bilgiler gerekmişti. Bu bilgiler bir tablodan bakılan değerlerdi ya da istatistik
yazılımımızda gerekli bir çağrı ile hemen bulunabiliyorlardı.

Öğrenci t’nin Z’ye göre farklı bir tarafı belli bir değeri bulmak için iki parame-
treye ihtiyaç olması, bunlardan biri α diğeri ise serbestlik derecesi (degree of
freedom -dof-). Standart normal için tablo paylaştık, fakat t için artık tablolarla
uğraşmayacağız, bilgisayar çağındayız, yazılım ile bu işi halledelim!
Örnek
T bir Öğrenci t dağılımı ise, ve serbestlik derecesi 3 ise, α = 0.01 için için fT (t)’nin
100(1 − α) yüzdeliği nedir? Üstteki grafikteki tα,n notasyonundan hareketle t0.01,3
değerini arıyoruz yani.

from scipy.stats.distributions import t


df = 3
print t.ppf(0.99,df)
print 1-t.cdf(4.541,df)

4.5407028587
0.00999823806449

Yani

4
P(T3 > 4.541) = 0.01

Ȳ−µ

S/ n
ifadesinin n-1 derece serbestliğe sahip Öğrenci t dağılımına sahip olduğunu
bilmek alttaki ifadeyi mümkün kılar,

 
Ȳ − µ
P − tα/2,n−1 6 √ 6 tα/2,n−1 =1−α
S/ n

Bu ifadeyi daha önce standart normal için yaptığımız gibi tekrar düzenlersek,
 
S S
P Ȳ − tα/2,n−1 √ 6 µ 6 Ȳ + tα/2,n−1 √ =1−α
n n

Tabii, Yi ’ların normal dağılımdan gelmiş olması lazım. Bunun sonucunda gerçek
veri temel alınarak hesaplanacak S ve Ȳ bize µ için bir %100(1 − α) güven aralığı
verecektir.
Örnek
Yapışkan elementlerin üzerinde yapılan deneyler sonucundaki ölçümler altta verilmiştir.
Acaba µ için %95 güven aralığı nedir?
Öncelikle verinin normal dağılımdan geldiği doğru mudur? Bu faraziyeyi kon-
trol etmemiz gerekir yoksa t dağılımını kullanamayız. Önce bir kutu grafiği (box-
plot) yapalım,

data = np.array([19.8,10.1,14.9,7.5,15.4,15.4,15.4,18.5,7.9,12.7,
11.9,11.4,11.4,14.1,17.6,16.7,15.8,19.5,8.8,13.6,11.9,11.4])
plt.boxplot(data)
plt.savefig('stat_ci_01.png')

Şimdi normal olasılık grafiği (normal probability plot) yapalım, ki bu grafik verinin
normal dağılıma ne kadar uyumlu olduğunu grafik olarak gösterir, eğer uyumlu
ise veri düz çizgiye yakın çıkmalıdır,

import scipy.stats as stats


res = stats.probplot(data, plot=plt)
plt.savefig('stat_ci_02.png')

5
Bu grafiklere bakınca verinin normal olduğu belli oluyor. Zaten örneklem sayısı
az, bu sebeple t dağılımı kullanmak uygun. Veri sayısal ortalaması ve sayısal
standart sapmasına bakalım, ve güven aralığını hesaplayalım, yani

√ √
x̄ − tα/2,n−1 s/ n 6 µ 6 x̄ + tα/2,n−1 s/ n

from scipy.stats.distributions import t


n = len(data)
dof = len(data)-1
m = np.mean(data)
s = np.std(data)
print 'ortalama',m
print 'sapma',s
print m + t.ppf(0.025,dof) * s / np.sqrt(n),\
m - t.ppf(0.025,dof) * s / np.sqrt(n)

ortalama 13.7136363636
sapma 3.47187340764
12.174293931 15.2529787962

Güven aralığı oldukça geniş, çünkü (demek ki) ölçümlerde yüksek değişkenlik
var.
Normal Nüfusun Varyansının Güvenlik Aralığı
Bazen nüfusun varyansı ya da standart sapması üzerinde bir güven aralığı hesapla-
mak gerekebilir. Eğer nüfus normal olarak dağılmış ise, şimdiye kadar gösterdiğimiz
tekniklerin hepsi kullanılabilir. (1) teorisinin b kısmındaki ifadeyi kullanırsak,
nüfusu µ, σ parametreli bir normalden alınan X1 , .., Xn örneklemi üzerinden hesa-
2
planan X2 = (n−1)S
σ2
ifadesinin n − 1 serbestlik derecesindeki bir chi kare dağılımı
olduğunu biliyoruz.
Chi karenin yüzdelik kısımları altta görülebilir,

6
from scipy.stats.distributions import chi2
print chi2.ppf(0.05,5)
print chi2.ppf(0.99,5)

1.14547622606
15.0862724694

Dikkat edilmesi gereken bir konu chi karenin yamuk (skewed) olması sebebiyle
sağdaki ve soldaki alan hesaplarının arasında z skorunda olduğu gibi her se-
ferinde birebir geçiş yapılamayabileceği.
Notasyonel olarak χ2p,n ifadesi, x eksenindeki bir eşik noktasını ifade eder ki bu
değerin sol tarafındaki alan büyüklüğü p, n serbestlik derecesindeki chi kare
dağılımının alanıdır. Mesela üstte χ20.05,5 = 1.145 ve χ20.99,5 = 15.086. Olasılık
ifadesi olarak

P(χ25 6 1.145) = 0.05

P(χ25 6 15.086) = 0.05

Not: Bazı kaynaklar eşik değerinin sağ kısmını referans alıyor her nedense, bu
duruma dikkat.
σ2 İçin Güvenlik Aralığı
Chi kare tanımından hareketle şu ifadeyi yazabiliriz,

(n − 1)S2
 
2 2
P χα/2,n−1 6 6 χ1−α/2,n−1 = 1 − α
σ2

Belirtildiği üzere, üstteki ifadenin Z’li halinde olduğu gibi, bir z değerini alıp,
eksi ile çarparak (ve çarpmayarak) hem sol hem sağda eşik değeri olarak kul-
lanamadık çünkü chi kare simetrik değil. Eşik değerinin belli noktalarda ayrı
ayrı hesaplanması gerekiyor.

7
Üstteki denklem birkaç cebirsel işlem sonrasında σ2 ’yi ortada tek başına bırakacak
şekilde değiştirilebilir, önce eşitsizlikleri tersine çeviriyoruz, aynı anda ortadaki
bölüme tersine çeviriyoruz, ve yeni böleni hem sol hem sağa çarparak taşıyoruz,

(n − 1)S2 (n − 1)S2
 
P 2 6 σ2 6 2 =1−α
χ1−α/2,n−1 χα/2,n−1

Eşitsizliğin karekökünü alırsak, σ için %100(1 − α) güven aralığı

s s 
(n − 1)S2 (n − 1)S2
,
χ21−α/2,n−1 χ2α/2,n−1

Örnek
Bir fabrikada deterjanları doldurmak için bir makina kullanılıyor. Rasgele seçilen
bir örneklemde 20 tane deterjan plastik şişeden alınan ölçümlerde örneklem varyansının
s2 = 0.0153 olduğu hesaplanıyor (birim ons2 ). Bu ölçümlerin standart sapması
σ2 için %95’lik üst güven sınırı nedir?

s
(19)0.0153
σ2 6
χ20.05,19

from scipy.stats.distributions import chi2


print chi2.ppf(0.05,19)

10.1170130639

r
(19)0.0153
σ2 6 = 0.0287
10.117

Yani

σ 6 0.17

Demek ki nüfusun gerçek standart sapması 0.17 ons kadar büyük olabilir.
Nüfus Ortalama Farkı, µ1 − µ2 Güven Aralığı
İki farklı nüfusun ortalamaları µ1 , µ2 ’nin birbirinden farklı olup olmadığını, ve bu
farkın istatistiki önemli olup olmadığını nasıl anlarız? Bir yaklaşım, iki nüfusun
örneklem ortalaması X̄1 , X̄2 ’i kullanmak ve farklılık µ1 − µ2 ’ için bir güven aralığı
oluşturmak, eğer sıfır değeri bu aralık içine düşüyorsa, farklılık vardır. Birbirinden
aynı olan şeylerin farkı sıfır olduğuna göre eğer sıfır güven aralığı içinde ise bu
iki nüfusun ortalamasının birbirine yakın olduğundan emin olabiliriz.

8
Devam edelim; Merkezi Limit Teorisi’ne göre yeterince büyük örneklemler, yani
n1 > 30, n2 > 30 için, X̄1 , X̄2 Normal olarak dağılmaya mecbur.
Diğer yandan biliyoruz ki iki Normal dağılımın toplamı, ya da çıkartılması yeni
bir Normal dağılım verir. µa , µb ve σa , σb için, toplam N(µa + µb , σa + σb )
elde edilir. Örneklem durumunda ve çıkartma sonrası yeni ortalama ve standart
sapma

σ21 σ2
µ1 − µ2 , + 2
n1 n2

olacaktır [1, sf. 257].


Ayrıca µ ortalamasına, σ varyansına sahip bir X̄’i

X̄ − µ
Z= √
σ/ n

ile standart normal Z = N(0, 1)’e cevirilebileceğimizi biliyoruz.


O zaman yaklaşım şöyle olabilir; X̄1 − X̄2 ’i hesaplarız, bu dağılımın kesinlikle nor-
mal olduğunu biliyoruz; o zaman nüfus ortalama ve standart sapması üzerinden
standardizasyon ve biraz cebirsel cambazlık ile µ1 − µ2 için bir güven aralığı
oluştururuz.

X̄1 − X̄2 − (µ1 − µ2 )


Z= p 2
σ1 /n1 + σ22 /n2
 
X̄1 − X̄2 − (µ1 − µ2 )
P − zα/2 6 p 2 6 zα/2 =1−α
σ1 /n1 + σ22 /n2

P[(X̄1 − X̄2 ) − zα/2 σw 6 µ1 − µ2 6 (X̄1 − X̄2 ) + zα/2 σw ] = 1 − α


p
ki σw = σ21 /n1 + σ22 /n2 . Eğer σ bilinmiyorsa, onun yerine, yine yeterince büyük
örneklem için örneklem standart sapması s kullanılabilir.
σ2 için yansız (unbiased) tahmin edici

s2 = σi (Xi − X̄)2 /(n − 1)

Not: Kaynaklarda çoğunlukla σ2 yerine s2 kullanılırsa Z yerine T yani Öğrenci


T dağılımı kullanılması tavsiye edilir, fakat eğer örneklem yeterince büyük ise Z
kullanımında problem yoktur [3, sf. 544].
Bir biyolog erkek ve dişi çekirgelerin uzunluk ölçümünü (ölçek milimetre) alıyor.
Bu iki ölçümlerin ortalaması birbirinden farklı mıdır?

9
a = [5.20, 4.70, 5.75, 7.50, 6.45, 6.55, 4.70, 4.80, 5.95, \
5.20, 6.35, 6.95, 5.70, 6.20, 5.40, 6.20, 5.85, 6.80, \
5.65, 5.50, 5.65, 5.85, 5.75, 6.35, 14.1, 12.2, 14.0, 14.6, \
5.75, 5.95, 5.90, 7.00, 6.10, 5.80]

b = [8.25, 9.95, 5.90, 7.05, 8.45, 7.55,\


9.80, 10.80, 6.60, 7.55, 8.10, 9.10, \
6.10, 9.30, 8.75, 7.00, 7.80, 8.00, \
9.00, 6.30, 8.35, 8.70, 8.00, 7.50, \
9.50, 8.30, 7.05, 8.30, 7.95, 9.60 ]
a = np.array(a)
b = np.array(b)

ma = np.mean(a); sa = np.std(a,ddof=1)
mb = np.mean(b); sb = np.std(b,ddof=1)

from scipy.stats.distributions import norm


sw = np.sqrt(sa**2/len(a) - sb**2/len(b))

print (mb-ma) + np.array([-1,1]) * norm.ppf(0.975)*sw

[ 0.53624225 2.09983618]

Yüzde 95 güven aralığı 0 değerini içermediği için nüfus ortalamalarının birbirinden


farklı olduğu sonucuna varıyoruz.
Verinin Yüzde Kaçı, Ortalama
Verinin yüzde 68’inin hangi aralık olduğu hesabı biraz farklı, ve daha basit. Mesela
kafatası ölçümü için

print (np.array([dfetr.mean() - dfetr.std(),


dfetr.mean() + dfetr.std()]).T)

Yani ortalam etrafında sağda ve solda tek standart sapmayla belirli bölge, bir
Normal dağılımın yüzde 68’ine tekabül eder, ve bir veri Normal şekilde dağılmış
ise, o verinin yüzde 68’inin hangi aralıkta olduğu bu şekilde hesaplanabilir.
[[137.80833099 149.80612685]]

10
Yüzde 95 hesabı için sağda ve solda iki standart sapmaya bakmak gerekir,

print (np.array([dfetr.mean() - 2*dfetr.std(),


dfetr.mean() + 2*dfetr.std()]).T)

[[131.80943306 155.80502478]]

Peki yüzde 68, yüzde 95, gibi değerlerin standart sapma ile bağlantısının nere-
den biliyoruz? Düşünelim, her normal dağılım standart normal dağılıma in-
dirgenebilir, ve standart normal dağılım N(0, 1)’dir, yani ortalaması 0 standart
sapması 1. O zaman bu dağılımın, sıfır etrafında -1 ve +1 sınırları içindeki alan
nedir hesabı basit kumulatif yoğunluk ile yapılabilir,

from scipy.stats.distributions import norm


print (norm.cdf(1)-norm.cdf(-1)) # tek standart sapma
print (norm.cdf(2)-norm.cdf(-2)) # iki standart sapma

0.6826894921370859
0.9544997361036416

Her dağılımın tamamının alanı bilindiği gibi 1, bu sebeple üstteki rakamlar bir
yüzde olarak algılanabilir.
Kaynaklar
[1] Larsen, Introduction to Mathematical Statistics and Its Applications
[2] Runger, Applied Statistics and Probability for Engineers
[3] Dekker, Probability and Statistical Inference

11
Binom İçin Normal Yaklaşıksallığı
Merkezi Limit Teorisinden X̄’nin her Xi için aynı olan nüfus beklentisi ve sap-
masını içeren N(µ, σ) olarak dağılacağını biliyoruz. Ve bu durum, nüfus hangi
dağılıma sahip olursa olsun geçerlidir. X1 , .., Xn birbirinden bağımsız ve aynı Bernoulli
olarak dağılmış, ve onların toplamını temsil eden binom dağılımı X olarak tanımlayalım,
o zaman

X = X1 + X2 + .. + Xn

Daha önceden biliyoruz ki E(Xi ) = p, Var(Xi ) = p(1−p), standart sapma varyansın


karekökü. O zaman Merkezi Limit Teorisine göre,

X/n − p X − np
Z= p =p
p(1 − p)/n np(1 − p)

Soru
Amerikalıların yüzde 12’sinin zenci olduğunu biliyoruz. Eğer 1500 kişiyi içeren
bir örneklem alsaydık, bu örneklemde 170’den daha az zenci olmasının olasılığı
nedir?
Cevap
%12 nüfus parametresidir, yani p = 0.12. Örneklem n = 1500. Normal yaklaşıksallaması
ile

from scipy.stats import norm


n = 1500
p = 0.12
mu = n*p
std = np.sqrt(n*p*(1-p))
print mu,std
print 'olasilik',norm.cdf(170,loc=mu,scale=std)

180.0 12.585706178
olasilik 0.213437028747

Yani N(180, 12.58) dağılımını elde ettik ve hesapları onun üzerinden yaptık. Sonuç
diyor ki verilen örneklem ve nüfus p değeri ile 170 altında zenci sayısı elde etmek
oldukça düşük bir ihtimalde.
Örnek
Diyelim ki elimizde bir Web sitesinin günlük ziyaret, tıklama sayılarını gösteren
bir veri seti var, CVR ziyaretçilerin sitedeki tıklayan müşteriye dönüşmesi oranı
(conversion).

import pandas as pd
from scipy import stats

1
a = pd.DataFrame({'tiklama': [20.,2.,40.,5.,10.,100.],
'ziyaret': [100.,10.,300.,400.,30.,800.]})
a['cvr'] = a['tiklama'] / a['ziyaret']
print a

tiklama ziyaret cvr


0 20 100 0.200000
1 2 10 0.200000
2 40 300 0.133333
3 5 400 0.012500
4 10 30 0.333333
5 100 800 0.125000

Bu veri seti için cvr’in 0.16, yani yüzde 16 olduğunu önceden biliyoruz. Üstteki
başarı oranı binom dağılı ile modellenebilir, ziyaretler ”deneylerdir”, yani örneklem
büyüklüğünü gösterirler. Tıklama ise başarıdır, önceki binom örneğindeki aynı
formülü kullanırsak, normal yaklaşıksallığı üzerinden bir z-skoru hesaplayabili-
riz,

p = 0.16
btest = lambda x: (x['cvr']-p) / np.sqrt( p*(1-p)/x['ziyaret'])
a['guven'] = a.apply(btest, axis=1)
a['guven'] = np.round(stats.zprob(a['guven'])*100,2)
print a

tiklama ziyaret cvr guven


0 20 100 0.200000 86.24
1 2 10 0.200000 63.50
2 40 300 0.133333 10.39
3 5 400 0.012500 0.00
4 10 30 0.333333 99.52
5 100 800 0.125000 0.35

Soru
Amerika’da 2009 yılında halkın ne kadarının arabalarında yakıt tasarrufunu destek-
lediği merak konusuydu. Bir Gallup telefon anketinde bu soru 1012 yetişkine (18
ve üstü yaşta) soruldu. Cevap 810 kişinin tasarrufu desteklediği yönündeydi.
Yani n = 1012, k = 810. O zaman p için %95 güven aralığını bulun.
Cevap

 r r 
810 (810/1012)(1 − 810/1012) (810/1012)(1 − 810/1012)
− 1.96 , 1.96
1012 1012 1012

= (0.776, 0825)

Python ile

m = 810/1012.
low = m - 1.96*np.sqrt(m*(1-m)/1012.)

2
high = m + 1.96*np.sqrt(m*(1-m)/1012.)
print low, high

0.775768711331 0.825021802503

Soru
Borsa konusunda okuyuculara tiyo veren bir gazete, bir şirket hissesinin belli bir
olay ardından çoğunlukla yükseldiğini söylüyor. Yazara göre hisse 9 olay içinden
6’sında bu çıkmış. Buradan hareketle yazar hissenin tekrar çıkma şansının 6/9=%66.7
olduğunu iddia ediyor. Okuyucu bunu ciddiye alsın mı?
Cevap
Ufak örneklemler için Agresti ve Coull yöntemini kullanmak iyi olur, bu yönteme
göre başarılı olay sayısına iki, tüm olay sayısına 4 ekleriz (yani 2 başarısızlık
eklemiş oluruz) ve p̂ = (x + 2)(n + 4) elde edilir. Bu ekler hem genel teorik olarak
bir değişim yaratmaz, hem de örneklem sayısını arttırarak Normal yaklaşıksallığını
kullanabilmemizi sağlar. Güven aralığı,

x=6.;n=9.;p=(x+2)/(n+4); z = 1.96
print p + np.array([-1,+1])*z*np.sqrt(p*(1-p)/n)

[ 0.29753517 0.93323406]

Demek ki yazar okuyucularına kötü bir tavsiye vermiş, güven aralığının alt kısmı
%30 olduğuna göre hissenin yükselmesi garanti değildir, garanti için güven aralığının
iki ucu da %50 üzerinde olmalıydı. Noktasal tahmin bağlamında %66.7 rakamı
da yanıltıcıdir. Bu yazar okuyucularının para kaybetmesine sebep olabilir.
Örneklem Büyüklüğü
Bir araştırmacı n bağımsız deney baz alınarak elde edilen binom parametresi p’yi
tahmin etmek istiyor, fakat kaç tane n kullanması gerektiğini bilmiyor. Tabii ki
daha büyük n değerleri daha iyi sonuçlar verecektir, ama her deneyin bir masrafı
vardır. Bu iki gereklilik nasıl birbiri ile uzlaştırılır?
Yeterli olacak en az kesinliği, duyarlılığı (precision) bulmak için Z transformasy-
onu kullanılabilir belki. Diyelim ki p için maksimum olurluk tahmini olan X/n’in
en azından 100(1 − α)% olasılıkta p’nin d kadar yakınında olmasını istiyoruz. O
zaman alttaki denklemi tatmin eden en ufak n’i bulduğumuz anda problemimizi
çözdük demektir,
 
X
P −d6 −p6d =1−α (1)
n

Tahmin edici X/n’nin kendisi de bir rasgele değişkendir. Bu değişken normal


olarak dağılmıştır, çünkü X Binom olarak dağılmış ise, bu dağılım ayrı Bernoulli
dağılımlarının toplamına eşittir. Fakat başka bir irdeleme bizi daha basitçe sonuca
götürür, binom dağılımı bir toplamdır, bu toplamı, yani X’i n ile bölüyorsak,
otomatik olarak bir aritmetik averaj işlemi yapmış oluyoruz. Bağımsız özdeşçe

3
dağılmış (ıid) rasgele değişkenlerin aritmetik ortalaması Merkezi Limit Kanunu’na
göre normal’e yaklaştığına göre o zaman, elimizde bir normal dağılım var de-
mektir.
Standardize etmek için X/n’den beklentiyi çıkartıp standart sapmaya bölebiliriz.
Beklenti zaten çıkartılmış durumda (şansa bak!), beklentinin ne olduğunu kontrol
edelim tabii, ezbere yapmayalım bu işi, eğer her Bernoulli’yi Xi olarak temsil
edersek,

X = X1 + .. + Xn

X/n = 1/n(X1 + .. + Xn )

E[X/n] = E[1/n(X1 + .. + Xn )]

= 1/nE[(X1 + .. + Xn )]

= (1/n)np = p

Varyans için

1 1 1
Var(X/n) = 2
Var(X) = 2 np(1 − p) = p(1 − p)
n n n
Binom dağılımlar için Var(X) = np(1 − p) olduğunu biliyoruz. Standart sapma
üstteki ifadenin karekökü, yani

p
Std(X/n) = p(1 − p)/n

Simdi standardize edelim,

 X 
−d −p d
P p 6p n 6p =1−α
p(1 − p)/n p(1 − p)/n p(1 − p)/n
 
−d d
P p 6 Zp =1−α
p(1 − p)/n p(1 − p)/n

Daha önceki z-skoru içeren eşitsizlikleri hatırlarsak, üstteki ifade

d
p = zα/2
p(1 − p)/n

4
O zaman

z2α/2 p(1 − p)
=n
d2

Fakat bu bir nihai sonuç olamaz, çünkü n, p’nin bir fonksiyonun haline geldi ve
p bilinmeyen bir değer. Fakat biliyoruz ki 0 6 p 6 1, ve p(1 − p) 6 41 . Yani bir üst
sınır (upper bound) elde ettik.
Bunu kontrol edelim, p(1 − p) hangi p’de maksimize olur? p’ye göre türev alırız,
sıfıra eşitleriz, (p − p2 ) 0 = 1 − 2p = 0, p = 1/2. Ve hesabı yaparsak, 1/2(1 − 1/2) =
1/4. Demek ki p(1 − p) değeri 1/4’ten daha büyük olamaz. Buna göre, üstteki
formüle p(1 − p) yerine onun olabileceği en büyük değeri koyarsak,

z2α/2 1/4
=n
d2

z2α/2
n=
4d2

Not: p(1 − p), 1/4 değerinden daha küçük olabilir mi? Olabilir. Bu durumda
n üstteki formülden elde edebileceğimiz değerden daha küçük te çıkabilecektir.
Fakat p(1 − p)’in olabileceği en büyük değer 1/4’u kullanarak “n’in bundan daha
büyük olmasına gerek yok” diyebilen bir formüle erişmiş olduk, yani, aslında n
için bir üst sınır elde ettik.
Örnek
Büyük bir şehirde çocukların kaçta kaçının aşısını almış olup olmadığını anla-
mak için bir anket gerçekleştirilecek. Anketi düzenleyenler örneklem oranı olan
X/n’in en az 98% oranda gerçek oran p’nin 0.05 yakınında olmasını istiyorlar.
Örneklem ne kadar büyük olmalıdır?
Burada 100(1−α) = 98, o zaman α = 0.02, demek ki zα/2 = z0.02/2 = z0.01 değerine
ihtiyacımız var. Python ile

from scipy.stats.distributions import norm


print norm.ppf(0.99)

2.32634787404

Tüm hesap için

(2.33)2
n= = 543
4(0.05)2

Demek ki kabul edilebilir en ufak değer 543.

5
Hata Payı (Margin of Error)
Basında oranları rapor ederken onunla beraber telafuz edilen bir kavram hata
payıdır. Aslında bu binom dağılımlarda güven aralığı ile çok yakından alakalıdır;
hata payı %95 güven aralığının en maksimum genişliğinin yarısı olarak bilinir.
Yani %95 aralığının bir ucunu diğer ucundan çıkartırsak ve ikiye bölersek, istenen
sonuca erişiriz. Formülsel olarak genişlik w,

r  r 
k (k/n)(1 − k/n) k (k/n)(1 − k/n)
w = + 1.96 −− − 1.96
n n n n
r
(k/n)(1 − k/n)
= 3.92
n

Şimdi (k/n)(1 − k/n) çarpımını düşünelim. [8] bölümünde gördük, n her zaman
k’den büyük olduğuna göre k/n her zaman 0 ve 1 arasındadır, o zaman (k/n)(1−
k/n) 6 1/4 olmalıdır, yani gösterilen çarpım 1/4’ten büyük olamaz. Bunu alıp
üstteki formül içine koyarsak,

r
1
max w = 3.92
4n

elde ederiz. Bunun yarısı hata payıdır d olur, yani

0.98
d= √
n

Örnek
Bir seçim kampanyası sırasında A ve B adayları arasında hangisinin daha önce
olduğunu bulmak için bir anket yapılır. Telefonda 597 kişiye sorulduğunda A
adayının 299 kişinin oyunu alacağı saptanmıştır. Basın durumu “A adayının
avantajı hata payı %4 içinde olduğu için o önde kabul edilebilir” diye rapor
etmiştir. A oylarının hata payı hakikaten %4’müdür?

n = 597.
k = 299
print n/2
print k/n
d = 0.98/np.sqrt(n)
print d*100

298.5
0.500837520938
4.01087299444

Evet hata payı %4 çıktı.

6
Dikkat edilirse hata payının anketten gelen sonuçlarla hiçbir alakası yok, A için
tercih %25, %75 olabilirdi ama üstteki hata payı hesabı yine aynı kalırdı. Bunun
sebebi formülün n’ye bağlı olması.
Daha önemli soru hata payı basının üstteki ifadesinin gerçekten seçim sonucu ile
alakalı olup olmadığı!
Hipotez Testleri (Hypothesis Testing)
İstatistik tek ya da aralıklar olarak sayısal tahminler üretmenin ötesinde, “iki
şey arasında birisini seçmek” türünde bir karar bağlamında da kullanılabilir. Bir
psikolog bir davaya uzman görüş vermek için çağrılmıştır ve sanık hakkında ’aklı
olarak dengesiz ya da dengeli’ arasında bir seçim yapacaktır. İlaç regülasyonu ile
uğraşan kurum yeni bir ilaç hakkında ’etkili’ ya da ’etkisiz’ şeklinde bir karara
ulaşacaktır.
Bir deneyin mümkün sonuçlarını belli seçeneklere yönlendirip olasılık teorisini
kullanarak bunlardan birisini seçmeye İstatistik biliminde Hipotez Test Etmek
adı verilir.
Birbiriyle yarış halinde olan iki hipotez vardır, bunlar sıfır hipotezi (H0 olarak
yazılıyor) ve alternatif hipotezdir (H1 olarak yazılıyor). Ho ve H1 arasında nasıl
seçim yapacağımız kavramsal olarak bir davada jürinin yaptığı seçime benzer:
aynen sanığın, tersi ispatlanana kadar, masum kabul edilmesi gibi eğer veri tersi
sonuca varmaya yetmezse H0 da “kabul edilir”, yani suçsuzluğun devam etmesi
gibi H0 görüşü terkedilmemiş olur. Statüko devam eder. Bu kararı verirken
mahkemenin kanıtları incelemesi, hipotez testinde rasgele değişkenlerle verinin
üzerinden hesaplar yapmaya benzer.
Bunu bir örnek üzerinden daha iyi anlayabiliriz. Diyelim ki araba üreten bir
şirket yakıt performansını (gas mileage) arttırmaya uğraşıyor. Benzine katılan
yeni bir madde üzerinde deneyler yapıyorlar, deney için Boston / Los Angeles
arasında 30 tane araba sefer yapıyor. Yeni katkı maddesi olmadığı durumda
(statüko) yakıt performansının ortalama 25.0 mil/galon ve standart sapmanın
2.4 mil/galon olduğu biliniyor. Diyelim ki deney sonrasında arabalar ortalama
olarak ȳ=26.3 mil/galon performansı göstermişler. Katkı maddesi etkili mi, etkili
değil mi?
Araştırmacılar 25.0’dan 26.3’e olan değişikliği daha önce bahsettiğimiz mahkeme
örneğindeki gibi bir çerçevede incelerler. Tipik olarak sıfır hipotezi statükoyu
temsil eder, yani değişmesi için “ezici şekilde aksi yönde veri olması gereken
şey” budur. Öyle değil mi? Eğer etkisiz bir katkı maddesine evet dersek, ve
ileride öyle olmadığı belli olursa bunun şirket için çok negatif etkileri olacaktır,
aynen masum bir kişiyi yanlışlıkla hapse atmış olmak gibi. O yüzden kalmak
istediğimiz güvenli konum H0 ’i temsil etmelidir.
Bu noktada problemi rasgele değişkenlerin terminolojisi üzerinden tekrar tanımlamak
faydalı olur. Diyelim ki test sırasında 30 tane aldığımız ölçüm y1 , .., yn , her yi
normal olarak dağılmış ve bu dağılımların µ’şu aynı, ve µ’u birazdan “eski”

7
ölçümlerin ortalaması olarak alacağız, çünkü çürütmek istediğimiz hipotez bu.
Ayrıca daha önceki tecrübelerimiz gösteriyor ki σ = 2.4. Yani,

1 1 y−µ 2
fY (y; µ) = √ e− 2 ( 2.4 ) , −∞ < y < ∞
2π(2.4)

Hipotezleri şöyle tanımlayalım,


H0 : µ = 25.0 (Katkı maddesi etkili değildir)
H0 : µ > 25.0 (Katkı maddesi etkilidir)
Şimdi yeni dağılımı standardize edip, bir hayali ortalama eşik değeri üzerinden
bir sonuç çıkartalım, standardize etmek için kullandığımız µ = 25.0 çünkü eski
ortalama bu. Şimdi diyelim ki test ettiğimiz eşik değer 25.25 (esas amaç 26.3 ama
oraya geleceğiz), aradığımız olasılık,

P(Ȳ > 25.25)

Üstteki ifade “eğer örneklem eski dağılımdan geliyor olsaydı, 25.25 eşik değerini
geçmesi ne kadar mümkün olabilirdi” diye bir soru soruyor. Ȳ’yi standardize
edelim, o sırada eşitsizliğin sağ tarafı da değişir,

Ȳ − 25.0 25.25 − 25.0


P( √ > √ )
2.4/ 30 2.4/ 30

P(Z > 0.57)

z-Skoru tablosunu kullanakarak bu hesabı yapmak için

1 − P(Z < 0.57)

0.57’nin z-skoru (satır 0.5 kolon .07) 0.7157 olarak gösterilmiş, o zaman 1-0.7157
= 0.2843. Kod ile

print 1-norm.cdf(0.57)

0.284338849046

Demek ki

P(Z > 0.57) = 0.2843

Demek ki yeni deney sonuçlarının, eski dağılıma göre, eşik değerinden fazla
gelmesi hala az da muhtemel, demek ki eski hipotezi tam çürütemedik. Seçtiğimiz
eşik değeri bize kesin bir sonuç sağlamadı, sezgisel olarak bu olasılığın büyük

8
olduğunu görüyoruz. Mahkeme durumunda suçsuz olması çok muhtemeldir
diyemiyoruz. Ya da araba örneğinde (ve pozitif bağlamda) yeni yakıt kesinlikle
farklıdır / fazladır diyemiyoruz. Bize daha kesin noktalar lazım, aklımızda bize
“acaba?” dedittirecek eşik değerler istemiyoruz.

Hayali eşik noktası ȳ∗ ’nin daha büyük yapsak (ki o zaman ona bağlı olan sağdaki
olasılık küçülecek). Bu olur mu? Eğer ȳ∗ = 26.50 olsaydı?

Ȳ − 25.0 26.50 − 25.0


P( √ > √ )
2.4/ 30 2.4/ 30

P(Z > 3.42)

= 0.0003

Bu olasılık ise çok küçük, yani eşik değeri çok büyük! Çıtayı çok fazla kaldırdık,
mahkeme durumunda sanki diyoruz ki suçun 1000 tane tanığı lazım, sanık suçunu
itiraf etmiş olmalı, herşey apaçık olmalı, bir de herşeyi bizzat ben görmüş ol-
malıyım, yoksa kabul etmem. Araba örneğinde katkı maddesi arabaya Formula-1
yarısı kazandırmazsa biz bu yakıtı daha iyi olarak kabul etmeyiz diyoruz.

9
Peki eğer 0.28 çok fazla, 0.0003 çok küçük ise hangi olasılık en iyi eşik değerini
verir? Bu soruya kesin olarak ve matematiksel bir cevap vermek mümkün değil,
fakat hipotez test etme tekniğini kullanan araştırmacıların ulaştığı konsensüs 0.05
olasılık seviyesinin en iyi sonuçlar verdiğidir. Bu durumda sıfır hipotezinin çok
kolayca kenara atılmaması, ya da ona gereğinden fazla bağlı kalınmaması mümkün
oluyor.
O zaman 0.05 olasılığını verdirtecek eşik değeri hesaplayalım,

Ȳ − 25.0 ȳ∗ − 25.0


P( √ > √ ) = 0.05
2.4/ 30 2.4/ 30

ȳ∗ − 25.0
P(Z > √ ) = 0.05
2.4/ 30
ya da

ȳ∗ − 25.0
P(Z 6 √ ) = 0.95
2.4/ 30

z-Skor tablosuna bakıyoruz, “hangi z değeri 0.95 değeri sonucunu verir”, kordi-
natlardan 1.64 z-skorunu buluyoruz. Ya da

print norm.ppf(0.95)

1.64485362695

P(Z 6 1.64) = 0.95


O zaman

ȳ∗ − 25.0
√ = 1.64
2.4/ 30

ve buradan ȳ∗ = 25.178 sonucu çıkıyor. 26.3 değeri bu değerden yüksektir de-
mek ki sıfır hipotezi çürütülmüştür. Yeni yakıt katkısının performansı arttırıyor
olması büyük bir olasılıktır.
Not: Bu testi aslında daha basit şekilde ȳ∗ = 26.3 değerini vererek elde edilen
değeri 0.05’ten küçük olup olmadığına bakarak ta yapabilirdik. Fakat metotu
inşa ediyorduk o sebeple daha fazla örnekli anlatmak gerekti.
Örnek
SAT-I testinde ülke averajına oldukça yakın sonuçlar alan bir lisede yeni bir müfredat
denenmesine karar veriliyor. Deneme için 86 öğrenci rasgele şekilde seçiliyor ve
yeni bir tür cebir ve geometri dersine sokuluyor. Sonraki SAT-1 testinde sonuçlarına

10
göre bu çocuklar ortalama 502 sonuç almışlar, ülke çapındaki ortalama 494, stan-
dart sapma 124. α = 0.05 önemliliği (significance) seviyesinde yeni müfredatın
başarılı olduğu iddia edilebilir mi?
İlk önce µ parametresinin yeni müfredatın gerçek ortalaması olduğunu farzediy-
oruz. O zaman statüko nedir? Bu ortalamanın ülke ortalaması seviyesinde kalmasıdır,
yani µ0 = 494 olmasıdır. Fakat bu sefer alternatif hipotez iki yönlü (two-sided)
olmalı çünkü yeni müfredat, hiç istenmese de, test sonuçlarında negatif sonuca
da yol açabilir! O zaman H0 ’i reddetmeliyiz eğer z istatistiği 6 −z0.025 ise (yani
-1.96’dan küçük ise), ya da > z0.025 (yani 1.96’dan büyük ise).

502 − 494
z= √ = 0.60
124 86

Sonuç 1.96’dan büyük değil. O zaman H0 ’i, yani statükoyu değiştiremedik. Elde
edilen sonuçlar bir ilerlemedir fakat bu ilerlemenin şans eseri olması da muhtemel.

Binom Hipotez Testleri


Örnek
Erteleme Teorisi: Yaygın bir inanışa göre insanlar ölüm tarihlerini onlar için önemli
bir gün sonrasına erteleyebiliyorlar, mesela kendi doğum günleri, aile toplantıları,
bir akrabanın dönüşünü beklemek, vs. gibi Hatta ülke çapında seçimlerin bile
ölüm günlerini etkilediği görülmüştür, başkanlık seçimleri olan Eylül ve Ekim
ayları sırasında ölüm oranlarının düştüğü saptanmıştır. Bu teoriye göre pek çok
yaşlı insan kimin kazandığını görmek için “biraz daha dayanıyor”.
Bir araştırma bu teorinin doğru olup olmadığını kontrol etti. Bu bağlamda Salt
Lake City şehrindeki bir gazetenin ölüm ilanı kısmına bakıldı ve 747 kişi içinden
sadece 60 kişinin, daha doğrusu %8’inin kendi doğumgünlerinin 3 ay öncesi
içinde olduğunu saptadı. Eğer insanların ölümü rasgele olsaydı yaklaşık olarak
%25’inin bu periyod içinde ölmesini beklerdiniz. O zaman bu %25’den %8’e
düşüşü nasıl açıklamalıyız? Araştırma teoriyi destekleyecek rakamları veriyor
mu?
Diyelim ki 747 ölüm iki kategori üzerinden temsil edilsin, doğumgünü öncesindeki
3 ay içinde ölenler ve ölmeyenler. ki = 1 ile i’inci kişinin 1. kategoriye, ki = 0 ise

11
2. kategoriye ait olmasını temsil ediyoruz. O zaman k = k1 + k2 + .. + k747 bir-
inci kategorideki toplam ölümü temsil ediyor. Üstteki her k doğal olarak Binom
dağılımı, ve p parametresini kullanıyor ki

p = P(sahıs doğumgünü öncesindeki 3 ay içinde ölüyor)

Eğer insanlar ölümlerini ertelemeseydi p = 3/12 = 0.25 olurdu. Eğer erteliyorlar


ise p 0.25’den daha küçük olmalı. Bu azalmanın ne kadar önemli (significant)
olduğunu irdelemek için tek taraflı bir Binom Testi uygulamak lazım.
H0 : p = 0.25
H1 : p < 0.25
Test için p0 olduğunu farzettiğimiz “gerçek” dağılımı (ki statükoyu onun üzerinden
temsil edeceğiz) kullanacağız.

k − np0
z= p 6 −z0.05 = −1.64
np0 (1 − p0 )

60 − 747(0.25)
= = −10.7 6 −1.64
747(0.25)(0.75)

Test istatistiği kritik değerin aşırı derecede sol tarafına düştü. Demek ki ezici
miktarda kanıt, veri, sonuç elde ettik, %25’ten %8’e düşüşün pür şans dışında
başka bir sebebi var. Tabii bu sebep Erteleme Teorisi haricinde bir şey de olabilir,
fakat yine de ortaya çıkan kalıp bize ölüm vaktimizin kontrolümüzde olduğunu
destekleyen yönde bir sonuç veriyor.
Not: Üstteki test “büyük örneklem” olduğu durumlarda geçerlidir. Küçük örneklem
durumunda Binom dağılımının kendisi test için kullanılabilir.
Tek Örneklem t Testi (The One-Sample t test)
Bu test verinin bir N(µ, σ) Normal dağılımından geldiğini farzeder, test etmek
istediğimiz hipotez / karşılaştırma µ = µ0 . Ayrıca σ bilinmiyor, ki Öğrenci t
dağılımından bahsetmemizin ana sebebi buydu zaten, o zaman hipotez testine
Tek Örneklem t Testi adı verilir.
Örnek
Alttaki veride bir grup hanımın ne kadar kalori tükettiği kayıtlanmış. Acaba bu
hanımların aldığı enerji tavsiye edilen 7725’ten ne kadar sapmıştır?

daily_intake = np.array([5260.,5470.,5640.,6180.,6390.,6515.,6805.,\
7515.,7515.,8230.,8770.])

ȳ−µ
Örneklem küçük. O sebeple t dağılımı kullanmak mantıklı. t değerini s/ √ o olarak
n
hesaplayacağız, ki µ0 = 7725 olacak.

12
from scipy.stats.distributions import t
import pandas as pd, math
data = pd.DataFrame(daily_intake)
n = len(data)
df = n-1 # serbestlik derecesi
mu0 = 7725.
ybar = float(data.mean())
s = float(data.std())
print 'ortalama',ybar,'std',s
tval = (ybar-mu0)/(s/np.sqrt(n))
print 'df',df,'tval',tval
print 'sol',t.ppf(0.025,df)
print 'sag',t.ppf(0.975,df)
ortalama 6753.63636364 std 1142.12322214
df 10 tval -2.82075406083
sol -2.22813885196
sag 2.22813885196

Sol ve sağ eşik değerlerini hesapladık ve t değeri bu aralığın içine düşmüyor. Yani
hipotezi reddediyoruz. Bazıları bu problemde p değeri görmek isteyebilir,

print 't degeri', tval


print 'iki tarafli p degeri', 2*t.cdf(tval,df)
t degeri -2.82075406083
iki tarafli p degeri 0.0181372351761

p değeri hesapladık 0.05’ten küçük çıktı. İkiyle çarpmamızın sebebi iki-taraflı


p-testi yapmış olmamız, yani kabul edilebilir bölgenin hem solundan hem de
sağından ne kadar dışına düşüyorsak, bu iki taraftaki p değerini birbirine topla-
malıyız. Tabii t dağılımı simetrik olduğu için her iki taraftan da aynı şekilde
dışarıda kalıyoruz. Bazı kaynaklar iki taraflı p testinin |t| < −tesik,derece karşılaştırmasını
yaptığını söyler.
Benzer bir hesabı kütüphane çağrısı ile yaparsak,

from scipy.stats import ttest_1samp


t_statistic, p_value = ttest_1samp(daily_intake, mu0)
print 't', t_statistic, 'one-sample t-test', p_value
t -2.82075406083 one-sample t-test 0.0181372351761

Sonuç p değeri 0.05’ten küçük çıktı yani yüzde 5 önemliliğini (significance) baz
aldık bu durumda veri hipotezden önemli derecede (significantly) uzakta. De-
mek ki ortalamanın 7725 olduğu hipotezini reddetmemiz gerekiyor.
İki Örneklemli Test
Gruplar 0/1 değerleri ile işaretlendi, ve test etmek istediğimiz iki grubun ortala-
masının (mean) aynı olduğu hipotezini test etmek. t-test bu arada varyansın aynı
olduğunu farzeder.

energ = np.array([
[9.21, 0],[7.53, 1],

13
[7.48, 1],[8.08, 1],
[8.09, 1],[10.15, 1],
[8.40, 1],[10.88, 1],
[6.13, 1],[7.90, 1],
[11.51, 0],[12.79, 0],
[7.05, 1],[11.85, 0],
[9.97, 0],[7.48, 1],
[8.79, 0],[9.69, 0],
[9.68, 0],[7.58, 1],
[9.19, 0],[8.11, 1]])
group1 = energ[energ[:, 1] == 0][:, 0]
group2 = energ[energ[:, 1] == 1][:, 0]
t_statistic, p_value = ttest_ind(group1, group2)
print "two-sample t-test", p_value

two-sample t-test 0.00079899821117

p değeri < 0.05 yani iki grubun ortalaması aynı değildir. Aynı olduğu hipotezi
reddedildi.
Eşlemeli t-Test (Paired t-test)
Eşlemeli testler aynı deneysel birimin ölçümü alındığı zaman kullanılabilir, yani
ölçüm alınan aynı grupta, deney sonrası deneyin etki edip etmediği test edilebilir.
Bunun için aynı ölçüm deney sonrası bir daha alınır ve ”farkların ortalamasının
sıfır olduğu” hipotezi test edilebilir. Altta bir grup hastanın deney öncesi ve son-
rası ne kadar yiyecek tükettiği listelenmiş.

intake = np.array([
[5260, 3910],[5470, 4220],
[5640, 3885],[6180, 5160],
[6390, 5645],[6515, 4680],
[6805, 5265],[7515, 5975],
[7515, 6790],[8230, 6900],
[8770, 7335],
])
pre = intake[:, 0]
post = intake[:, 1]
t_statistic, p_value = ttest_1samp(post - pre, 0)
print "paired t-test", p_value

paired t-test 3.05902094293e-07

Wilcoxon işaretli-sıralı testi (Wilcoxon signed-rank test)


t Testleri Normal dağılıma göre sapmaları yakalamak açısından, özellikle büyük
örneklemler var ise, oldukça sağlamdır. Fakat bazen verinin Normal dağılımdan
geldiği faraziyesini yapmak istemeyebiliriz. Bu durumda dağılımdan bağımsız
metotlar daha uygundur, bu tür metotlar için verinin yerine çoğunlukla onun sıra
istatistiklerini (order statistics) kullanır.
Tek örneklemli Wilcoxon testi için prosedür µ0 ’i tüm veriden çıkartmak ve geri
kalan (farkları) işaretine bakmadan sayısal (numeric) değerine göre sıralamak, ve
bu sıra değerini bir kenara yazmak. Daha sonra geri dönüp bu sefer çıkartma

14
işlemi sonucunun işaretine bakmak, ve eksi işareti taşıyan sıra değerlerini topla-
mak, aynı işlemi artı işareti için yapmak, ve eksi toplamı artı toplamından çıkartmak.
Sonuçta elimize bir istatistik W gelecek. Bu test istatistiği aslında 1..n tane sayı
içinden herhangi birini 1/2 olasılığıyla seçmek, ve sonuçları toplamaya tekabül
etmektedir. Ve bu sonuç yine 0.05 ile karşılaştırılır.

from scipy.stats import wilcoxon, ttest_ind


daily_intake = np.array([5260,5470,5640,6180,6390,6515,6805,7515,7515,8230,8770])
z_statistic, p_value = wilcoxon(daily_intake - 7725)
print "one-sample wilcoxon-test", p_value
one-sample wilcoxon-test 0.0279991628713

Hipotezi reddettik.
Eşlemeli t-testi şimdi Wilcoxon testi ile yapalım,

z_statistic, p_value = wilcoxon(post - pre)


print "paired wilcoxon-test", p_value
paired wilcoxon-test 0.00463608893545

Normallik Testi
Paket scipy.stats altında normallik testleri için bazı çağrılar var, bu tekniklerden
ikisini altta gösteriyoruz,

import scipy.stats as st
arr = np.array([3,4,3,10,10,444,444,3,98])
arr2 = np.array([np.random.normal() for i in range(100)])

print 'D-Agostino and Pearsons'


print st.normaltest(arr)
print st.normaltest(arr2)
print
print 'Shapiro-Wilk'
print st.shapiro(arr)
print st.shapiro(arr2)
D-Agostino and Pearsons
(4.6919700569024814, 0.095752836393526289)
(1.4265636263795889, 0.49003335773235424)

Shapiro-Wilk
(0.6167718172073364, 0.00015052134403958917)
(0.9891485571861267, 0.5962899923324585)

Sonuçlara göre Shapiro-Wilk yaklaşımı daha güvenilir gözüküyor, zaten [6, sf


53]’e göre örneklem sayısı 6 50 olduğu durumlarda bu test tercih edilmelidir.
Biraz Matematik
Diyelim ki Gaussian dağılımına sahip olduğunu düşündüğümüz {xi } verilerimiz
var. Bu verilerin Gaussian dağılımına uyup uymadığını nasıl kontrol edeceğiz?
Normal bir dağılımı her veri noktası için şöyle temsil edebiliriz,

15
 
xi − µ
yi = Φ
σ

Burada Φ standart Gaussian’ı temsil ediyor (detaylar için [7] ve CDF fonksiy-
onuna tekabül ediyor. CDF fonksiyonunun aynı zamanda yüzdelik dilimi (quan-
tile) hesapladığı söylenir, aslında CDF son derece detaylı bir olasılık değeri verir
fakat evet, dolaylı yoldan noktanın hangi çeyrek içine düştüğü de görülecektir.
Şimdi bir numara yapalım, iki tarafa ters Gaussian formülünü uygulayalım, yani
Φ−1 .
  
−1 xi − µ
−1
Φ (yi ) = Φ Φ
σ

xi − µ
Φ−1 (yi ) =
σ

xi = Φ−1 (yi )σ + µ

Bu demektir ki elimizdeki verileri Φ−1 (yi ) bazında grafiklersek, bu noktalar eğimi


σ, kesisi (intercept, y ekseninin kesildiği yer) µ olan bir düz çizgi olmalıdır. Eğer
kabaca noktalar düz çizgi oluşturmuyorsa, verimizin Gaussian dağılıma sahip
olmadığına karar verebiliriz.
Üstte tarif edilen grafik, olasılık grafiği (probabılıty plot) olarak bilinir.
Ters Gaussian teorik fonksiyonunu burada vermeyeceğiz, Scipy scipy.stats.ınvgauss
hesaplar için kullanılabilir. Fakat yi ’nin kendisi nereden geliyor? Eğer yi , CDF’in
bir sonucu ise, pür veriye bakarak bir CDF değeri de hesaplayabilmemiz gerekir.
Bunu yapmak için bir başka numara lazım.
1. Eldeki sayıları artan şekilde sıralayın
2. Her veri noktasına bir derece (rank) atayın (sıralama sonrası hangi seviyede
olduğu yeterli, 1’den başlayarak).
3. Çeyrek değeri yi bu sıra / n + 1, n eldeki verinin büyüklüğü.
Bu teknik niye işliyor? x’in CDF’i xi < x şartına uyan xi ’lerin oranı değil midir?
Yani bir sıralama söz konusu ve üstteki teknik te bu sıralamayı biz elle yapmış
olduk, ve bu sıralamadan gereken bilgiyi aldık.
Basit bir Gaussian kontrolü, qqplot kullanarak.

import statsmodels.api as sm
fig = sm.qqplot(arr)
plt.savefig('stat_tests_01.png')

16
Gerçekten Gaussian olan bir veri şöyle gözükür,

fig = sm.qqplot(arr2)
plt.savefig('stat_tests_02.png')

Kaynaklar
[1] Dalgaard, Introductory Statistics with R
[2] Kerns, Introduction to Probability and Statistics Using R
[3] Blondel, t-test and wilcoxon-test examples in Python, urlhttps://gist.github.com/mblondel/17617
[4] Runger, Applied Statistics and Probability for Engineers
[5] Stack Exchange, Sample variance converge almost surely, http://math.stackexchange.
com/questions/243348/sample-variance-converge-almost-surely
[6] Haslwanter, Introduction to Statistics using Python
[7] Bayramli, İstatistik, Giris)
[8] Bayramli, Istatistik, Örneklem Büyüklüğü

17
Testlere Devam
İstatistiki test yaratmak için takip edilen teknik basit; bir istatistiki ölçüt hesaplıyoruz,
ya da hesabımızın başka noktasından çıkanı alıyoruz, ki bu ölçüt mesela bir or-
talama olabilir bu durumda bilinen bir dağılımı vardır, ya da lineer regresyon-
dan bize verilen bir katsayıdır, onun t değeri vardır, bu durumda da dağılımın
ne olduğunu biliyoruz. Yani hangi ölçüte bakarsak bakalım, ya da biz yeni bir
tanesini uyduralım, önce elde ettiğimiz rasgele değişkeninin ideal koşullarda
dağılımının ne olduğuna bakarız, ki test ettiğimiz bir anlamda bu ideal koşullar
olacaktır. Ardından bir kriter ortaya koyarak testi ortaya çıkartırız.
Ama ondan önce biraz regresyon.
Örnek veri olarak Big Andy’s Burger Barn adında hamburger satan bir restoran
zincirinin verisini kullanalım [1, sf. 168]. Veride her nokta ayrı bir şehirdeki belli
bir aydaki dükkan için kaydedilmiş reklam gideri ADVERT , burger fiyatı PRICE,
ve satış getirisi SALES (SALES ve ADVERT bin dolarlık birimde kaydedilmiş).
Şirket yönetimi diyelim ki reklam harcamalarının satışları nasıl etkilediğini merak
ediyor. Ayrıca yönetim bir fiyatlama stratejisi belirlemek istiyor, fiyatın geliri
nasıl etkilmektedir? Fiyatta düşüş çok az satış artışı yaratıyorsa bu durum kazancı
düşürür, demek ki talep fiyatsal-elastik değildir (price inelastic). Tam tersi de ola-
bilir, fiyat değişimi satışı arttırır, o zaman talep fiyatsal-elastiktir.

import pandas as pd
df = pd.read_csv('andy.dat',sep='\s*',names=['sales','price','advert'])
print df.head(3)

sales price advert


0 73.2 5.69 1.3
1 71.8 6.49 2.9
2 62.4 5.63 0.8

Regresyon modelini kuralım,

SALES = β1 + β2 PRICE + β3 ADVERT

import statsmodels.formula.api as smf


results = smf.ols('sales ˜ price + advert', data=df).fit()
print results.summary()

OLS Regression Results


==============================================================================
Dep. Variable: sales R-squared: 0.448
Model: OLS Adj. R-squared: 0.433
Method: Least Squares F-statistic: 29.25
Date: Mon, 24 Aug 2015 Prob (F-statistic): 5.04e-10
Time: 08:59:52 Log-Likelihood: -223.87
No. Observations: 75 AIC: 453.7
Df Residuals: 72 BIC: 460.7
Df Model: 2
Covariance Type: nonrobust

1
==============================================================================
coef std err t P>|t| [95.0% Conf. Int.]
------------------------------------------------------------------------------
Intercept 118.9136 6.352 18.722 0.000 106.252 131.575
price -7.9079 1.096 -7.215 0.000 -10.093 -5.723
advert 1.8626 0.683 2.726 0.008 0.501 3.225
==============================================================================
Omnibus: 0.535 Durbin-Watson: 2.183
Prob(Omnibus): 0.765 Jarque-Bera (JB): 0.159
Skew: -0.072 Prob(JB): 0.924
Kurtosis: 3.174 Cond. No. 69.5
==============================================================================

Fiyatsal elastikliği kontrol etmek için β2 ’nin t değerine bakabiliriz çünkü bu değer
β2 = 0 hipotezini reddedip reddedemeyeceğimiz hakkında bize bir şeyler söylüyor.
Eğer t değer ve P>|t| değeri 0.05’ten küçük ise hipotezi reddedebiliriz. Çıktıya
bakıyoruz, 0 değerini görüyoruz. Demek ki fiyatsal elastiklik vardır.
Gayrı Lineerlik: Fakat acaba reklam harcaması ile satış arasında tam lineer bir
ilişki mi var? Belli bir noktadan sonra ne kadar harcarsak harcayalım daha fa-
zla kazanamayacağımız bir durum da olamaz mı? Bunu test edelim, ADVERT 2
değişkenini ekleyip yeni bir regresyon yaratalım. ADVERT ’in karesini aldık çünkü
karesi alınmış ADVERT normal olana göre daha hızlı büyür, yani büyük değerlerde
karesinin sonucu çok daha büyüktür, ve eğer bu uç noktalarda bir kalıp var ise,
onu “yakalamak” bu karesi alınmış yeni değişken sayesinde mümkün olur.

import statsmodels.formula.api as smf


df['advert2'] = df.advert**2 # kare aldik
results2 = smf.ols('sales ˜ price + advert + advert2', data=df).fit()
print results2.summary()

OLS Regression Results


==============================================================================
Dep. Variable: sales R-squared: 0.508
Model: OLS Adj. R-squared: 0.487
Method: Least Squares F-statistic: 24.46
Date: Mon, 24 Aug 2015 Prob (F-statistic): 5.60e-11
Time: 15:54:13 Log-Likelihood: -219.55
No. Observations: 75 AIC: 447.1
Df Residuals: 71 BIC: 456.4
Df Model: 3
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [95.0% Conf. Int.]
------------------------------------------------------------------------------
Intercept 109.7190 6.799 16.137 0.000 96.162 123.276
price -7.6400 1.046 -7.304 0.000 -9.726 -5.554
advert 12.1512 3.556 3.417 0.001 5.060 19.242
advert2 -2.7680 0.941 -2.943 0.004 -4.644 -0.892
==============================================================================
Omnibus: 1.004 Durbin-Watson: 2.043
Prob(Omnibus): 0.605 Jarque-Bera (JB): 0.455
Skew: -0.088 Prob(JB): 0.797
Kurtosis: 3.339 Cond. No. 101.

2
==============================================================================

Yeni regresyon için R2 = 0.50! Bu yeni model verideki varyansın yüzde 50’sini
açıklıyor! Eskisinden daha iyi bir model ve AIC’i de daha düşük zaten, ve ADVERT 2
için hesaplanan katsayı -2.768 eksi değeri taşıyor. Demek ki reklam harcamalarının
belli bir noktadan sonra etkisinin aynı olmayacağı varsayımımız doğru.
Birleşik Hipotez Testleri
Ne yazık ki t testi ile ortak (joint) hipotez testleri yapamıyoruz. Mesela sadece bir
değil, birkaç değişkenin model için ne kadar önemli olduğunu bilmek istiyoruz.
Tabii bu değişkenleri regresyondan atabiliriz, sonra çıplak gözle AIC’e bakarız,
vs. Fakat bu testi daha İstatistiksel bir hipotez testi olarak yapmak daha iyi olmaz
mıydı? Alttaki test bu durumlar için kullanılır,
F Testi
Diyelim ki reklam harcamasının satışı etkileyip etkilemediğini merak ediyoruz.
Fakat artık bir değil iki tane reklam ile alakalı değişkenimiz var! Biri ADVERT
diğeri onun karesi ADVERT 2 . Sıfır hipotezimiz şu olacak, “reklam harcaması
satışları belirlemede etkili değildir”. Yani

H0 : β3 = 0, β4 = 0

H1 : β3 6= 0, ya da β4 6= 0 ya da ikisi de sıfır değil

Hipotez bu şekilde tanımlanınca onu reddetmek demek reklamın satışları etk-


ilediği hakkında güçlü bir kanıt ortaya koyar. Bu nokta önemli, aşırı fantastik bir
şekilde zaten umduğumuz şeyi desteklemek için kanıt aramak yerine, onun tam
tersini reddetmek için kanıt arıyoruz.
Peki bu testi nasıl yaratacağız? Bir regresyona değişken eklemek onun hatasını
azaltır, çıkartmak ise çoğaltır. Eğer ana regresyondan değişken çıkartırsak onun
hatası SSEu diyelim, çoğalarak SSEr olur. Notasyonel açıdan değişik bir şekilde
de duruma bakabiliriz, β3 = 0, β4 = 0 şartını koşmak aslında bir modeli kısıtlamak
ta (restrict) anlamına gelir, üzerinde şart belirlenmemiş olan model de kısıtlanmamış
(unrestricted) olur. Neyse, F testi ile yapmaya çalışacağımız bu çoğalmanın is-
tatistiki olarak önemli (significant) olup olmadığını anlamaktır. SSE notasyonu
bu arada hata karelerinin toplamı (sum of squared errors) kelimelerinden geliyor.
Şimdi, daha önce belirttiğimiz gibi, ideal şartlarda doğru olacak bir ölçüt yarat-
mak, ve bu ideal şartlarda bu ölçütün dağılımını bulmak, ve veriyi kullanıp bu
ölçütü hesaplayıp sonucu bu dağılıma “sormak” gerekiyor. Eğer sıfır hipotezi
doğru ise,

(SSEr − SSEu )/j


F=
SSEu /(n − k)

3
hesabı bir Fj,n−k dağılımıdır. F dağılımının tanımını hatırlayalım, iki chi kare
dağılımının birbiriyle bölünmüş hali idi,

χ2 /j
Fj,n−k = 2
χ /n − k

SSE hesapları karelerin toplamı olduğu için ve hataların normal dağıldığı varsayımından
hareketle bölüm ve bölendeki rasgele değişkenler Chi kare dağılımına sahiptir.
Peki neden üstteki F dağılımının j, n − k derece serbestliği vardır? İki chi kare
dağılımını toplayınca onların dereceleri toplanır. Aynı şekilde çıkartma derece
eksiltir. Şimdi, SSEr ’nin derecesi n − k’dir, k tane katsayı dereceyi / serbestliği
azaltmıştır. Eğer SSEr elde etmek için j tane katsayıyı çıkartırsak, bu durum
dereceyi fazlalaştırır, yani SSEr için n − k + j elde ederiz. O zaman bölümdeki
çıkartmanın derecesi

(n − r + j) − (n − r) = j

olacaktır. Şimdi nihai hesabı yapalım, regresyonu reklamla alakalı iki değişkeni
çıkartılmış şekilde bir daha işletiriz, sonra SSE hesabı için her iki regresyondan
gelen artıklar resid’leri kullanırız, onların karelerinin toplamı bize gerekli SSE
hesabını verecektir,

import statsmodels.formula.api as smf


results3 = smf.ols('sales ˜ price ', data=df).fit()
SSE_u = np.sum(results2.resid**2)
SSE_r = np.sum(results3.resid**2)
print 'SSE_u', SSE_u
print 'SSE_r', SSE_r
J = 2; N=len(df); K = len(results2.params)
F = (SSE_r - SSE_u)/J / SSE_u*(N-K)
print 'j,n-k',J,N-K
print 'F =', F
SSE_u 1532.0844587
SSE_r 1896.39083709
j,n-k 2 71
F = 8.44135997807

p değeri P(Fj,n−k > 8.44). Kumulatif yoğunluk fonksiyonu (CDF) kullanabilmek


için formülü şu şekilde tekrar yazalım, 1 − P(Fj,n−k < 8.44),

import scipy.stats as st
f = st.f(J,N-K)
print 1-f.cdf(F)
0.000514159058424

Üstteki değer 0.05 kritik değerinden daha ufak olduğu için hipotez reddedilmiştir.
Direk p değeri hesabı yerine yüzde 95 güven için bir eşik değeri de hesaplaya-
bilirdik,

4
print f.ppf(0.95)

3.12576423681

Ve eğer F değeri bu değerden büyük ise hipotez reddedilmiştir diyebilirdik, ki


hesapladığımız F değeri eşik değerinden büyük idi. Vardığımız sonuç reklam
harcamalarının satış için önemli olduğudur.
Daha Basit bir F-Test Örneği
F-Test’in ana fonksiyonu ve ilk kullanımı varyans karşılaştırmak aslında, iki ölçüm
grubunu standard sapma karesinin oranı alınır, ve sonuç bir F rasgele değişkenidir,
belli serbestlik dereceleri vardır,

S2x
F=
S2y

ki Sx , Sy 1. ve 2. grubun örneklem standart sapmasıdır. Bu şekilde bir örnek


te görelim [2, sf. 42]. Diyelim ki elimizde göz hareketlerini ölçen iki metod var,
gözümüzü 20 derece hareket ettirince metotlar şu rakamları veriyor,

method_1 = [20.7, 20.3,20.3, 20.3, 20.7, 19.9, 19.9, 19.9, \


20.3, 20.3, 19.7, 20.3]
method_2 = [19.7, 19.4, 20.1, 18.6, 18.8, 20.2, 18.7, 19.]

F-testini kullanarak bu metotların, ölçümlerin doğruluğunun (accuracy) aynı mı,


yoksa birinin diğerinden daha doğru mu olduğunu bulacağız.

import pandas as pd
m1 = np.array(method_1); m2 = np.array(method_2)
df = pd.DataFrame([m1,m2]).T
ss = df.std()
F = ss.ix[0]**2/ss.ix[1]**2
print F

0.243934673841

import scipy.stats as st
f = st.f(len(m1)-1,len(m2)-1)
print 1-f.cdf(F)

0.981334830069

F dağılımı n − 1 ve m − 1 serbestlik derecesine sahip. Üstteki p değeri 0.05’ten


küçük değildir, demek ki iki metotun ölçüm doğruluğunun aynı olduğu hipotezini
reddedemiyoruz. Not: Örneklem standart sapma hesabı için n − 1’e bölünme du-
rumu var, bu bölüm kullanılan F’in derecesine yansıyor tabii.
Testin özünde şu var, ki varyansın eşitsizliği oranın 1’den ne kadar uzak olduğuna
bağlı. Ama ne kadar uzak istatistiki olarak önemli bir uzaklık? İşte bunun cevabını
F-dağılımı veriyor.

5
Örneklem Korelasyonu
Korelasyon ρ’yu daha önce gördük, tahmin edicisi r’dir,

Sxy
ρ̂ = r = p (1)
Sxx Syy

ki örneklem hesapları Sxx , Sxy , Syy

X
n
Sxx = (xi − x̄)2
i=1

X
n
Sxy = (xi − x̄)(yi − ȳ)
i=1

X
n
Syy = (yi − ȳ)2
i=1

olsun; bu hesapların teorik varyans ile olan bağlantısı görülebilir. Eğer X, Y iki
değişkenli (bivariate) bir normal dağılımından geliyorsa, o zaman ortada bir re-
gresyon varmış gibi gösterebiliriz

E(Y|X = x) = β0 + β1 x + 

ki β1 = σY /σX · ρ olur. Detaylar için [4]. Soru şu, r için bir istatistiksel önemlilik
(significance) hesabı nasıl yapardık? Yani, eğer −1 6 r 6 1 işe, ve r = 0 hiç
korelasyon olmama durumu ise, acaba bu “sıfır olmama” durumunu test ede-
bilir miydim? Evet. Yukarıdaki normallik faraziyesi doğru ise β1 = 0 olmama
durumunu test etmek ρ = 0 olmama testi ile aynı, bu durumda

β̂1
t0 = q
Var(β̂1 )

gibi bir test istatistiği yaratırız, ki bu istatistik Öğrenci t dağılımına sahip olurdu
çünkü sıfır hipotezi β̂1 = 0, ve üstteki istatistik sıfır hipotezi altında ile Öğrenci
t dağılımına sahip olmak zorundadır, çünkü bölünen normal dağılmış, bölen chi
karenin karekökü olarak dağılmış. Eğer to hesabı veriye uygulandıktan sonra
hipotezin öngördüğü dağılıma uymaz ise, sıfır hipotezini reddederiz.
Bu noktada lineer regresyon ile alakalı bilgiler devreye sokulabilir, [4]’den biliy-
oruz ki

6
σ2
Var(β̂1 ) =
Sxx

σ yerine örneklemden gelen S kullanırsak ve üstteki formüle koyarsak,

β̂1
t0 = p
S/Sxx

Buqifadeyi r bazında ifade edebilir miyiz? Deneyelim, β̂1 = Sxy /Sxx ve r =


β̂1 SSyy
xx
olduğunu biliyoruz [4], ayrıca

SSE
S= , SSE = Syy − β̂1 Sxy
n−2

ki SSE hata karelerinin toplamıdır (sum of squared errors),

√ √
Sxx β̂1 n − 2
t0 = √
SSE
√ √
Sxx β̂1 n − 2
= q
Syy − β̂1 Sxy
p
Bölümün iki kısmını Sy ile bölelim,

p √
Sxx /Syy β̂1 n − 2
= q
1 − β̂1 Sxy /Syy

Bölünen kısmında bir r ortaya çıktı,


r n−2
=q
1 − β̂1 Sxy /Syy

Bölen kısmındaki β̂1 yerine β̂1 = Sxy /Sxx koyarsak yine (1)’deki r tanımına geli-
riz, ve alttaki basitleştirilmiş ifade ortaya çıkar,

s
(n − 2)r2
to =
(1 − r2 )

Bu istatistik n − 2 derece serbestliğe sahip bir Öğrenci t dağılımıdır.


Örnek

7
Possum adı verilen bir tür hayvanın dişilerinin tüm uzunluğu ve kafa ölçümü
totlngth,hdlngth değişkenleri arasında korelasyon olup olmadığı merak edilmek-
tedir.

import pandas as pd
import scipy.stats

def p_corr(df1, df2):


corr = df1.corr(df2)
N = np.sum(df1.notnull())
t = corr*np.sqrt((N-2)/(1-corr**2))
p = 1-scipy.stats.t.cdf(abs(t),N-2) # one-tailed
return corr, t, p

df = pd.read_csv('fossum.csv')
c,tval, pval = p_corr(df.totlngth,df.hdlngth)
print c, pval

0.779239322172 3.75045772216e-10

p-değeri çok küçük, demek ki korelason olmadığı tezi reddedildi. Korelasyon


var.
Pearson Chi Kare Uyum Derecesi (Goodness-of-Fit) Testi
Her sene günde kaç saat çalıştığımızı bir yere yazdık diyelim, elde 365 veri nok-
tası var. Ertesi sene yine aynı veriyi topladık, şu soruyu soruyoruz, iki veri bir-
birinden istatistiki olarak farklı mıdır? Ya da; elimizdeki belli bir veri var, ve
o verinin normal mi, ya da üstel (exponential) dağılımdan mı geldiğini merak
ediyoruz. Acaba veri istatistiki olarak hangi tip dağılım fonksiyona (yani teorik
yoğunluk fonksiyonuna) daha yakındır? Ya da; eldeki bir verinin µ = 0 merkezli
normal dağılımdan mı, yoksa µ = 30 merkezli normal dağılımdan mı geldiğini
merak ediyoruz.
Her üç sorunun ve benzerlerinin cevabı Pearson’un chi kare (chi square) uyum
derece testi ile verilebilir.
İki veriyi karşılaştırdığımız durumda bu iki veri kümesini dağılım olarak kabul
edip, birini diğerine uyum açısından test edebiliriz. Bu karşılaştırma her iki
tarafta histogram alınıp histogram kutucuklarının (bins) içine her iki tarafta düşen
miktarların bir test istatistiği üzerinden karşılaştırılması ile olabilir. Veri ile yoğunluk
karşılaştırdığımızda ise veriyi histogram kutucukları, yoğunluğu ise aynı aralıklara
düşen olasılıkların fonksiyonel hesaplarıyla karşılaştırılması ile yaparız.
Test istatistiği
Diyelim ki her kutucukta görülen miktar Ni , ki N1 + N2 + .. + Nk = n, ve
karşılaştırmak istediğimiz, bu miktara tekabül eden “ideal” olasılık pi , o zaman
ideal miktar npi . Kutucuktaki sayıları bir binom dağılımından geliyormuş gibi
modelleyebiliriz, 1. kutucuk için mesela N1 ∼ Bin(n, p1 ), ve N1 rasgele değişkeni
N tane deneyde “başarılı” olan sayı - tipik binom kullanımı. Bu durumda Pear-
son uyum derecesi istatistiği

8
X
k
(Nj − npj )2
2
χ =
j=1
npj

ile belirtilir, üstteki toplamın yaklaşıksal olarak χ2k−1 dağılımına yaklaştığı ispatlanmıştır.
Detaylar için [5, sf 318, 6]. Nihai ispat oldukça çetrefil, biz burada alternatif bazı
yaklaşıksal ispatlardan bahsetmek istiyoruz (okkalı ispat için yukarıdaki refer-
anslar geçerli tabii).
Eğer her Nj binom dağılımını Gaussian ile yaklaşıkladığımızı düşünürsek, ki bu
yeterince büyük n, ve npi > 5 için mümkün, bu dağılım µ = npj ve varyans
npj (1 − pj )’ye sahip olur, o zaman Gaussian’ı standardize etmek için

N − npj
p j ≈ N(0, 1)
npj (1 − pj )

Z = N(0, 1) diyelim,

(Nj − npj )
q
√ ≈ (1 − pj )Z
npj

İki tarafın karesini alalım, ve her j üzerinden toplam alalım,

X (Nj − npj )2 X
≈ (1 − pj )Z2
j
npj j

Üstteki eşitliğin sol tarafı Pearson istatistiğiyle aynı. Sağ tarafı neye eşit?

X
(1 − pj )Z2 = (1 − p1 )Z2 + (1 − p2 )Z2 + ... + (1 − pk )Z2
j

= Z2 [(1 − p1 ) + (1 − p2 ) + ... + (1 − pk )]

X
= Z2 [k − (p1 + p2 + .. + pk ))] = (k − 1)Z2 = Z2
k−1

Şimdi, bu eriştiğimiz toplamın χ2k−1 dağılımı, yani k−1 derece serbestliği olan bir
chi kare dağılımı olduğunu iddia edebilir miyiz? Eğer Zj ’ler birbirinden bağımsız
ise kesinlikle evet, çünkü standart normal rasgele değişkenlerin toplamı chi kare
dağılımını verir. Üstteki kolay ispatın önündeki tek engel budur, bizim burada
yapacağımız yaklaşıksal argüman i, j ikilisi için Z’lerin bağlantısının, kovaryansının
küçük olduğudur, ki bu küçüklük sebebiyle Zj ’ler çoğu durumda bağımsız kabul
edilebilir.

9
Diyelim ki X1 , X2 , .. değişkenleri ba
 ğımsız ve Mult(1,
 P p), yani multinom dağılımdan
geliyorlar [7, sf. 180], ve p = p1 p2 . . . , ve j pj = 1. Yani her Xi zar
attığında 1 × k boyutlu bir vektör ortaya çıkıyor, bu vektörün sadece bir hücresi 1
diğerleri 0. Multinom dağılımların tanımından biliyoruz ki Cov(Xi , Xj ) = −npi pj =
−pi pj (çünkü n = 1).
Bu demektir ki 1’den küçük iki değer çarpılıyor bu daha da küçük bir değer
verecektir. Eğer k yeterince büyük ise, bu, mesela sürekli yoğunlukları ayrıksal
olarak gösterdiğimiz durumda ve yeterince çok kutucuk var ise bu kutucuklara
“düşen” olasılıkların ufalması demektir, ve ufak değerlerin çarpımı iyice ufalır,
ki bu kovaryansı sıfıra yaklaştırır. Yani yeterince büyük k için i, j bağlantısını
sezgisel bağlamda etkisiz olduğunu görebiliriz. Tabii, toplamın kesinlikle chi kare
olduğunun ispatı için dediğimiz gibi verdiğimiz referanslara bakılabilir.
İstatistiki testlerin mantığını hatırlarsak, tarif edilen Pearson istatistiği sıfır hipotezi.
Bize reddetmeye uğraşacağımız bir dağılım / hesap ikilisi üretiyor. Eğer hesap
beklenen, normal (sıfır hipotez durumu) uymuyorsa, hipotezi reddediyoruz. Ret
durumu özellikle seçiliyor çünkü kabul edilmezlik daha kesin bir cevap.
Örnek
Bir paralı otoyolunda geçiş noktasında durulmuş ve her dakika gelen araç sayılmış,
ve dakika başına bu araç sayısı yazılmış. Bu deney 106 dakika süresince yapılmış
(elde 106 satırlı bir veri var yani). Bu veri için Poisson dağılımının uygun olup
olmadığını yüzde 5 önemlilik seviyesinde ispatlamamız isteniyor.

import pandas as pd
vehicle = [2, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6,\
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,\
7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9,
9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, \
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, \
12, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,\
15, 16, 16, 16, 16, 18]
df = pd.DataFrame(vehicle)

Verinin histogramına bakalım,

f = plt.figure(); df.hist(bins=13)
plt.savefig('stat_tests2_01.png')

10
Poisson dağılımı muhtemel gözüküyor. Ama şimdi bunu uyum derece testi ile
daha kararlı şekilde göstermeye uğraşacağız. Verideki sayımları o sayım rakamı
bazında gruplayalıp gösterelim,

kt = plt.hist(np.array(df),bins=range(20))
kt = pd.DataFrame([kt[1],kt[0]]).T
kt = kt[:-1] # sonuncu satiri at
kt.columns = ['kac araba','kac kere']
print (kt)
kac araba kac kere
0 0.0 0.0
1 1.0 0.0
2 2.0 1.0
3 3.0 3.0
4 4.0 5.0
5 5.0 7.0
6 6.0 13.0
7 7.0 12.0
8 8.0 8.0
9 9.0 9.0
10 10.0 13.0
11 11.0 10.0
12 12.0 5.0
13 13.0 6.0
14 14.0 4.0
15 15.0 5.0
16 16.0 4.0
17 17.0 0.0
18 18.0 1.0

Yani bir dakikada 6 araba sayımı 13 kere yapılmış (13 değişik dakikada). Not:
Üstte bir kütüphane çağrısı hist kullandık (grafikleme kısmını kullanmadan),
ama Poisson frekans hesabı elle çok kolay yapılabilir.
Eğer üstteki verinin bir Poisson dağılımdan geldiğini kabul ediyorsak, Poisson’un
parametresi λ’yi veriden hesaplamak için ortalama almak yeterlidir,

lam = np.mean(kt['kac kere'])


print ('lambda %0.2f' % lam)

11
lambda 5.58

Bu Poisson’u kullanarak bazı olasılık hesapları hemen yapabilirdik, mesela 3’ten


fazla, 9’dan fazla araba sayılma ihtimali nedir?

from scipy.stats import poisson


print (1-poisson.cdf(3, lam))
print (1-poisson.cdf(9, lam))
0.807087823822676
0.057975438622207665

Devam edelim. Veride bazı kutucukların boş olduğunu görüyoruz, bu durum


özellikle tek tepeli (unimodel) dağılımlı verilerde etekleri temsil eden uçlardaki
kutucukların boş olması sonucunu verebilir. Bu durumda o kutucukların verisi
daha dolu olanlara aktarabilmek için kutucuk noktalarını tekrar tanımlıyoruz,

bins = [0] + range(5,15) + [100]


kt2 = plt.hist(np.array(df),bins=bins)
kt2 = pd.DataFrame([kt2[1],kt2[0]]).T
kt2.columns = ['int_low','n_i']
print kt2
int_low n_i
0 0 9
1 5 7
2 6 13
3 7 12
4 8 8
5 9 9
6 10 13
7 11 10
8 12 5
9 13 6
10 14 14
11 100 NaN

Şimdi bu değerler üzerinden Pearson χ2 hesabını yapalım. Ama ondan önce,


hatırlayalım, bu verinin herhangi bir Poisson’dan gelip gelmediğini kontrol ediy-
oruz, ama testimiz için parametresi belli olan, özel bir Poisson lazım, bunun için
bize bir λ gerekiyor. Önemli değil, λ’nin tahmin edicisi λ̂’yi biliyoruz,

1X
n
λ̂ = xj
n j=1

Bu λ̂’yi kullanarak Poisson hesaplarını yapabiliriz artık. Bir kutucuğa düşen Pois-
son olasılığının hesabı P(a 6 X < b), ki bu basit bir F(b) − F(a), yani a, b nokta-
larındaki kümülatif yoğunluk fonksiyonun farkı üzerinden hesaplanabilir, altta
kullanılan çağrı poisson.cdf.

from scipy.stats import poisson


kt2['int_high'] = kt2.shift(-1).int_low

12
lam = df.mean() # tahmin edici
def f(x):
high = poisson.cdf(x.int_high-1,lam)
low = poisson.cdf(x.int_low-1,lam)
return pd.Series(high-low)
kt2['p_i'] = kt2.apply(f,axis=1)
kt2['np_i'] = len(df) * kt2['p_i']
kt2['chi'] = (kt2['n_i']-kt2['np_i'])**2 / kt2['np_i']
kt2 = kt2[:-1]
print kt2
print '\nchi kare istatistigi', kt2.chi.sum()

int_low n_i int_high p_i np_i chi


0 0 9 5 0.051863 5.497487 2.231492
1 5 7 6 0.058217 6.171048 0.111352
2 6 13 7 0.088242 9.353602 1.421508
3 7 12 8 0.114643 12.152118 0.001904
4 8 8 9 0.130325 13.814437 2.447271
5 9 9 10 0.131691 13.959242 1.761849
6 10 13 11 0.119764 12.695009 0.007327
7 11 10 12 0.099016 10.495702 0.023412
8 12 5 13 0.075040 7.954290 1.097248
9 13 6 14 0.052496 5.564539 0.034078
10 14 14 100 0.078703 8.342527 3.836608

chi kare istatistigi 12.9740502104

Şimdi üstteki değerin istatistiki önem taşıyıp taşımadığını anlamaya geldi sıra.
Eşik değerimiz χ29,0.05 olacak. Peki niye serbestlik derecesi 9 alındı? Elde kaç tane
kutucuk var?

print len(kt2), 'kutucuk'

11 kutucuk

11-1=0 niye olmadı, -1 ile serbestlik derecesi hesaplamıyor muyduk? Evet. Fakat
bir kavis daha var, tahmin edici ile λ’yi hesaplayınca 1 serbestlik derecesi daha
kaybettik! χ2 ile çalışırken hatırlanması gereken bilgilerden biri bu. Pearson
bu testi keşfettiğinde aslında bu eksiltmeye gerek görmüyordu, daha sonraları
Fisher adlı istatistikçi bunun gerekli olduğunu ispatladı.

from scipy.stats import chi2


dof = len(kt2)-1-1 # lambda tahmini 1 derece kaybettirdi
print 'serbestlik derecesi', dof
print 'chi kare', chi2.ppf(0.95,dof)

serbestlik derecesi 9
chi kare 16.9189776046

Hesaplanan değer üstteki değerden küçük olduğu için Poisson hipotezi kabul
edilmiştir (ya da olmadığı reddedilememiştir, eğer p-değeri hesaplasaydık, 0.05’den
az sonuca bakacaktık, aynı şey).
Örnek

13
Gördüğümüz gibi bir dağılım varlığlığını test için o dağılımın analitik yoğunluk
fonksiyonunu veriden gelen tahmin ediciler üzerinden tanımlayıp, veriyi bu fonksiyon
ile üretmeyi deneyebiliriz, ve bu sonuç ile veri arasında uyumluluğa bakabiliriz.
Mesela olayların coğrafi olarak dağılımına bakalım.. Bu tür olayları nasıl model-
leriz? Olaylar depremler, yangınlar, ya da bir savaşta bir alana atılan bombalar
olabilir, ve bu tür sayılar Poisson dağılımı ile modellenir. Bu dağılım ilk bölümde
gördüğümüz gibi,

λx
f(x) = P(X = x) = e−λ
x!

olay sayısı x = 1, x = 2, vs.. olacak şekilde, ki önceden tanımlı belli bir za-
man aralığında x tane olayın olma olasılığını bu yoğunluk veriyor. Coğrafi olay
sayılarını ölçmek için biraz farklı düşünmek gerekiyor, mesela 2’inci Dünya Savaşı
sırasında Almanların Londra’ya attıkları bombaları düşünelim, analizi [13]’te var;
Merak edilen şuydu, acaba bombalar belli bir yerde kümeleniyor muydu (cluster-
ing)? Cevap önemli olabilirdi, belki özel bir yer vurulmak isteniyordu? Analizde
olayların doğal oluş sayısını modelleyen Poisson varlığı ispatlanırsa, kümelenme
hipotezi reddedilmiş olacaktı. İstatistikçi Clarke Londra’yı 536 tane ızgaraya
böldü, ve her öğe içine düşen bombaları saydı. Bu bittikten sonra 1 tane bomba,
2 tane bomba, vs.. şeklinde olan hücrelerin sayısını aldı, ki yoğunluğa x ile
geçilecek olan bu sayıydı.
Sonra Clarke yoğunluğu λ tahmin edici hücre sayısı bölü bomba sayısı üzerinden
tanımladı, ve bu yoğunluktan tüm sayılar için bir tahmini bomba sayısı ürettirdi,
sonuçları gerçek bomba sayıları ile karşılaştırdı.

N = 576.
lam = 537/N
d = N*np.exp(-lam)
probs = [d*1, d*lam, d*lam**2/2, d*(lam**3)/(3*2), d*(lam**4)/(4*3*2)]
list(map(lambda x: np.round(x,2), probs))

Out[1]: [226.74, 211.39, 98.54, 30.62, 7.14]

Gerçek sayılar 229, 211, 93, 35, 7, .. idi, görüldüğü gibi oldukca yakın sayılar. Bir
adım daha atılıp bunun üzerinde bir istatistik testi uygulanınca Poisson varlığı,
ve dolaylı olarak kümelemenin olmadığı ispatlanmış oldu.
Kaynaklar
[1] Hill, Principles of Econometrics
[2] Uriel, Introduction to Econometrics, Lecture
[3] Haslwanter, Introduction to Statistics Using Python
[4] Wackerly, Mathematical Statistics, 7th Edition
[5] Soong, Fundamentals of Probability and Statistics for Engineers

14
[6] OCW MIT, Statistics for Applications, 18.443
[7] Hunter, Asymptotics for Statisticians
[8] Steiger, Correlation and Regresion, Lecture Notes
[9] Sheppard, Introduction to Python for Econometrics
[10] Greene, Econometric Analysis
[11] Uriel, Introduction to Econometrics
[12] Bayramlı, İstatistik, Gayri Lineer Regresyon, Petrol Tepe Noktası
[13] Clarke, An application of the Poisson distribution, https://www.actuaries.
org.uk/system/files/documents/pdf/0481.pdf

15
Çok Değişkenli Gaussian Dağılımlar
Çok değişkenli normal dağılımlarla iş yaparken, mesela Gaussian karışımları
kullanırken, bazı numaraları bilmek faydalı olabiliyor. Bunlardan birincisi (x −
µ)T Σ−1 (x − µ) hesabını yapmaktır, diğer log-toplam-exp numarası (logsumexp
trick) diye bilinen hesaptır.
Birinciden başlayalım, daha kısalaştırmak için y = x − µ diyelim, yani yT Σ−1 y ol-
sun. Şimdi bu formülde bir ters alma (inversion) işleminin olduğunu görüyoruz.
Fakat bu işlem oldukça pahalı bir işlem olarak bilinir, hele hele boyutların yükseldiği
durumlardan (binler, onbinler), kovaryansı temsil eden Σ, n × n olacaktır. Acaba
tersini almayı başka bir şekilde gerçekleştiremez miyiz?
Σ matrisi bir kovaryans matrisi olduğu için simetrik, pozitif yarı kesin bir matri-
stir. Bu tür matrislerin Cholesky ayrıştırmasının olduğunu biliyoruz ve bu işlem
çok hızlı yapılabiliyor. O zaman

Σ = LLT

ki L matrisi alt-üçgensel (lower triangular) bir matristir,

Σ−1 = (LLT )−1

= L−T L−1

Bunu temel alarak iki taraftan y’leri geri koyalım,

yT Σ−1 y = yT L−T L−1 y

Bilindiği gibi lineer cebirde istediğimiz yere parantez koyabiliriz,

= (yT L−T )L−1 y

Parantezden bir şeyin devriği gibi temsil edersek, parantez içindekilerin sırası
değişir ve tek tek devriği alınır,

= (L−1 y)T L−1 y

= |L−1 y|2

Üstteki ifadede |·| içindeki kısım Ax = b durumundaki x’in en az kareler çözümü


olan A−1 b’ye benzemiyor mu? Evet. Gerçi n × n boyutunda bir matris olduğu
için elimizde “bilinmeyenden fazla denklem” yok, yani bu sistem artık belirtilmiş

1
(overdetermined) değil, yani en az kareler değil direk lineer sistem çözümü yapıyoruz.
Bu durumda her standart lineer cebir kütüphanesinde mevcut bir çağrı kullanacağız,
mesela solve_triangular (ve lower -alt- doğru seçeneğini kullanacağız), ki bu
çağrı özellikle alt üçgensel matris üzerinden çözüm yapmaktadır, çünkü L alt-
üçgensel olduğu için çözüm geriye değer koymak (back substitution) ile anında
bulunabilir. Geriye değer koymayı hatırlarsak, mesela

    
2 0 x1 6
=
3 4 x2 8

En üst satırda her zaman tek bir bilinmeyen olacak, çünkü matris alt üçgensel, en
üst satır her zaman en boş satırdır. Bu tek bir eşitlik demektir, yani 2x1 = 6, ki
x1 = 3. Bunu alıp bir sonraki satıra gideriz, artık x1 ’i biliyoruz, sonraki satırda
sadece x2 bilinmeyen kalıyor, 3 · x1 + 4 · x2 = 8, yani x2 = −1/4. Sonuca ulaştık.
Daha fazla boyut olsaydı durum değişmezdi, aynı işlem daha fazla tekrarlanırdı.
Bu arada bu türden bir çözümün ne kadar hızlı olacağını belirtmemize gerek yok
herhalde.
Demek ki yT Σ−1 y hesabı için önce Σ üzerinde Cholesky alıyoruz, sonra L−1 y
çözdürüyoruz. Elde edilen değerin noktasal çarpımını alınca Σ’nin tersini elde
etmiş olacağız.
Örnek (önce uzun yoldan),

import numpy.linalg as lin


Sigma = np.array([[10., 2.],[2., 5.]])
y = np.array([[1.],[2.]])
print np.dot(np.dot(y.T,lin.inv(Sigma)),y)
[[ 0.80434783]]

Şimdi Cholesky ve solve_triangular üzerinden

import scipy.linalg as slin


L = lin.cholesky(Sigma)
x = slin.solve_triangular(L,y,lower=True)
print np.dot(x.T,x)
[[ 0.80434783]]

Aynı sonuca eriştik.


Çok Boyutlu Gaussian’ı Parçalamak (Partitioning)
Diyelim ki Normal bir vektör X’i X = (X1 , X2 ) olarak parçaladık. Bunu Gaussian’a
etkileri ne olur? Aynı şekilde µ = (µ1 , µ2 ) olarak parçalayabiliriz. Σ ise

 
Σ11 Σ12
Σ=
Σ21 Σ22

olarak parçalanabilir. a, b’nin parçalarının boyutları p, q olsun, n = p + q.

2
Şimdi birleşik Gaussian’ı

 T  −1  
1 1 x1 − µ1 Σ11 Σ12 x1 − µ1
f(x; µ, Σ) = exp −
(2π)(p+q)/2 det(Σ)1/2 2 x2 − µ2 Σ21 Σ22 x2 − µ2

Birleşik yoğunluğu parçalar üzerinden belirtirsek, bu yoğunluğu X2 için bileşen


yoğunluğa ve X1 için bir koşullu yoğunluğa ayırabiliriz. Yani

f(x1 , x2 ) = f(x1 |x2 )f(x2 )

tanımındaki parçaları elde etmeye çalışacağız. Ama bundan önce bölüntülenmiş


matrislere yakından bakalım.
Bir bölüntülenmiş (partitioned) matrisin tersini almak için, o matrisin parçalarının
tersini almak doğru değildir, yani

 −1  
E F E−1 F−1
6=
G H G−1 H−1

Tersini alma işlemi için bazı numaralar lazım. Ana numara bölüntülenmiş matrisi
köşegen bir matris haline getirmek, çünkü köşegen matrislerin tersi, köşegendeki
elemanların tersidir, yani ters alma operasyonu bu tür matrislerin “içine işler”,
o yüzden bir şekilde bir köşegen matris elde etmeye uğraşacağız. Bunun için
bölüntülenmiş matrisimizi sağdan ve soldan bazı matrislerle çarpacağız. Ayrıca
şunu da bilelim,

XYZ = W

durumunda Y’nin tersini almak istersek, sağ ve soldaki X, Z matrislerinin tersini


almak gerekmez, niye?

X−1 XYZ = X−1 W

YZZ−1 = X−1 WZ−1

Y = X−1 WZ−1

Şimdi iki tarafın da tersini alalım,

Y −1 = ZW −1 X

3
Tamam, başlayalım.

 
E F
M=
G H

matrisini köşegen yapacağız. Eğer sadece alt sol köşeyi sıfırlayasaydık, bunu
yapacak özel bir matrisle soldan çarpardık,

    
I −FH−1 E F E F
=
0 I G H 0 H

Sadece üst sağ köşeyi sıfırlamak isteseydik, sağdan çarpardık

    
E F I 0 E 0
=
G H −H−1 G I G H

Hepsini biraraya koyalım,

     
I −FH−1 E F I 0 E − FH−1 G 0
−1 = (2)
0 I G H −H G I 0 H

Bu çarpımın doğruluğu çarpım elle yapılarak kontrol edilebilir.


Üstte gördüğümüz gibi

XYZ = W

ifadesindeki Y’nin tersi

Y −1 = ZW −1 X

ile olur.

     
I −FH−1 E F I 0 E − FH−1 G 0
=
0 I G H −H−1 G I 0 H
| {z } | {z } | {z } | {z }
X Y Z W

O zaman

 −1   −1  
E F I 0 E − FH−1 G 0 I −FH−1
= −1
G H −H G I 0 H 0 I

4
Daha kısa olması eşitliğin sağ tarafında, ortadaki matris için E − FH−1 G yerine
M/H kullanalım (bu arada M/H lineer cebirde “M’in H’e göre Schur tamam-
layıcısı (complement)” olarak bilinir),

 −1    
E F I 0 (M/H)−1 0 I −FH−1
= −1 −1 (3)
G H −H G I 0 H 0 I

Eşitliğin sağ tarafındaki çarpımı gerçekleştirirsek,

 
(M/H)−1 −(M/H)−1 FH−1
=
−H−1 G(M/H)−1 H−1 + H−1 G(M/H)−1 FH−1

Bu final ifade bölüntülenmiş bir matrisin tersini o matrisin içindeki parçalar üzerinden
temsil eden bir ifadedir.
İçinde bir köşesi sıfır olan bölüntülenmiş matrislerde determinantlar şöyle işler,

   
E 0 E F
det = det = det(E) det(H)
G H 0 H

Ayrıca

det(AB) = det(A) det(B)

O zaman (2)’nin determinantını alırsak, det yerine || kullandık,

|M| = |M/H||H| (4)

Bu ifade gayet doğal duruyor (bir raslantı herhalde, ya da Schur tamamlayıcısı


işareti özellikle böyle seçilmiş),
Bölüntülenmiş bir matrisin devriğini almak için her bloğunun ayrı ayrı devriği
alınır, ve tüm blokların yanı bölüntülenmiş tamamının bir daha devriği alınır,
yani

 T  
A B A T CT
=
C D BT DT

Şimdi çok değişkenli Normal için bileşen ve koşullu yoğunluk hesaplarına gele-
lim. Gaussian formülünün exp kısmını alırsak,

 T  −1  
1 x1 − µ1 Σ11 Σ12 x1 − µ1
exp −
2 x2 − µ2 Σ21 Σ22 x2 − µ2

5
(3)’teki açılımı kullanırsak, ve E = Σ11 , F = Σ12 , .. olacak şekilde,

T  
I −Σ12 Σ−1
   
1 x1 − µ1 I 0 (Σ/Σ22 ) 0 22 x1 − µ1
exp −
2 x2 − µ2 −Σ−1
22 Σ21 I 0 Σ−1
22 0 I x2 − µ2

Açılımı tamamen yaparsak,


1
= exp − 2
(x1
− µ1 − Σ12 Σ−1
22 (x2
T −1
− µ2 )) (Σ/Σ22 ) (x1 − µ1 − Σ12 Σ−1
22 (x2 − µ2 )) ·

exp 1 12 (x2 − µ2 )T Σ−1
22 (x2 − µ2 )

Not: ΣT12 = Σ21 . Üstte birinci exp içinde sol bölümde devriğin içindeki ifadeler-
den, mesela xT1 , µT1 ’den ve Σ21 ’li ifadeden devrik işlemini çekip, büyük paranteze
alınınca bu değişim oldu.
Şimdi mesela 1. exp’ye dikkat edersek, ortada (Σ/Σ22 )−1 var, ve bu ifadenin sol-
unda ve sağında birbirinin devriği olan aynı terimler duruyor. İfadenin tamamı
bir Normal dağılım. Aynı şey 2. exp için geçerli.
İşin exp tarafını halletik. Şimdi exp öncesindeki kesiri (4) kullanarak parçalayalım,

1 1
= 1/2
(2π)(p+q)/2 det(Σ)1/2

(2π)(p+q)/2 det(Σ/Σ22 ) det(Σ22 )

  
1 1
=
(2π) det(Σ/Σ22 )1/2
p/2 (2π) det(Σ22 )1/2
q/2

Bu parçaların her birini ayrı bir exp önünde kullanabiliriz, ve ikinci exp ifadesinin

1 1
exp (x2 − µ2 )T Σ−1
22 (x2 − µ2 )
(2π) det(Σ22 )1/2
q/2 2

olduğunu görüyoruz. Bu ifade f(x2 ) bileşen yoğunluğudur! O zaman geri kalan-


lar, yani diğer kesir ve birinci exp hep beraber f(x1 |x2 ) yoğunluğu olmalıdır. Yani,

1
·
(2π)p/2 det(Σ/Σ22 )1/2

1
exp − (x1 − µ1 − Σ12 Σ−1 T −1 −1
22 (x2 − µ2 )) (Σ/Σ22 ) (x1 − µ1 − Σ12 Σ22 (x2 − µ2 ))
2

Buradan genel bir kural çıkartabiliriz,

6
1) X2 ’nin bileşen yoğunluğu X2 ∼ N(µ2 , Σ22 )
2) X2 = x2 olmak üzere X1 ’in koşullu dağılımı
 
X1 |X2 = x2 ∼ N µ1 + Σ12 Σ22 (x2 − µ2 ) , Σ/Σ22
−1

Σ/Σ22 nedir? Hatırlarsak, M/H = E − FH−1 G, ve E = Σ11 , F = Σ12 , .. o zaman

Σ/Σ22 = Σ11 − Σ12 Σ−1


22 Σ21

Yani
 
X1 |X2 = x2 ∼ N µ1 + Σ12 Σ22 (x2 − µ2 ) , Σ11 − Σ12 Σ22 Σ21
−1 −1

log-toplam-exp (log-sum-exp trick)


Bu numaranın ilk kısmı nisbeten basit. Bazı yapay öğrenim algoritmaları için
olasılık değerlerinin birbiriyle çarpılması gerekiyor, mesela

r = p1 · p2 . . . pn

Olasılıklar 1’den küçük olduğu için 1’den küçük değerlerin çarpımı aşırı küçülebilir,
ve küçüklüğün taşması (underflow) ortaya çıkabilir. Eğer çarpım yerine log alırsak,
çarpımlar toplama dönüşür, sonra sonucu exp ile tersine çeviririz, ve log’u alınan
değerler çok küçülmez, çarpma yernie toplama işlemi kullanıldığı için de nihai
değer de küçüklüğe doğru taşmaz.

log r = log p1 + log p2 + · · · + log pn

r = exp(log p1 + log p2 + · · · + log pn )

Bir diğer durum içinde exp ifadesi taşıyan bir olasılık değerinin çok küçük değerler
taşıyabilmesidir. Mesela çok değişkenli Gaussian karışımları için alttaki gibi bir
hesap sürekli yapılır,

X
1 1
= wi exp − (x − µ)T Σ−1 (x − µ)
i
(2π) det(Σ)1/2
k/2 2

ki 0 6 wi 6 1 şeklinde bir ağırlık değeridir. Üstteki formülün çoğunlukla log’u


alınır, ve, mesela bir örnek üzerinde görürsek (ve ağırlıkları bir kenara bırakırsak),

7
log(e−1000 + e−1001 )

gibi hesaplar olabilir. Üstteki değerler tamamen uyduruk denemez, uygulamalarda


pek çok kez karşımıza çıkan değerler bunlar. Her neyse, eğer üstteki ifadeyi kodla
hesaplarsak,

print np.log(np.exp(-1000) + np.exp(-1001))

-inf

Bu durumdan kurtulmak için bir numara şudur; exp ifadeleri arasında en büyük
olanını dışarı çekeriz, ve log’lar çarpımı toplam yapar,

log(e−1000 (e0 + e−1 ))

−1000 + log(1 + e−1 )

Bunu hesaplarsak,

print -1000 + np.log(1+np.exp(-1))

-999.686738312

Bu numaranın yaptığı nedir? Maksimumu dışarı çekerek en az bir değerin küçüklüğü


taşmamasını garantilemiş oluyoruz. Ayrıca, bu şekilde, geri kalan terimlerde de
aşırı ufalanlar terimler kalma şansı azalıyor.
Kaynaklar
[1] Flannery, Numerical Recipes, 3rd Edition
[2] Tapaswi, Log-Sum-Exp Trick, http://makarandtapaswi.wordpress.com/
2012/07/18/log-sum-exp-trick/

8
Kullback-Leibler (KL) Mesafesi
İki olasılık dağılımının arasındaki uyumsuzluğu (discrepancy) hesaplayan bir
ölçüt KL mesafesidir. Gerçi bu ölçüt tam tanımıyla mesafe değil, f ile g arasındaki
mesafe g ile f arasındaki mesafeden farklı olabiliyor, KL mesafesi üçgen eşitsizlik
(triangle inequality) kavramını takip etmiyor. Tam tanımlamak gerekirse KL bir
yönsel (directed) mesafedir [2].
Kullback-Leibler aslında 1951’de bir enformasyon ölçütü bulmuş oldular, bu ölçüt
ilginç bir şekilde fizikçi Boltzmann’ın bir sistemdeki düzensizliği ölçen entropi
kavramının negatif değerli halidir. Ayrıca KL mesafesi Enformasyon Teorisi’ni
keşfeden Shannon’un enformasyon tanımının da bir uzantısıdır, bu sebeple bazen
KL mesafesine “izafi entropi” ismi de veriliyor.
Tüm bu kavramların tabii ki İstatistik’teki model seçme uygulamalarıyla yakın
alakaları var. Diyelim ki elimizde iki dağılım var, f yaklaşmaya çalıştığımız bir
model, g ise onu yaklaşık olarak temsil etmeye uğraşan başka bir model, θ parame-
treleri üzerinden tanımlı, yani g(x|θ). θ çoğunlukla veriden kestirilmeye çalışılır,
θ̂ elde edilir, o zaman g(x|θ̂) olur. Bu iki dağılım / model arasındaki KL mesafesi

Z  
f(x)
I(f, g) = f(x) log dx
g(x; θ)

(çoğunlukla çok boyutlu) entegrali ile hesaplanır. Kullback-Leibler I(f, g) nota-


syonunu “g, f yerine, onu yaklaşık olarak temsil edecek şekilde kullanıldığına
kaybedilen enformasyon” şeklinde kullandılar. Tabii ki uygulamalarda bu kayıbın
olabildiği kadar az olmasını isteriz, yani I(f, g)’i g üzerinden minimize etmek
önemli bir uygulama alanı.
Ayrıksal dağılımlar durumunda üstteki formül,

X
k 
pi

I(f, g) = pi log
i=1
πi

Burada k değişkeni rasgele değişkenin alabileceği k farklı değeri temsil eder,


i’inci olayın olma olasılığı pi ’dir, π1 , .., πk ise gerçek dağılımı yaklaşık olarak tem-
sil
P etmeye uP ğraşan modeldir. Ayrıksal durumda 0 < pi < 1, 0 < πi < 1, ve
pi = 1 = πi = 1.
Formüllere yakından bakarsak onların birer beklenti hesabı olduğunu görebiliriz,
R
f(x)(·) dx şablonundaki formüllerin beklenti hesabı için kullanıldığını biliyoruz.
P
Ayrıksal durumda ki=1 pi (·), ve bu beklenti iki dağılımın birbirine olan oranının
negatifinin beklentisi, yani bu oranın ortalaması. Bu kavramın çıkışı çok derin ve
temel, Boltzmann’ın 1877’de, Shannon’un sonra buldukları ile derin bağlantılar
var.
Kabaca tarif etmek gerekirse, bir dağılımın içerdiği enformasyon onun negatif
log’udur, iki dağılım arasındaki mesafe için negatif log’ların farkını alırız, ki fark

1
cebirsel olarak bölümün log’u olarak tek bir log altında gruplanabilir, ve mümkün
tüm sayılar üzerinden bu farkların beklentisini alırsak üstteki entegral (ya da
toplam) formülünü elde etmiş oluruz.
KL mesafesi her zaman pozitiftir, tek bir durum haricinde, eğer f, g eşitse - o
zaman I(f, g) = 0.
Bir örnek üzerinde görmek gerekirse, diyelim ki f 2 parametreli bir Gamma dağılımı,
α = 4, β = 4. Şimdi bu modeli yaklaşık olarak temsil etmeye uğraşan 4 tane
seçeneği görelim, Weibull, lognormal, ters Gaussian, ve F dağılımı.
Yaklaşık Model I(f, gi )

Weibull (α = 2, β = 20) 0.04620


Lognormal (θ = 2, σ2 = 2) 0.67235
Ters Gaussian (α = 16, β = 64) 0.06008
F dağılımı (α = 4, β = 10) 5.74555
Görüldüğü gibi Weibull en yakın olan (yani yaklaşık temsil sırasında en az enfor-
masyon kaybeden o). Lognormal 3. sırada, F dağılımı en uzak olanı.

2
Bir başka örnek için Testlere Devam yazısındaki araba sayım verisine bakalım.
Şimdi ham veriye en uygun olan dağılımı bulmaya çalışacağız.

import pandas as pd
df = pd.read_csv('../stat_tests2/vehicles.csv',header=None)
df.hist(bins=13)
plt.savefig('stat_kl_02.png')

3
Veride Poisson görünümü var. Eşit aralıklarda yapılan sayımların Poisson dağılımını
takip etmeye meyilli olduğunu biliyoruz. Bu tezi kontrol edelim. Eğer, diye-
lim, Possion ve Gaussian arasında seçim yapacak olsak, bu seçimi KL mesafesi
üzerinden yapabilirdik. Her iki durumda da dağılım parametrelerini veriden
tahmin ediyor olurduk,

print np.float(df.mean()), np.float(df.std())

9.09433962264 3.54166574177

Poisson durumunda ortalama hesabı λ̂ için, Gaussian’da ise ortalama ve standart


sapma µ̂, σ̂ için kullanılırdı.
Altta hem verinin hem de hipotez dağılımlardan üretilmiş rasgele sayıların his-
togramlarını hesaplıyoruz. Not: Aslında ham verinin histogramından sonra his-
togram kutularının (bins) sınırlarına bakarak Poisson ve Gaussian analitik dağılımlarının
oraya tekabül eden yoğunluklarını analitik çağrılar ile bulabilirdik, fakat kolay
yolu (!) seçtik, analitik dağılımlar için de rasgele sayı üretiyoruz, hem ham veri
hem analitik durum için histogram hesaplıyoruz.

import scipy.stats
s = 4000
b = 15
r1 = scipy.stats.poisson.rvs(mu=8, size=s)
plt.hist(r1, bins=b,color='b')
plt.title('Poisson $\lambda = 8$')
plt.xlim(0,20)
plt.savefig('stat_kl_04.png')
plt.figure()
r2 = scipy.stats.norm.rvs(2, 1, size=s)
plt.hist(r2, bins=b,color='b')
plt.title('Gaussian $\mu = 2,\sigma=1$')
plt.xlim(0,20)
plt.savefig('stat_kl_06.png')
plt.figure()
r3 = scipy.stats.poisson.rvs(mu=9.0943, size=s)
plt.hist(r3, bins=b,color='b')

4
plt.title('Poisson $\lambda = 9.1$')
plt.xlim(0,20)
plt.savefig('stat_kl_07.png')
plt.figure()
r4 = scipy.stats.norm.rvs(9.1, 3.54, size=s)
plt.hist(r4, bins=b,color='b')
plt.title('Gaussian $\mu = 9.1,\sigma=3.54$')
plt.xlim(0,20)
plt.savefig('stat_kl_08.png')

Şimdi veri ve tüm müstakbel analitik yoğunluklar arasında KL mesafelerini hesaplayalım,

def kl(p, q):


return np.sum(p * np.log(p / q))

b = range(0,30)
eps = 1e-5
dh = np.histogram(df, bins=b, density=True)[0]+eps
h1 = np.histogram(r1, bins=b, density=True)[0]+eps
h2 = np.histogram(r2, bins=b, density=True)[0]+eps
h3 = np.histogram(r3, bins=b, density=True)[0]+eps
h4 = np.histogram(r4, bins=b, density=True)[0]+eps
print 'Poisson lambda = 8', kl(h1, dh)
print 'Gaussian mu = 2,sigma=1', kl(h2, dh)
print 'Poisson lambda = 9.1', kl(h3, dh)
print 'Gaussian mu = 9.1,sigma=3.54', kl(h4, dh)

Poisson lambda = 8 0.14722344735


Gaussian mu = 2,sigma=1 6.39721632939
Poisson lambda = 9.1 0.133099166073
Gaussian mu = 9.1,sigma=3.54 0.200156046018

5
En yakın olan Poisson λ = 9.1 olarak gözüküyor.
Çok Boyutlu Dağılımlar
Eğer bir dijital görüntü üzerinde çalışıyorsak, o resimdeki piksel değerlerinin de
bir “dağılımı” olduğunu düşünebiliriz. Yani resmi, ya da resmin bir bölgesini bir
teorik dağılımdan “üretilmiş” bir örneklem olarak görmek mümkün. Bu dağılımı
çok boyutlu histogram alarak yaklaşık olarak hesaplayabiliriz. Eğer iki farklı
resim bölgesini bu şekilde belirtirsek, bu iki dağılımı KL mesafesiyle karşılaştırabililiriz,
ve böylece görüntüsel olarak iki bölgeyi karşılaştırabiliriz.

from PIL import Image, ImageDraw

def draw_boxes_color(bs,imfile):
im = Image.open(imfile).convert('HSV')
arr = np.asarray(im)
draw = ImageDraw.Draw(im)
colors = ['magenta','green','white','red','yellow']
for i,b in enumerate(bs):
fr = b[0]; to = b[1]
bnew = [(fr[0],arr.shape[0]-fr[1]),(to[0],arr.shape[0]-to[1])]
draw.rectangle(bnew,outline=colors[i])
plt.imshow(im)

def get_pixels(box, im):


arr = np.array(im)
(yw,xw,d) = arr.shape
(bx1,by1) = box[0]; (bx2,by2) = box[1]
by1 = yw-by1; by2 = yw-by2
x1 = min(bx1,bx2); x2 = max(bx1,bx2)
y1 = min(by1,by2); y2 = max(by1,by2)
arr = arr[y1:y2, x1:x2, :]
return arr

box1 = [(35,144),(87,292)]
box2 = [(106,183),(158,287)]
box3 = [(117,86),(132,160)]
f = '../../vision/vision_50colreg/castle.png'
draw_boxes_color([box1,box2],f)
plt.savefig('stat_kl_03.png')
draw_boxes_color([box2,box3],f)
plt.savefig('stat_kl_05.png')

6
Renklerin HSV kodlamasını kullanalım, o zaman her piksel kordinatında 3 değer
olur. Bu durumda histogram almak demek çok boyutlu histogram demektir, üç
boyut için sırasıyla 8,8,4 tane kutu tanımlarsak, 256 tane kutu elde ederiz. Bu
kutuları numpy.histogramdd ile hesaplarız, KL karşılaştırması için kutuları düz
vektör haline getirebiliriz -KL hesabında her iki tarafın birbirine tekabül eden
kutuları kullanıldığı sürece problem yok- ve böylece nihai hesap yapılır.

def box_kl_dist(b1,b2,im):
im = Image.open(f).convert('HSV')
arr1 = get_pixels(b1, im)
r = [(0,255),(0,255),(0,255)]

arr1 = np.reshape(arr1, (arr1.shape[0]*arr1.shape[1],3))


H1, edges = np.histogramdd(arr1, bins=(8, 8, 4), normed=True, range=r)
H1 = np.reshape(H1, (H1.shape[0]*H1.shape[1]*H1.shape[2], 1))

arr2 = get_pixels(b2, im)


arr2 = np.reshape(arr2, (arr2.shape[0]*arr2.shape[1],3))
H2, edges = np.histogramdd(arr2, bins=(8, 8, 4), normed=True, range=r)
H2 = np.reshape(H2, (H2.shape[0]*H2.shape[1]*H2.shape[2], 1))

return kl(H1+eps, H2+eps)

print box_kl_dist(box1, box2, f)


print box_kl_dist(box2, box3, f)

7.55231179178e-06
7.30926985663e-07

İkinci karşılaştırmada mesafe daha yakın duruyor; hakikaten de resimlere bakarsak


ikinci resimdeki bölgelerin renksel olarak birbirine daha yakın olduğunu görebiliyoruz.
Kaynaklar
[1] Cover, Elements of Information Theory
[2] Burnham, Model Selection and Inference

7
Lineer Regresyon
Bir hedef değişkeninin bir veya daha fazla kaynak değişkenine olan bağlantısını
bulmak için en basit yöntemlerden biri bu ilişkinin lineer olduğunu kabul et-
mektir, yani eldeki değişkenlerin belli ağırlıklar ile çarpımının toplamı olarak.
İlk başta bilinmeyen bu ağırlıkları, ya da katsayıları bulmak için En Az Kareler
(Least Squares) en iyi bilinen yöntemlerden biri; En Az Kareler daha önce pek
çok değişik ders notlarında, yazıda türetildi. Mesela [7], [8], ya da [9].
Lineer Regresyonun sadece iki değişken temelli işlemek gerekirse,

Y = β0 + β1 x + 

olabilir. Eğer iki değişkenden fazlası var ise bu bir düzlem uydurulacak demek-
tir. Değişken , N(0, σ2 ) dağılımından gelen hatadır ve σ bilinmez. Eğer veriyi
(x1 , y1 ), ...(xn , yn ) ikili olarak grafiklesek

gibi gözükebilirdi, lineer regresyon ile yapmaya çalıştığımız tüm noktalara ola-
bilecek en yakın düz çizgiyi (üstte görüldüğü gibi) bulmaktır.
Bu düz çizgiyi (ki boyutlu ortamda bu çizgi bir hiper düzlem olurdu, β2 , β3 , ..
gibi daha fazla katsayı gerekirdi), En Az Kareler ile bulduktan sonra elimize
geçenler katsayı değerlerinin tahminidir, ki bunlar bazı kaynaklarda β̂0 , β̂1 olarak
tanımlanır, bu notasyon istatistikteki “tahmin edici (estimator)” notasyon ile uyumlu.
Bu tahmin ediciler ile elde edilen y’nin kendisi de bir tahmin edici haline gelir ve
bir düz çizgiyi tanımlar,

ŷ = β̂0 + β̂1 x

Katsayıların tahmin edicilerinin de dağılımı vardır ve bu dağılım, ideal şartlarda


bir normal dağılımdır. İspat için bu yazının sonuna bakınız.
Örnek olarak lineer regresyon için tarihte kullanılan neredeyse ilk veri setini
seçeceğim. Bu veri çocukların ve onların ebeveynlerinin boy uzunluğunu içeren
Galton’un 19. yüzyılda analiz ettiği veri setidir. Hatta öyle ki regresyon ke-
limesinin bile bu problem ile alakası var, İngilizce regress kelimesi baştaki (çoğunlukla
daha iyi olmayan) bir hale dönmek anlamında kullanılır, ve problemde çocukların
boyunun ebeveyn boyuna “geri döndüğü” ya da ondan ne kadar etkilendiği in-
celenmektedir.

1
import pandas as pd
df = pd.read_csv('galton.csv',sep=',')
print df.head(4)

child parent
0 61.7 70.5
1 61.7 68.5
2 61.7 65.5
3 61.7 64.5

Şimdi regresyonu işletelim, sadece bağımsız tek değişken olacak, ebeveyn boyu
parent, hedef değişken ise çocuk child içinde.

import statsmodels.formula.api as smf


results = smf.ols('child ˜ parent', data=df).fit()
print results.summary()

OLS Regression Results


==============================================================================
Dep. Variable: child R-squared: 0.210
Model: OLS Adj. R-squared: 0.210
Method: Least Squares F-statistic: 246.8
Date: Thu, 03 Nov 2016 Prob (F-statistic): 1.73e-49
Time: 09:11:04 Log-Likelihood: -2063.6
No. Observations: 928 AIC: 4131.
Df Residuals: 926 BIC: 4141.
Df Model: 1
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [95.0% Conf. Int.]
------------------------------------------------------------------------------
Intercept 23.9415 2.811 8.517 0.000 18.425 29.458
parent 0.6463 0.041 15.711 0.000 0.566 0.727
==============================================================================
Omnibus: 11.057 Durbin-Watson: 0.046
Prob(Omnibus): 0.004 Jarque-Bera (JB): 10.944
Skew: -0.241 Prob(JB): 0.00420
Kurtosis: 2.775 Cond. No. 2.61e+03
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly speci
[2] The condition number is large, 2.61e+03. This might indicate that there are
strong multicollinearity or other numerical problems.

print pd.Series(results.resid).describe()

count 9.280000e+02
mean 4.484995e-13
std 2.237339e+00
min -7.805016e+00
25% -1.366144e+00
50% 4.869321e-02
75% 1.633856e+00
max 5.926437e+00
dtype: float64

2
Bu çıktıda gösterilenler ne anlama gelir?
1) coef altında görülen değerler sırasıyla βo , β1 tahminleridir, yani β̂o , β̂1 . Bun-
lar bulmak istediğimiz katsayılar. İki boyutta olduğumuz için düz bir çizgiden
bahsediyoruz, bu çizginin y eksenini kestiği yer kesi (intercept) β̂0 ’da ve ebeyne
(parent) tekabül eden katsayı β̂1 .
Teorik olarak eğer bir katsayı sıfır ise bu işe yaramaz bir katsayıdır, çünkü modele
hiçbir şey “eklemez”. Fakat Basit En Az Kareler (ordinary least squares -OLS-)’in
hesapladığı bir tahmindir nihayetinde ve hiçbir zaman sıfır olmayacaktır. O za-
man soruyu biraz daha değiştirmek gerekir: istatistiki olarak düşünürsek gerçek
katsayının sıfır olma olasılığı nedir? Katsayı yanında görülen t ve P > |t| (diğer
ismiyle p-değeri) bunun için kullanılır.
t değeri bir katsayı için onun tahminini ve standart hatasına bölerek elde edilir.
Üstteki çıktıda mesela 23.9415/2.811=8.517. Bu değer katsayı tahmininin veri-
den veriye ne kadar değişik sonuçlar verebileceğini (variability) gösterir, ve bir
bakıma bu katsayı tahmininin kesinliği (precision) hakkında bir rapordur. Eğer
bir katsayı tahmini, standart hatasına göre büyük ise (ki bölüm bunu gösterir) bu
katsayının sıfır olmadığına dair güçlü bir işaret olarak alınabilir.
Peki ne kadar büyük bir sayı büyük sayılmalıdır? Bunun için p-değerine başvuruyoruz.
P-değerini hesaplamak için t değeri ve standart hatasının dağılımından bahset-
mek lazım.
t değeri bir rasgele değişken olduğu için bir dağılımı vardır, ve bu dağılım Öğrenci
t (Student t) dağılımıdır. Sebep şu, t değerinin kendisi de iki rasgele değişkeninin
bölümüdür, bu değişkenlerden biri katsayının kendisidir, ki bu değer nüfustaki
“gerçek” katsayı etrafında normal olarak dağılmış bir rasgele değişken olarak
kabul edilir. Diğeri ise, yani bölen, tahmin edici S’tır ki bir chi kare rasgele
değişkenin kareköküdür. Bu bölümün Öğrenci t dağılımına sahip olduğu daha
önce gösterildi.
Standart hata ise, artık / kalıntı değerlerle (residuals) alakalıdır (results.resid
içinde), ve bu değerler model uydurulduktan sonra o modeli kullanarak gerçek
veriye ne kadar uzak düştüğümüzü gösterir. Formül olarak her veri noktası i için
ri = yi − β1 xi − βo . Her katsayı için de ayrı ayrı kalıntı hesaplanabilir.
İdeal durumda, yani modelin doğru, veriye uyduğu durumda artıkların mükemmel
bir Normal dağılıma sahip olması gerekir, çünkü veri içindeki tüm örüntü, kalıp
model tarafından “bulunmuştur” ve geri kalanlar gürültüdür (gürültü tabii ki
Normal dağılımda). İdeal ortamda OLS algoritmasının, matematiksel olarak, or-
talaması (mean) sıfır olan artıklar üretmesi garantidir. Bir diğer varsayım uy-
duralan değişkenlerin katsayılarının onların “gerçek” değerleri etrafında merke-
zlenen bir Normal dağılıma sahip olduğudur (ispat için [10] yazısının sonuna
bakılabilir). Bu normallik önemli çünkü katsayı tahmini ile standart hatayı bölünce
başka bir Öğrenci t dağılımı ortaya çıkacak.
Kalıntıların normalliği QQ grafiği ile kontrol edilebilir, bkz [11],

3
import statsmodels.api as sm
sm.qqplot(results.resid)
plt.savefig('stat_linreg_01.png')

Oldukça düz bir çizgi, uyum başarılı demek ki..


Şimdi, katsayı için olan kalıntı değerlerinin karesini alıp toplarsak ve karekökü
alırsak, bu rasgele değişkenin Chi Kare (Chi Square) olarak dağıldığı bilinir, ve
yine bilinir ki standart normal rasgele değişken, bolu, chi kare karekökü bize bir
Öğrenci t dağılımını verir, mesela

Z
t= p = tm
V/m

serbestlik derecesi m olan bir Öğrenci t rasgele değişkenidir.


Öğrenci t’den p-değeri üretmek için t değerinin sıfırdan ne kadar uzağa düştüğü
bir Öğrenci t olasılık hesabına dönüştürülür. Önce katsayının tam değeri (ab-
solute value) alınır, eksileri artı yaparız, çünkü sıfırdan uzaklık ile ilgileniyoruz
sadece ve Öğrenci t dağılımı simetriktir, sonra bu değer tm dağılımı üzerinden bir
olasılık hesabına dönüştürülür. Yani “katsayı / standart hata bir tm ile dağılmış
ise, elde edilen bölümün o dağılımdan gelme olasılığı nedir?” gibi bir soru.
Olasılık hesabı yoğunluk fonksiyonu üzerinde bir alan hesabıdır, t değeri 2 ise
ve t5 için bu alan hesabı şöyle,

Ayrıca bu olasılık sonucu sıfır ile karşılaştırmak kolay olsun diye 1’den çıkartılır

4
ve 2 ile çarpılır, istatistiğin böylece iki taraflı (two-sided) olduğu belirtilir. m,
veri nokta sayısı, eksi katsayı sayısı, artı bir olarak hesaplanıyor. Eğer sonuç
0.05’ten küçük ise bu iyiye işarettir, 0.05’ten büyük olan değerler iyi değildir. Gal-
ton örneğinde β̂0 için,

from scipy.stats import t


print 2*(1-t(927).cdf(np.abs(8.517)))

0.0

Üstteki sonuç 0.0 değeri çok iyi. Demek ki bu katsayı önemli (significant).
2) Artıklarda sıfırdan sapma, herhangi bir yöne doğru yamukluk (skew) OLS
uyumsuzluğunun işareti olabilir, üstte artıklar üzerinde describe çağrısı ile me-
dyanı (%50 noktası) hesaplattık, bu değerin 0.04 ile sıfırdan çok az sağa doğru
saptığını görüyoruz. %25, %75 bölgelerinin işaretlerine bakmadan tam (absolute)
değerlerine bakalım, 1.36 ve 1.63, çok az farklılar. İdealde hiç fark olmamasını is-
teriz çünkü normal dağılım simetriktir, her iki tarafında da bu bölgelerin yakın
değerde olmasını bekleriz. Fakat bu değerler alarm yaratacak nitelikte değil.
Artıkların minimum, maksimum (min,max) değerleri verideki ekstrem, aykırı değerlere
(outlier) dair bir işaret olabilir.
3) R2 , ya da R-squared, modelin kalitesiyle alakalıdır, ne kadar büyükse o kadar
iyidir. Matematiksel olarak bu değer y’nin değişiminin / varyansının oran olarak
ne kadarının regresyon modeli tarafından “açıklanabildiğini” belirtir. Üstteki
örnekte R2 = 0.21 ise model varyansın yüzde 21’ini açıklıyor. Ya da “bir çocuğun
boyunun yüzde 21’i ebeveyn boyu ile açıklanabilir” sözü de söylenebilir. Geri
kalan 0.75’lik yani yüzde 75’lik “açıklanamayan” kısmın değişik sebepleri ola-
bilir; belki hesaba katmadığımız değişkenler vardır, ya da örnekleme prosedüründe
hatalar yapılmıştır, ya da lineerlik bu probleme uygun değildir, vs.
Tavsiyemiz düz R2 yerine OLS çıktısında görülen “düzeltilmiş R2 ” yani Adj. R-squared
bilgisinin kullanılmasıdır, çünkü bu bilgi modeldeki değişken sayısını da hesaba
katar ve daha iyi bir ölçüttür.
4) F istatistiği: Bu istatistik tüm modelin önemli mi önemsiz mi olduğunu ird-
eler. Eğer modelde sıfır olmayan en az bir katsayı var ise model önemlidir (her-
hangi bir i için βi 6= 0). Eğer tüm katsayılar sıfır ise model önemsizdir (β0 =
β1 , . . . , βn = 0). Örnekte

... F-statistic: 246.8


... Prob (F-statistic): 1.73e-49

Prob (F-statistic) bir p-değeri, ve bu değer 0.05’ten küçük ise model büyük
bir ihtimalle önemlidir, eğer 0.05’ten büyük ise büyük ihtimalle önemli değildir.
Üstteki p-değeri 1.73e-49 gösteriyor, çok ufak bir değer, yani bu iyi.
Not: Çoğu kişi OLS çıktısında ilk önce R2 ’ye bakar, fakat bilgili istatistikçi F’e
bakar, çünkü bir model önemli değilse, geri kalan hiçbir ölçütün önemi yoktur.

5
Nihai analiz olarak bu veride parent katsayısının pozitif olan değerine bakarak
çocuk ve ebeveyn boyu arasında bir bağlantı olduğunu söyleyebiliriz.
Basamaklı Regresyon (Stepwise Regression)
Eğer elimizde çok fazla değişken var ise, bu değişkenlerden hangilerinin en iyi
olduğunu seçmek oldukça zor olabilir. Önemlilik sayıları burada biraz yardımcı
olabilir, fakat değişkenlerin eklenip, çıkartılması regresyonun tamamını etkilediği
için deneme / yanılma ile ekleme / çıkartma işleminin yapılması gerekebilir, ki
bu işlemi elle yapmak külfetli olur. Acaba bu yöntemi otomize edemez miyiz?
R dilindeki lm’in step adlı özelliği burada yardımcı olabilir. Önce yapay bir veri
üretelim,

import pandas as pd
n = 100
df = pd.DataFrame()
np.random.seed(10)
df['x1'] = np.random.normal(size=n)
df['x2'] = np.random.normal(size=n)
df['x3'] = np.random.normal(size=n)
df['x4'] = np.random.normal(size=n)
df['y'] = 10 + -100*df['x1'] + 75*df['x3'] + np.random.normal(size=n)

Yapay veride farkedileceği üzere x2,x4 modele eklenmedi bile. Bu değişkenler


önemsiz, ürettiğimiz için biz bunu biliyoruz. Bakalım regresyon bunu keşfedecek
mi? Şimdi tüm değişkenlerle bir OLS yapalım,

%load_ext rpy2.ipython

%R -i df
%R fullmodel <- lm(y˜x1+x2+x3+x4,data=df)
%R -o res res = summary(fullmodel)
print res

Call:
lm(formula = y ˜ x1 + x2 + x3 + x4, data = df)

Residuals:
Min 1Q Median 3Q Max
-3.15789 -0.63251 -0.01537 0.58051 2.30127

Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 9.94953 0.09378 106.098 <2e-16 ***
x1 -99.95333 0.09686 -1031.975 <2e-16 ***
x2 -0.04103 0.09500 -0.432 0.667
x3 75.14720 0.10240 733.851 <2e-16 ***
x4 0.04863 0.10015 0.486 0.628
---

6
Residual standard error: 0.9292 on 95 degrees of freedom
Multiple R-squared: 0.9999,Adjusted R-squared: 0.9999
F-statistic: 4.23e+05 on 4 and 95 DF, p-value: < 2.2e-16

Görüldüğü gibi daha baştan x2,x4 önemsiz bulundu. Ama daha karmaşık bir
modelde bu o kadar rahat bulunmayabilirdi. Şimdi step ile tam modelden bu
değişkenler çekip çıkartılabiliyor mu ona bakacağız.
R dilinde basamaklı regresyon iki şekilde işler. Ya tam modelden geriye gider-
siniz yani tam modelden ise yaramayan değişkenleri atarsınız, ya da en baz (boş)
modelden başlayıp ileri gidersiniz yani ekleye ekleye en iyi değişkenlere erişmeye
uğraşırsınız. İlk önce eliminasyonu görelim,

%R reducedmodel <- step(fullmodel, direction="backward")


%R -o resred resred<-summary(reducedmodel)
print resred

Call:
lm(formula = y ˜ x1 + x3, data = df)

Residuals:
Min 1Q Median 3Q Max
-3.1667 -0.6078 -0.0256 0.5732 2.3592

Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 9.95039 0.09251 107.6 <2e-16 ***
x1 -99.95181 0.09540 -1047.7 <2e-16 ***
x3 75.14514 0.10101 744.0 <2e-16 ***
---

Residual standard error: 0.9217 on 97 degrees of freedom


Multiple R-squared: 0.9999,Adjusted R-squared: 0.9999
F-statistic: 8.599e+05 on 2 and 97 DF, p-value: < 2.2e-16

Doğru sonuçlar bulundu. Bu yöntem fena değildir, ama bazen o kadar çok değişken
vardır ki tam modelle başlamak iyi bir fikir olmayabilir, o zaman boş başlayıp
ileri gitmek daha mantıklı olabilir. Boş modelde sadece y ˜ 1 olacak, biraz garip
gelebilir, çünkü hiç değişken yok (ki bu durumda uydurulan tüm değişkenler
sadece y’nin ortalamasıdır). Neyse, ileri giden modelde step’e hangi değişkenlerin
aday / potansiyel değişken olduğunu belirtmek gerekir, bunu scope ile yaparız,

%R minmodel <- lm(y ˜ 1,data=df)


%R fwd <- step(minmodel, direction="forward", scope = ( ˜ x1 + x2 + x3 + x4))
%R -o fwdres fwdres <- summary(fwd)
print fwdres

Call:
lm(formula = y ˜ x1 + x3, data = df)

7
Residuals:
Min 1Q Median 3Q Max
-3.1667 -0.6078 -0.0256 0.5732 2.3592

Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 9.95039 0.09251 107.6 <2e-16 ***
x1 -99.95181 0.09540 -1047.7 <2e-16 ***
x3 75.14514 0.10101 744.0 <2e-16 ***
---

Residual standard error: 0.9217 on 97 degrees of freedom


Multiple R-squared: 0.9999,Adjusted R-squared: 0.9999
F-statistic: 8.599e+05 on 2 and 97 DF, p-value: < 2.2e-16

Yine aynı sonuca geldik. Tabii bu çok basit bir yapay veri, o yüzden aynı yere
gelmiş olmamız şaşırtıcı değil. Gerçek problemlerde geriye ve ileri giden mod-
ellerin ikisini de deneyip sonuçları karşılaştırmak iyi oluyor. Sonuçlar şaşırtıcı
olabilir.
Bir diğer tavsiye basamaklı regresyonu her derda deva bir yöntem olarak görmemek,
çünkü üstteki çıktılara göre sihirli bir şekilde en kullanışlı alt kümeyi buluveriyor,
vs, fakat bu metot, değişkenleri iyi tanıyan birisi tarafından dikkatli bir şekilde
alt kümenin elenip, seçilerek bulunması yerine geçemez. Bunu özellikle belirtiy-
oruz, çünkü bazılarının aklına şöyle bir şey gelebilir,

%R full.model <- lm(y ˜ (x1 + x2 + x3 + x4)ˆ4)


%R reduced.model <- step(full.model, direction="backward")

Üstte görülen ˆ4 kullanımı dört değişken arasındaki tüm mümkün etkileşimleri


(interaction) ortaya çıkartır, yani x1:x2,x1:x2:x3:x4,x3:x4,.. gibi ve bunların
tamamını basamaklı regresyona sokar, çünkü bu cinliğe göre nasılsa eliminasyon
metotu ise yaramayan değişkenleri atacaktır (!). Bu metot iyi işlemeyecektir, çoğu
etkileşimin hiçbir anlamı yoktur, step fonksiyonu herhalde çok fazla seçenek
arasında boğulur, sonuçta elimizde bir sürü ise yaramaz değişken kalacaktır.
Soru
Diyelim ki elimde bir veri seti var ve üzerinde OLS uyguladım, sonuçlara baktım.
Eğer bu veri setini alıp, kendisine eklersem, yani veriyi iki katına çıkartırsam, ilk
işlettiğim OLS’teki katsayılara, ve standart hataya ne olur?
Cevap
Dikkat, bu soru bir mülakat sorusudur! :) Düşünelim, sezgisel bir şekilde, 2
boyutta, uydurulan tek çizginin altında ve üstünde yine aynı verilerin bir kez
daha tekrarlanacağını farkederiz, ki bu çizginin yerini değiştirmezdi. Yani kat-
sayılar aynı kalırdı. Fakat standart sapmaya ne olurdu? Artıklardan başlayalım,

ri = yi − β0 + β1 xi

8
Veriyi ikiye katlayınca,

2yi − 2β0 + 2β1 xi ⇒ 2ri

Standart hata hesabı, kolaylık için n − 1 yerine n, ve C = r2i ,

rP r P r
2 2
i (2ri ) 4 r
i i 4C
= =
2n 2n 2n
p
Eski veri seti için aynı hesap C/n. İki tarafta da karekök var, sadece karekök
içine bakalım,

C 4C
?
n 2n
Aradaki ilişki nedir? Eğer veriyi ikiye katlarsak C 4 katına çıkıyor, ama herhangi
bir n > 2 için, 2n bu büyümeyi geçer, ve sağdaki büyüklük soldakina nazaran
küçülür.

C 4C
> , n > 2 için
n 2n
Demek ki yeni veri setinde standard hata küçülür. Eğer bu değer küçülürse, kat-
sayılara ait olan standart hatalar da, ki onlar biraraya gelerek standart hatayı
oluşturacaklar, küçülecektir. Standart hatanın küçülmesi aslında şaşırtıcı olma-
malı, aynı yönde daha fazla veri alınca elimizdeki katsayılarından daha “emin”
hale geldik. Bu iyi bir şey olarak görülebilirdi belki, ama bu durumun mod-
elin geri kalanı üzerindeki etkilerini şimdi düşünelim. Eğer katsayı aynı kalır,
hata küçülürse katsayı / hata olarak hesaplanan t değeri buyur. Daha büyüyen
t değeri daha küçülen p-değeri demektir! Yani veriyi ikiye katlayınca birden
bire önemsiz olan (> 0.05) bir değişken, önemli hale gelebilir. Altta örneğini
görüyoruz,

import statsmodels.formula.api as smf


results = smf.ols('y˜x1+x2+x3+x4', data=df).fit()
print results.summary()

OLS Regression Results


==============================================================================
Dep. Variable: y R-squared: 1.000
Model: OLS Adj. R-squared: 1.000
Method: Least Squares F-statistic: 4.230e+05
Date: Sat, 14 Mar 2015 Prob (F-statistic): 5.97e-201
Time: 15:56:03 Log-Likelihood: -131.99
No. Observations: 100 AIC: 274.0
Df Residuals: 95 BIC: 287.0
Df Model: 4
Covariance Type: nonrobust

9
==============================================================================
coef std err t P>|t| [95.0% Conf. Int.]
------------------------------------------------------------------------------
Intercept 9.9495 0.094 106.098 0.000 9.763 10.136
x1 -99.9533 0.097 -1031.975 0.000 -100.146 -99.761
x2 -0.0410 0.095 -0.432 0.667 -0.230 0.148
x3 75.1472 0.102 733.851 0.000 74.944 75.350
x4 0.0486 0.100 0.486 0.628 -0.150 0.247
==============================================================================
Omnibus: 3.126 Durbin-Watson: 2.267
Prob(Omnibus): 0.210 Jarque-Bera (JB): 2.795
Skew: -0.191 Prob(JB): 0.247
Kurtosis: 3.724 Cond. No. 1.26
==============================================================================

Veriyi ikiye katlayıp bir daha OLS,

df2 = pd.concat((df,df))
results = smf.ols('y˜x1+x2+x3+x4', data=df2).fit()
print results.summary()

OLS Regression Results


==============================================================================
Dep. Variable: y R-squared: 1.000
Model: OLS Adj. R-squared: 1.000
Method: Least Squares F-statistic: 8.683e+05
Date: Sat, 14 Mar 2015 Prob (F-statistic): 0.00
Time: 15:56:41 Log-Likelihood: -263.98
No. Observations: 200 AIC: 538.0
Df Residuals: 195 BIC: 554.4
Df Model: 4
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [95.0% Conf. Int.]
Intercept 9.9495 0.065 152.006 0.000 9.820 10.079
x1 -99.9533 0.068 -1478.512 0.000 -100.087 -99.820
x2 -0.0410 0.066 -0.619 0.537 -0.172 0.090
x3 75.1472 0.071 1051.389 0.000 75.006 75.288
x4 0.0486 0.070 0.696 0.487 -0.089 0.186
==============================================================================
Omnibus: 4.922 Durbin-Watson: 2.274
Prob(Omnibus): 0.085 Jarque-Bera (JB): 5.589
Skew: -0.191 Prob(JB): 0.0611
Kurtosis: 3.724 Cond. No. 1.26
==============================================================================

Görüldüğü gibi x4 artık < 0.05 altında!


OLS’in bu tür nüanslarını bilmek iyi olur. Eğer veride tekrar varsa, herhangi bir
sebeple, tekrarlayan verileri çıkartmak belki de mantıklı olacaktır.
ABD Başkanlık Yarışını Tahmin Etmek
ABD başkanlık yarışlarının oldukça tahmin edilebilir olduğu uzunca süredir id-
dia edilmektedir. Bu alanda pek çok model var, Andrew Gelman’ın oldukça
çetrefil, MCMC kullanan modelinden [4] (ki bunun için başkasının yazdığı kod

10
[5]’te bulunabilir), ya da daha öz, basit bir metot [3] mevcuttur. En basit ve etk-
ili yöntem Değişim Zamanı (Time for Change) modeli, bu modele göre başkanlık
yarışının olduğu Haziran ayı itibariyle ekonomik büyüme yüzdesi (gdp_growth),
mevcut başkanın net destek oranı (net_approval, ki bu rakam destek yüzdesinden
desteklemeyen yüzdesi çıkartılarak hesaplanır) ve o anki başkanının partisinin, 2
dönem ya da daha fazladır Beyaz Ev’de olup olmadığı bilgisi 1/0 değeri ile kod-
lanarak (two_terms) lineer regresyona verilir ve hedef değişken olarak, yönetimi
elinde tutan partinin ülke genelinde tüm oyların (popular vote) yüzde kaç alacağı
tahmin edilmeye uğraşılır.
Örnek olarak Clinton ve Bush I arasındaki 1992 yarısında Cumhuriyetçi adayın
(çünkü o zamanki başkan Cumhuriyetçi) yüzde kaç oy alacağı tahmin edilecek,
two_terms=1 çünkü iki dönem Cumhuriyetçi Reagan ardından bir dönem Cumhuriyetçi
Bush gelmiş, Cumhuriyetçiler uzun süredir baştalar.
Gore / Bush arasındaki 2000 yılı yarısında Demokratların yüzdesini tahmin et-
meye uğraşıyoruz, çünkü başta Demokrat Clinton var, ve iki dönemdir orada.
Net popülarite ve büyüme hep o anki başkan ve onun partisinin performansı ile
alakalı. Bu regresyonu işlettiğimizde, sonuçlar şöyle,

import statsmodels.formula.api as smf


import pandas as pd
df = pd.read_csv('prez.csv')
print df.head() , '\n'
regr = 'incumbent_vote ˜ gdp_growth + net_approval + two_terms'
results = smf.ols(regr, data=df).fit()
print results.summary()
year gdp_growth net_approval two_terms incumbent_vote
0 2012 1.3 -0.8 0 52.0
1 2008 1.3 -37.0 1 46.3
2 2004 2.6 -0.5 0 51.2
3 2000 8.0 19.5 1 50.3
4 1996 7.1 15.5 0 54.7

OLS Regression Results


==============================================================================
Dep. Variable: incumbent_vote R-squared: 0.901
Model: OLS Adj. R-squared: 0.878
Method: Least Squares F-statistic: 39.52
Date: Fri, 11 Sep 2015 Prob (F-statistic): 8.50e-07
Time: 21:57:48 Log-Likelihood: -32.747
No. Observations: 17 AIC: 73.49
Df Residuals: 13 BIC: 76.83
Df Model: 3
Covariance Type: nonrobust
================================================================================
coef std err t P>|t| [95.0% Conf. Int.]
--------------------------------------------------------------------------------
Intercept 51.4363 0.811 63.409 0.000 49.684 53.189
gdp_growth 0.5799 0.118 4.903 0.000 0.324 0.835
net_approval 0.0987 0.021 4.764 0.000 0.054 0.143
two_terms -4.2983 1.032 -4.164 0.001 -6.528 -2.069

11
==============================================================================
Omnibus: 0.333 Durbin-Watson: 1.545
Prob(Omnibus): 0.847 Jarque-Bera (JB): 0.484
Skew: -0.169 Prob(JB): 0.785
Kurtosis: 2.246 Cond. No. 71.4
==============================================================================

İnanılmaz bir başarı, Prob (F-statistic) değeri neredeyse sıfır, Adj. R-squared
değeri yüzde 80’den daha fazla, tüm değişkenler istatistiki olarak önemli (P>|t|
değerleri 0.05’ten küçük).
Acaba bu modeli kullanarak geçmişteki yarışları “tahmin etsek” sonuç ne olurdu
diye merak ediyoruz, bunun için tahmin edeceğimiz senenin veri noktasını dışarıda
bırakarak (out-of-sample) regresyon işletip o seneyi bilmiyormuş gibi yapıp tah-
min ediyoruz,

def out_of_sample_pred(year):
df2 = df[df['year'] != year]
results2 = smf.ols(regr, data=df2).fit()
conf = results2.conf_int()
pred = np.array(df[df['year'] == year])[0][:-1]; pred[0] = 1.
return np.dot(pred, conf)
# o senenin verisinin disarida birakarak gecmisi tahmin et
print 'bush/clinton'; print out_of_sample_pred(1992)
print 'gore/bush'; print out_of_sample_pred(2000)
print 'bush/kerry'; print out_of_sample_pred(2004)
print 'mccain/obama'; print out_of_sample_pred(2008)
print 'obama/romney'; print out_of_sample_pred(2012)
bush/clinton
[ 43.68758927 52.47911415]
gore/bush
[ 48.31291287 60.68132985]
bush/kerry
[ 50.66667848 55.79188333]
mccain/obama
[ 41.05409775 46.15966954]
obama/romney
[ 49.81182614 54.45584122]

Tahmin hesabında değişken katsayılarının %95 güven aralıklarını veren conf_int()


çağrısını kullandık, değişkenlerin noktasal değerlerini kullanmadık, bu şekilde
tahmine olan güvenimizi aralığın büyüklüğüne bakarak görebilmiş olacağız. Dikkat:
aslında tahminin güven aralığını hesaplamak biraz daha ek iş gerektiriyor, türetilmesi
[12] bölümünde.
Şimdi sonuçlara bakalım; Bush / Kerry yarışı için kesin Bush diyor (çünkü güven
aralığının iki ucu da yüzde 50 üstünde), Bush kazandı. McCain / Obama için
McCain kesin kaybedecek diyor, McCain kaybetti. Obama / Romney yarışı için
Obama (neredeyse) kesin kazanacak diyor, Obama kazandı. Tahminler iyi!
Gore / Bush ilginç bir durum, Gore çok, çok daha şanslı, ama Gore kaybetti.
Fakat bu seçimin ne kadar yakın olduğunu o zaman yarısı takip edenler hatırlar,
ayrıca, Florida’da bir takım “şaibeli” işlerin (!) olduğu biliniyor, ve model ülke

12
genelinde oyu tahmin etmeye uğraşıyor, ki ülke genelinde bakılınca Gore daha
fazla oy almıştı. Amerikan sistemine göre başkanlık seçimleri de eyalet bazında
hesaplanır, bir eyalette kazanan tüm oyları alır, bu sebeple ülke geneli ile eyalet
bazı arasında uyumsuzluk ortaya çıkabiliyor.
Gore / Bush olayına bir diğer bakış açısı şöyle: oy yüzdesi tahminini yüzdenin
kendisi için değil, kazanma / kazanmama için bir sinyal olarak kabul etmek,
yani popüler oyun kime gittiğine bakmamak, o zaman modelimizin Göre / Bush
seçimini başarısız tahmin ettiğini kabul etmek lazım. Bu şaşırtıcı değil aslında
çünkü 2000’de Bush kazandığına kendisi bile şaşırmıştı.
2016 senesindeki yarışta kim kazanacak? Demokratların şansı şöyle (dikkat belli
bir adaydan bahsetmiyoruz bile); Haziran 2016 itibariyle büyüme 2%, Obama’nın
net popülaritesi sıfır olduğu durumda (bu değişkenlerin ne olduğuna o tarihte
tekrar bakılmalı),

conf = results.conf_int()
pred = [1., 2.0, 0.0, 1]
print np.dot(pred, conf), np.dot(pred, results.params)

[ 43.80446415 52.79105137] 48.2977577583

Yani Demokrat adayın kaybetme şansı daha fazla, her ne kadar kesin bir şey
söylenemezse de, güven aralığının iki ucu da yüzde 50 altında (ya da üstünde)
değil, Hillary Clinton’un işi zor olacaktı, ki kaybetti. Trump ülke genelinde oy
çoğunluğunu kaybetti, ama eyalet bazında kazandı. Demek ki model tahminini
kazanma sinyali olarak almak daha uygun.
Analiz
Model oldukça basit, 3 değişken ile tahmin yapılıyor, fakat bu basitlik aldatıcı ola-
bilir. Modele neyin dahil edildiği yanında neyin dahil edilmediği de önemlidir,
mesela.. ham petrol fiyatı, işsizlik, seçim yılındaki suç oranı, iklim vs kullanılmamış,
sadece bu 3 değişken kullanılmış. Ya da model, Cumhuriyetçiler için ayrı, Demokrat-
lar için ayrı bir tahmin üretmiyor, o an başta hangi parti varsa onun başarısını tah-
min etmeye uğraşıyor. Yani bir bakıma iddiası şu, insanlar aslında başta olan par-
tiye göre oy verirler, bir süre sonra (2 dönem ardından) onu değiştirmeye meyilli
olurlar, ve o anda başta olan başkanın popülaritesi ve genel bir ekonomik perfor-
mansını kullanarak onun partisi hakkında bir tamam / devam kararını verirler.
Bu tür modelcilik yetenek ister. Basitlik zor iş!
Tahmin edilirliğin yüksekliği ve değişkenlerin azlığı hakkında bir diğer yorum;
bu durum aslında o kadar da şaşırtıcı olmamalı belki de, çünkü başkanlık seçimi
son derece kaba hatlı bir karar, tek bir kişi / parti hakkında karar veriliyor, ve
doğal olarak seçim için kullanılan parametreler de oldukça genel. Bir bakıma,
bu tahmin edilirlik iyi olarak ta görülebilir, stabilite, sakin ortamın işareti olarak
algılanabilir. “Vay o taraf ne dedi, bu taraf ne dedi” gibi faktörlerle oylar haldır
huldur inip çıkmıyor, belli genel parametreler ışığında sonuç ta dört ay önceden
oldukça belli (baz veri Haziran sonu itibariyle alınır, seçim Kasım ayında).

13
Model Karşılaştırmak
Bu alanda, mesela gazetelerde, yorumlara rastlanıyor. Bunlardan biri “mevcut
başkanın (incumbent) ikinci dönem için yarışa girerse avantajlı olduğu” söylemidir,
ki üstteki modelin ilk halini keşfeden Abromitz de bunu söylemektedir. Bizim
referans aldığımız model [6] o söylemi biraz değiştirmiş, avantajlı olan yerindeki
başkan değil, dezavantajlı olan 2 dönemden fazla başta kalan parti. İnsanlar 2 veya
daha dönemden fazla başta olan partiyi görevden almaya meyilli oluyor. Tabii
eğer parti yeni başa gelmişse, o zaman dezavantaj olmadığı için bazı durumlarda
“ilk dönem başkan avantajlıymış gibi” durmuş olabilir. Şimdi bu faraziyeyi test
edelim, hangi model daha doğru? Yeni bir veri setinde bu değişikliği test edebil-
iriz,

import statsmodels.formula.api as smf


import pandas as pd
df = pd.read_csv('prez_incumb.csv')
regr = 'incumbent_vote ˜ gdp_growth + net_approval + incumb_prez'
results = smf.ols(regr, data=df).fit()
print results.aic
84.6742088339

AIC sonucu arttı, bu modelin daha kötüleştiği anlamına gelir.


Not: Gayri-safi yurtiçi hasıla (GDP) 2. çeyrekteki artışına bakılıyor. Bu artış
bir sene önceye kıyasla değil (year-over-year) bir önceki çeyreğe göre artıştır
dikkat, ve sonra bu artış, yıl ölçeğine çıkartılır, d artışı diyelim (1 + ).4 − 1 formülü
üzerinden. Yani “her çeyrekte artış d olsaydı, tüm sene artışı nereye gelirdi?”
sorusunun cevabı.
Kaynaklar
[1] Teetor, R Cookbook
[2] The Yhat Blog ,Fitting & Interpreting Linear Models in R, http://blog.yhathq.
com/posts/r-lm-summary.html
[3] Abramowitz, Fasten Your Seat Belts: Polarization, Weak Economy Forecast Very
Close Election, http://www.centerforpolitics.org/crystalball/articles/
abramowitzpolarizationmodel/
[4] Gelman, A., Bayesian Data Analysis
[5] Bayramlı, Books Data, https://github.com/burakbayramli/books/tree/
master/Gelman_BDA_ARM/bda/election
[6] Linzer, R Code, https://github.com/dlinzer/BayesBARUG/blob/master/
Linzer-BayesBARUG.R
[7] Bayramlı, Çok Değişkenli Calculus, Ders 9
[8] Bayramlı, Lineer Cebir, Ders 15
[9] Bayramlı, Bilgisayar Bilim, Yapay Zeka, Regresyon, En Az Kareler

14
[10] Bayramlı, Istatistik, Tahmin Aralıkları
[11] Bayramlı, Istatistik, Güven Aralıkları, Hipotez Testleri
[12] Bayramlı, Istatistik, Tahmin Aralıkları (Prediction Interval)

15
F(X) = U
Başlıktaki matematiğin alt dallarından Simulasyon’un en temel formüllerinden
biri. Basitliği derin bir sonucu gizliyor aslında; ve simulasyon dahil olmak üzere
en az iki istatistiksel yöntemi mümkün kılıyor. Formülü ve mümkün kıldığı iki
yöntemi bu yazıda göreceğiz.
Başlıkta söylemi tam notasyonla vermek gerekirse;

FX (X) ∼ U(0, 1)

Yani, dağılımı her ne olursa olsun, bu dağılımdan gelen bir rasgele değişkenin
değerlerini o dağılımın kümülatif dağılım fonksiyonuna (cdf) geçersek, elde edilen
değerler yeni bir rasgele değişken U(0, 1) olarak, yani birörnek (uniform) olarak
dağılacaktır! Müthiş bir sonuç. Bu metot simülasyonda Ters Transform Metotu
(Inverse Transform Method) olarak geçiyor.
Teori
Diyelim ki X cdf FX ’e sahip surekli rasgele degisken. O zaman FX (X) ∼ U(0, 1).
İspat
Y = FX (X) olsun, ve Y’nin cdf’i G(y). O zaman

G(y) = P(Y 6 y) = P(FX (X) 6 y)

Olasılık operatörü içinde iki tarafa FX ’in tersini uygulayalım, sol tarafta tersi ile
kendisi sonucu fonksiyon kaybolur, geri kalanlar,

= P(X 6 F−1
X (y))

Üstteki ifadeye geldik. Bu ifade de aslında bir cdf hesabı değil midir? Evet. X’in
cdf hesabıdır,

= FX (F−1
X (y)) = y

G(y) = y

Yani y’nin cdf değeri y’nin kendisidir, bu da sadece Y birörnek olarak dağılmışsa
mümkündür [1].
Herhangi Bir Dağılım İçin Rasgele Sayı Üretmek
Bu teorinin rasgele sayı üretmek için nasıl kullanıldığını görmek zor değil. Çünkü
eğer

1
FX (X) = U

ise

X = F−1
X (U)

de doğrudur; O zaman birörnek dağılımdan örneklem alırız, bu örneklem içindeki


sayıları teker teker üretmek istediğimiz dağılımın cdf’inin tersine geçeriz, ve elim-
izdeki sonuçlar otomatik olarak hedeflediğimiz dağılımdan gelen sayılar olur!
Not: Tabii F−1 hesabının yapılabilmesi için bu fonksiyonun bir analitik formu
olması gerekir; bazı durumlarda bu mümkün olmayabilir. Mesela normal (gaus-
sian) dağılımın cdf’inin tersinin analitik formu mevcut değildir. Ya da çok daha
çetrefil, çok boyutlu dağılımlar durumunda da bu mümkün olmayabilir. Bu tür
durumlar için başka yöntemler var, Markov Zinciri Monte Carlo (MCMC) yöntemleri
mesela, ya da daha basit Kabul-Reddet (Accept-Rejection) yöntemi... Dağılımları
simüle etme konusunun arkasında derin bir literatür var [2].
Peki U Nereden Geliyor?
Diyelim ki elimizde tersi alınabilir bir cdf var, ve artık bu dağılımdan sayı üretmek
istiyoruz. Peki cdf tersine verilecek birörnek sayılar nereden gelecek?
Bu durumda sözde rasgele (pseudorandom) sayı üretimi konusuna girebiliriz.
Favori hesap kütüphanemizden birörnek sayılar üretebiliriz, fakat bu kütüphanelerin
ne yaptığını bilmek iyi olur. Kendimiz rasgele sayı üretmek istiyorsak, bunun en
kolay, etkili yolu lineer eşleşikşel üretici (linear congruential generator) kullan-
mak.

Zi = (aZi−1 + c) mod m

a çarpan, m ise genlik (modülüs). mod bildiğimiz gibi modülo matematiğinden


geliyor, 4 mod 2 = 0, 5 mod 3 = 2, vs., bölümden arta kalanların matematiği
yani. Modülo operatörü sayesinde Zi sonuçları 1 ile m − 1 arasında olacaktır.
Çoğunlukla m büyük ve asal bir sayı olarak seçilir. Ri = Zi /m ve Ri ∈ (0, 1).
Amaç bir dizi Ri ’in U(0, 1)’den geliyormuş gibi gözükmesini sağlamak. Bu seri
tabii ki bir süre sonra kendini tekrar edecektir, ama bunun olması için uzun za-
man geçiyorsa bu bizim için iyi bir sonuçtur.
a, c, m’in dikkatli seçilmesi gerekir, ki tekrarsız periyot uzun ve üretilen sayıların
istatistiki kalitesi iyi olsun. Eğer c = 0 ise üstte gösterilene çarpımsal üreteç ismi
veriliyor. Neyse, örnek olarak

Zi = (5Zi−1 + 3) mod 8

kullanalım. Eğer Z0 = 0 ise (ki bu başlangıç noktasına tohum -seed- ismi de


verilir) bir sonraki sayı Z1 = (5Z0 + 3) mod 8 = 3 olur, ve böyle devam edersek,

2
Görüldüğü gibi 8. adımda başa dönmüş olduk, çünkü Z8 = 0. Bu üreteç tam-
periyot üretecidir, yani mod 8 dedik ve tekrar edene kadar 8 tane sayı ürettik.
Genel olarak tam periyot iyi bir şeydir. Eğer

Zi = (5Zi−1 + 1) mod 7

seçseydik, Z0 = 1 ile 1, 6, 3, 2, 4, 6 yani küt diye 6’ya döndük. Bu olmadı, tam


periyot değil. Eğer Z0 = 5 seçseydik sonuç daha da kötü olurdu, bir sonraki sayı
başlangıcın kendisi, yani 5! Bu durumda tek bir tane bile sözde rasgele sayı bile
üretememiş olurduk.
Çok iyi üreteçlerden biri

Zi = 16807Zi−1 mod (231 − 1)

Bu çok hızlı işleyen, tekrar edene kadar 2 milyar (dikkat: milyar) sayıdan daha
fazla sayı üretebilen bir üreteçtir. Kodu altta bulunabilir, 231 − 1 = 2147483647
olduğunu biliyoruz,

def do_unif(ix):
u = (16807*ix) % 2147483647
return u

u = do_unif(1e7)
print u
u = do_unif(u)
print u
u = do_unif(u)
print u

566275534.0
1892860081.0
476634709.0

Biraz daha farklı bir yaklaşım [1], [5, sf. 215],

def do_unif(ix):
k1 = int(ix/127773)
ix = 16807*(ix - k1*127773) - k1*2836
if ix < 0: ix = ix + 2147483647
u = ix*4.656612875e-10 # 1'den kucuk olmasi icin
return ix, u

ix, u = do_unif(1e7)
print u

3
ix, u = do_unif(ix)
print u
ix, u = do_unif(ix)
print u

0.263692594242
0.881431662376
0.22195033226

Eğer tek bir çağrı ile istediğimiz kadar birörnek sayı üretmek istiyorsak,

def unif(size,seed=1e7):
tmp = seed; res = []
for i in range(size):
tmp,u=do_unif(tmp)
res.append(u)
return np.array(res)
print unif(size=10)

[ 0.26369259 0.88143166 0.22195033 0.31923449 0.37412169 0.8632809


0.16214486 0.16868319 0.05836612 0.95940828]

Örnek: Üstel Rasgele Değişken Üretmek


X = F−1 (U) prensibini kullanarak üstel (exponential) dağılımdan gelen rasgele
sayılar üretelim. Birörnek üreticimiz var, üstel dağılım için cdf’in tersini biliy-
oruz, ki bu F−1 (p; λ) = − ln(1 − p)/λ. Tüm bunları biraraya koyarsak,

x = unif(size=1000)
lam = 4.
y = -np.log(1-x) / lam # cdf tersi
f=plt.figure();
plt.hist(y)
plt.savefig('stat_fxu_02.png')

Üstel dağılıma benziyor! İşin iyi tarafı bu üretimi yapmak için tüm öğeleri evde
kendimiz pişirdik. Birörnek rasgele sayıları bile kendimiz üretiyoruz.
Uyum Derecesi ve Düzgünlük Testi (Goodness-of-Fit, Smooth Test)

4
FX (X) = U başka bir açıdan bir “numara” olarak ta kullanılabilir, çünkü teoriye
göre sadece ve sadece FX fonksiyonu hakikaten X’in cdf’i ise ispat geçerli. Bu
gerçeği bir istatistiki test için başlangıç noktası olarak kullanabiliriz; Diyelim ki
elimizde bir X var ve dağılımının ne olduğunu bilmiyoruz. Ama eğer doğru
dağılımı seçmişsek, mesela F0 , F0 (X) bize birörnek sonuç verir, değilse vermez.
O zaman bir tahmini cdf’i birörneklik testiyle birleştirirsek, verinin / rasgele
değişkenin dağılımın ne olduğunu test eden bir istatistiki test bulmuş oluruz [3,
sf. 325].
Birörneklik testi dedik, bunun için zaten bilinen chi kare, K-S uyum derece testi
gibi testleri mi kullansak acaba? Neyman adlı istatistikçi mevcut olanları kullan-
mak yerine özellikle birörnek dağılımına odaklı bir test yaratmaya karar verdi.
Neyman’ın düzgünlük testi (Neyman’s smooth test) birkaç baz fonksiyonunun
toplamından oluşan bir alternatifi (0,1) aralığına gömüyor (embed), ki sıfır hipotezinde
bu gömülü fonksiyon bize birörnek sonuçla aynı sonucu verir, ama birörneklikten
sapma varsa, baz fonksiyonları öyle oluşturulmuştur ki bu sapmanın etkisi düzgün,
sürekli bir şekilde birörneklikten ayrılır (ki testin ismi buradan geliyor). Ayrıca
baz fonksiyonları öyle seçilmiştir ki sıfır hipotezi altında test için bir chi kare
dağılımı elde ederiz, birörnek olmama durumunu bu chi kare dağılımda aykırı
bölgeye düşmek olarak irdeleyebiliriz, ve testimiz bunun üzerinden hesaplanır.
Bu özel fonksiyonlar nelerdir? Onları hj (y) olarak gösterelim, ki j = 1, .., d olsun,
yani d tane baz fonksiyonu var. Neyman’a göre d = 4 yeterlidir (baz fonksiy-
onuna göre değişir tabii, biz alttaki örnekte 5 kullandık). Bu fonksiyonlara bazı
şartlar getiriliyor, öncelikle hj ’ler sabit fonksiyona (yani 1’e) ve birbirlerine dik-
gen (orthogonal) olmalılar. Yani

Z1
hj (y) dy = 0
0

Z1
hk (y)hj (y) dy = 0
0

Ayrıca büyüklüğü (yani karesi) normalize edilmiş olmalı

Z1
hj (y)2 dy = 1 (1)
0

Bu şartları tatmin eden hangi fonksiyonlar vardır? Aklımıza gelen her fonksiyon
tipi üstteki şartlara uymayabilir. Neyman Legendre polinomları denen polinom-
ları kullandı, fakat aslında üstteki şartları yerine getiren

hj (y) = cj cos(2πjy)

ki cj normalizasyon sabiti, gayet rahat kullanılabilir. Dikkat, üstteki sabit hj ’yi

5
bir dağılım haline getirmez, “büyüklük hesabı için” onu normalize eder. Sebebini
birazdan göreceğiz.
Not: Üstteki fonksiyon eğer Fourier serilerini hatırlattıysa bu doğru bir gözlemdir,
böyle bir bağlantı var.. Birbirine dikgen fonksiyonlar özel fonksiyonlar tabii,
Fourier serilerinde bu sebeple kullanılıyorlar, ve dikgenlik lineer cebirde de çok
ortaya çıkar. Kontrol edilmek istenirse 1, cos(2πy), cos(4πy), cos(6πy), .. fonksiy-
onlarının birbirine dikgen olduğu entegral hesabını yapılarak görülebilir.
Devam edelim, (1)’i tatmin etmek için gereken cj ’i hesaplayalım,

Z1
c2j cos(2πy)2 dy = 1
0

Z1
cos(2πy)2 dy = 1/c2j
0

Trigonometrik eşitlik [4, sf 435]

1 + cos 2θ
cos(θ)2 =
2

O zaman,

1 1
cos(2πy)2 = + cos(4πy)
2 2

Entegrale geri koyalım,

Z1
1 1
+ cos(4πy) dy
0 2 2

1
y 1 1
= + sin(4πy) ⇒ = 1/c2j
2 8π 0 2


cj = 2

Bulunan cj her j için geçerli olacaktır.


Düzgünlük testi için önce xi veri noktaları o verinin geldiğini düşündüğümüz
cdf’e geçilir, yani yi = F(xi ) hesaplanır. Ardından,

1X
n
hj = hj (yi )
n i=1

6

Sıfır hipotezi altında ve Büyük Sayılar Kanununa göre hj → 0. n·hj ise Merkezi
Limit Teorisi’ne göre Gaussian’dır, ve bu Gaussian’ın varyansı 1 olacaktır. Demek
ki

X
d
2
2
Ψ =n hj
j=1

hesabı sıfır hipotezi altında χ2d dağılımına sahiptir. hj ’lerin birbirine dikgen seçilmesinin
sebebi şimdi biraz daha açıklık kazanıyor herhalde, dikgen fonksiyonlar ile arasında
hiç korelasyon olmayan standart normaller üretiyoruz, ve bu normallerin toplamının
bize chi kare vermesini bekliyoruz (chi kare için korelasyonsuz standard normal-
lerin toplamı gerekir).
hj → 0 ispatı için sıfır hipotezinde yi ’lerin, ya da ui diyelim, birörnek dağılım
U(0, 1)’dan geldiğini hatırlayalım, yani o zaman hj (U) bir rasgele değişkendir, ve

hj (u1 ) + hj (u2 ) + .. + hj (un )/n

hj ’nin nüfus beklentisine yaklaşır. Peki hj ’in nüfus beklentisi nedir? Bunun için
Z∞
E(hj ) = fU (u)hj (u) du
−∞

fU (u) = 1, ayrıca (0,1) arasına odaklı olduğumuz için,

Z1 Z1 1
sin 2jπu
= hj (u) du = cos 2πju du = =0
0 0 2jπu 0

j ne olursa olsun beklenti sıfır demektir bu. Peki varyans?


Z∞
Var(hj ) = E(h2j ) − E(hj ) = 2
fU (u)h2j (u) du
−∞

üstte E(hj ) = 0 olduğunu bulduk, bu terim üstteki formülde iptal oldu. Ve (1)’ın
de yardımıyla,

Z1
= h2j (u) du = 1
0

Prosedür böylece tamamlandı.


1) cdf ile veriden y = F(x) hesapla

2) hj hesapla, ki bizim seçtiğimiz baz için cj = 2, ardından hj

7
3) En son Ψ2 , sonucu χ2d üzerinde kontrol et.
Örnek
Bir standart normal, bir 4 derece serbestliğe sahip bir Öğrenci t dağılımı, bir de
üstel (exponential) dağılımdan üretilmiş veriyi standart normal olup olmadığına
bakmak için test ettik.

from scipy.stats import norm


from scipy.stats import t
from scipy.stats import expon
s = 200000
np.random.seed(0)
xnorm = norm.rvs(size=s)
xstudent = t.rvs(df=4, size=s)
xexp = expon.rvs(scale=1,size=s)

from scipy.stats import norm


def test(x,d=5,cdf=norm.cdf):
y = cdf(x)
c = np.sqrt(2)
# baz fonksiyonlar
hs = [c*np.cos(2*np.pi*i*x) for i in range(1,d+1)]
res = [xx.mean() for xx in hs]
res = [xx**2 for xx in res]
print len(x)*np.sum(res)

test(xstudent)
test(xnorm)
test(xexp)

from scipy.stats import chi2


dof = 5
print 'chi kare', chi2.ppf(0.95,dof)
12.1463285033
2.20265705473
259.103849686
chi kare 11.0704976935

Görüldüğü gibi Öğrenci t reddedildi, normal kabul edildi, üstel çok ciddi şekilde
reddedildi. Öğrenci t dağılımı normal dağılıma çok benzer bu arada, buna rağmen
arada büyük fark dikkate değer.
Kaynaklar
[1] Goldsman, D., ISyE 6644 - Simulation Lecture, http://www2.isye.gatech.
edu/˜sman/courses/6644/
[2] Ross, Introduction to Probability Models, 10th Edition
[3] Shalizi, Advanced Data Analysis from an Elementary Point of View
[4] Thomas, Thomas’ Calculus, 11th Ed
[5] Schrage, A Guide to Simulation

8
Üstel Kanunlar (Power Laws)
Bir web sitesini bir ayda ziyaret etmiş olan özgün kullanıcı sayısı üzerinden bir
alarm programı yazmak gerekti diyelim. Eğer çok fazla kullanıcı var ise bir ad-
min’e bir email gönderilecek.. Akla gelen çözümlerden aylık kullanıcı sayılarının
ortalamasını alıp 2 ya da 3 standart sapma kadar olan cevapları aykırı değer (out-
lier) olarak kabul etmek ve bu durumlarda alarm çalmak [1, sf. 255]. Çünkü, eh,
veri noktalarının yüzde 99.7’si 3 standart sapma içine düşer değil mi?
Burada gözardı edilen nokta şudur: verinin yüzde 99.7’si 3 standart sapma içine
düşer eğer veri Gaussian olarak dağılmış ise. Ayrıca ortalama hesabı da problemli,
burada ilk akla gelebilecek Merkezi Limit Teorisi üzerinden örneklem ortala-
ması gerçek ortalamaya yaklaşacağı, ki bu çoğu dağılım için doğrudur, fakat bazı
dağılımlar üzerinde Merkezi Limit Teorisi işlemez! Güç Kanunları ile istatistik
biliminin sınırlarına geliyoruz - gerçek dünyadan önümüze atılan veriler artık
sıkça bir şekilde normal dışı verileri içerebiliyor, ve bu durumlara hazır olmamız
lazım.
Üstte bahsettiğimiz senaryo için aslında elimizde veri var (pek çok ay için). Verinin
histogramına bakalım,

import pandas as pd
dfvis=pd.read_csv('visits.csv',header=None,sep='\t',index_col=0)
visits = np.array(dfvis[1])

dfvis.hist(bins=80)
plt.ylim([0,50])
plt.savefig('stat_powerlaw_05.png')

Görüldüğü gibi bazı değerlerden aşırı çok var, bazılarından neredeyse yok. Aşırı
değerler her iki uçta da gözüküyor, büyük olanlardan daha az var, evet, ama
oradaki yoğunluk dikkate alınmaz seviyede de değil. Bu arada eğer y eksenini
ufaltmasaydık aşırı değerler haricinde kalan değerler üstteki kadar bile gözükmeyecekti.
Olasılık yoğunluk fonksiyonu (probability density function),

1
p(x) = Cx−α

C bir normalizasyon sabiti, ki λ > 0 olmak üzere, dağılımın parametresi. Bu


dağılıma üstel kanun (power law) ismi verilir. Zıpf, ya Pareto dağılımı üstteki
formülün farklı şekilde temsilinden ibaret.
Her özgün λ farklı bir üstel kanuna işaret eder. Mesela p(x) = C/x2 bir ustel
kanun olabilir! Bildigimiz x2 ’yi baz alan bir dağılımdan bahsediyoruz yani! α >
1 olmalıdır, sebebini altta göreceğiz. Doğadaki çoğu üstel kanun 2 < α < 3
arasındadır. Beklentiyi hesaplayalım,
Z∞ Z∞
E[X] = xp(x) dx = C x−α+1 dx
xmin xmin

 ∞
C −α+2
= x
2−α xmin

Bu ifadenin α 6 2 için sonsuza gittiğine dikkat edelim, bahsettiğimiz gariplik


burada... xmin ’in ne olduğunu birazdan göreceğiz.
Log-Log Grafikleri
Üstel kanun dağılımlarının ilk kez histogram log-log skalasında grafiklenince
keşfedildiği düşünülmektedir, bir üstel kanun sürecinden gelen veriyi anlamaya
çalışırken hem p(x) hem x’in log’u alınmıştır, ve bu grafik negatif eğimli düz çizgi
olarak ortaya çıkmıştır. Yani

ln p(x) = −α ln x + c (1)

Üstteki yaklaşımla grafiği nasıl oluşturuz? Bunun için hist çağrısından histogram
grafiğini değil, histogramdaki kutucukların üç noktalarını düz veri olarak al-
mamız lazım, ki bu değerler x değerlerimizi oluşturacak, sonra onların normalize
edilmiş değerlerini almamız gerekiyor [4], bu değerler de ln p(x) olacak. Grafik-
lemeden önce elle log almamıza gerek yok, grafik rutinine skalayı log bazında
ayarlamasını söylememiz yeterli, xscale,yscale çağrıları ile bunu yapabiliriz.

def plot_power(data):
hst = plt.hist(data, normed=True,bins=1000)
f=plt.figure() # histogram halinden cik
x = hst[1][:-1]; y = hst[0]
plt.plot(x, y,'o')
plt.xscale('log')
plt.yscale('log')

plot_power(visits)
plt.title('Ziyaretler')
plt.ylim(1e-5,1e-3)
plt.savefig('stat_powerlaw_04.png')

2
Düz çizgiye benzer bir şekil ortaya çıktı, negatif eğimli, demek ki bir üstel kanun
mümkün.
Üstel kanunu yoğunluk formülüne nasıl erişiriz? Başlangıç önceden gösterdiğimiz
formül olmak üzere,

ln p(x) = −α ln x + c

Eger ln(c) = C dersek,

ln p(x) = −α ln x + ln C

= ln Cx−α

ve iki tarafı e üzerine alırsak,

p(x) = Cx−α

Olasılık yoğunluk fonksiyonuna eriştik.


xmin Hesabı
Dikkat edilirse Cx−α fonksiyonu x → 0 iken sonsuza gidiyor (diverge), demek
ki her x > 0 için yoğunluk fonksiyonu geçerli değildir. O zaman üstel kanunun
geçerli olduğu bir alt sınır olmalı. Bu alt sınıra xmin diyeceğiz.
Artık normalizasyon sabiti C’yi hesaplayabiliriz,
Z∞
Cx−α = 1
xmin

 ∞
C −α+1
x =1
(−α + 1) xmin

3
 ∞
C −α+1
x =1
(1 − α) xmin

Görülebileceği üzere bu formül sadece α > 1 için anlamlıdır, diğer durumlarda


sonsuzluğa gider. Demek ki üstel kanun dağılımı için α > 1 şartını da getirmemiz
gerekiyor. Devam edelim,

C
x−α+1 =1
(−α + 1) min

C = (α − 1)xα−1
min

C ile beraber ve bazı düzeltmeler ardından p(x) bazen şöyle gösteriliyor [5],

 −α
α−1 x
p(x) =
xmin xmin

α, xmin ’i Kestirmek (Estimation)


(1) formülüne bakarak bazıları lineer regresyon kullanarak xmin hesabı yapa-
bileceğini düşünüyor. Yani grafiğe bakılıyor, eh ortada lineer bir durum var, re-
gresyon ile eğim için bir tahmin elde ederim ve bu tahmini α için kullanırım.

import statsmodels.formula.api as smf


hst = plt.hist(visits, normed=True,bins=1000)
visitx = hst[1][:-1];visity = hst[0]
yy = np.log(visity);xx = np.log(visitx)
yy = yy[visity>0];xx = xx[visity>0]
df = pd.DataFrame([yy,xx]).T
df.columns = [['y','x']]
results = smf.ols('y ˜ x', data=df).fit()
print 'alpha', -1 * results.params[1]
print 'kesi', np.exp(results.params[0])

alpha 0.540551473071
kesi 0.00241514844497

Bu basit yöntemin, ne yazık ki, çok ciddi problemleri var. Bu metotun niye kul-
lanılmaması gerektiği [3, sf. 31]’de bulunabilir.
Alternatif yöntem şöyle; önce α için hızlı çalışan bir tahmin edici mevcut, bunu
görelim; Maksimum olurluk üzerinden,

Yn
α−1

xi
−α
p(x; α) =
i=1
xmin xmin

Maksimum log olurluk,

4
Yn
α−1

xi
−α
ln p(x; α) = ln
i=1
xmin xmin

X
n
α−1

xi
−α
= ln
i=1
xmin xmin

X
n 
xi

= ln(α − 1) + ln xmin − α ln
i=1
xmin

X
n
xi
= n ln(α − 1) + n ln xmin − α ln
i=1
xmin

Maksimum değer için α’ya göre türevi alıp sıfıra eşitleriz ve çözeriz, ln(α − 1)’in
türevini hatırlayalım bu arada,

import sympy
alpha = sympy.symbols('alpha')
print sympy.diff(sympy.log(alpha-1))

1/(alpha - 1)

n X n
xi
= − ln =0
(α − 1) i=1 xmin

n X n
xi
= ln
(α − 1) i=1
xmin

X
n −1
(α − 1) xi
= ln
n i=1
xmin

Xn −1
xi
α̂ = 1 + n ln
i=1
xmin

Fakat tahmin edicinin hesabı için xmin ’i bilmek gerekiyor. Bir tavuk-yumurta
problemi var, α̂ için xmin gerekli, ama xmin ’in kendisi de bilinmiyor.
O zaman üstteki tahmin ediciyi şöyle kullanırız; verideki her noktayı potan-
siyel bir xmin ’mis gibi alırız (ve bu nokta altındaki hiçbir noktayı dikkate al-
mayız, bu alt sınırı bunun için seçtik), ve bu nokta için yukarıdaki formül ile
α̂’yi hesaplarız, sonra elde ettiğimiz xmin , α̂ ikilisini kullanarak (artık özgün bir
üstel kanun dağılımımız var), bu dağılım ile veri arasındaki uyum derecesini
Kolmogorov-Şmirnov testi ile hesaplarız. Elimizdeki n veri noktası için n tane
hesap elde ederiz, ve raporlanan mesafeler arasından en ufak olanını seçeriz, ve

5
bu mesafeye tekabül eden xmin , α̂ ikilisini optimal parametreler olarak seçeriz.
Altta örneği gösterilen powerlaw adlı paket [6] tam da bunu yapıyor. Ziyaret verisi
üzerinde işletelim,

import powerlaw
fitvis = powerlaw.Fit(visits, discrete=False)
print 'xmin', fitvis.xmin, 'alpha', fitvis.alpha

xmin 34.0 alpha 1.57060706124

Hesaplanan α değerinin lineer regresyondan gelen hesaptan ne kadar farklı olduğuna


dikkat!
powerlaw paketine, biraz önce yaptığı tahminler üzerinden, üstel (exponential)
dağılımın mı, üstel kanun dağılımının mı (isimler birbirine çok benziyor doğru)
bu veri için daha olası olduğunu sorabiliriz, daha doğrusu her iki dağılım için
Kolmogorov-Şmirnov testini işletiriz,

print fitvis.exponential.KS()
print fitvis.power_law.KS()

0.487151691713
0.0312634791749

Üstel kanun görüldüğü gibi daha olası (p-değer 0.05 altında). Bir olasılık hesabını
da elle yapalım,

x0 = 1e2
p = x0**-fitvis.alpha
C = (fitvis.alpha-1) * fitvis.xmin**(fitvis.alpha-1)
print p*C

0.00308315744794

Bazı farklı veriler üzerinde aynı hesapları görelim. Mesela 2003 senesindeki en
zengin 300 Amerikalının net varlıklarının dağılımı.

import powerlaw
dfwl=pd.read_csv('wealth.dat',header=None)
wealth=np.array(dfwl)[:,0]
fitwl = powerlaw.Fit(wealth, discrete=True)
print 'xmin', fitwl.xmin, 'alpha', fitwl.alpha
print 'K-S testi', fitwl.power_law.KS()

xmin 1100000000.0 alpha 2.40575306524


K-S testi 0.0432807151071

plot_power(wealth)
plt.savefig('stat_powerlaw_03.png')
plt.hold(False)

6
Dikkat, çoğunlukla bu konularda araştırma yapanlar zengin, fakir herkesi kap-
sayan bir ölçüm üzerinden (bu konulara ilk bakan Pareto öyle yapmıştı) tüm
kazancın üstel kanunu takip ettiğini söylerler, ki bu doğrudur. Üstteki sonuç,
bunun üstüne, en zengin 400 kişinin kendi arasında bile üstel kanunun işlediğini
söylemektedir. Yani zenginlik öyle dengesiz dağılan bir şeydir ki, en zengin 400
içinde çoğunluk en tepedekilere göre daha fakirdir!
Devam edelim: Herman Melville adlı yazarın ünlü Moby Dick romanındaki özgün
kelimelerin kullanılma frekansının dağılımı,

import powerlaw

dfwords=pd.read_csv('words.txt',header=None)
words=np.array(dfwords)[:,0]
fitw = powerlaw.Fit(words, discrete=True)

plot_power(words)
plt.ylim(1e-6,1e-3)
plt.savefig('stat_powerlaw_02.png')

Bu arada powerlaw paketinin bazı grafikleme özellikleri de var. Veriyle beraber


tahmin edilen −α (düz çizgi olarak), üstel dağılım (kırmızı çizgi) ve üstel kanun
uyumunu aynı grafikte gösterebiliriz.

7
f = plt.figure()
fitw.power_law.plot_pdf(linestyle='--', color='g')
plt.hold(True)
fitw.exponential.plot_pdf(linestyle='--', color='r')
plt.hold(True)
fitw.plot_pdf(color='b', linewidth=2)
plt.xlim(1e2,1e4)
plt.ylim(1e-8,1e-4)
plt.savefig('stat_powerlaw_01.png')
plt.hold(False)

print 'Kolmogorov-Smirnov testi', fitw.power_law.KS()

Kolmogorov-Smirnov testi 0.00922886388026

Kaynaklar
[1] Janert, Data Analysis with Open Source Tools
[2] Shalizi, Advanced Data Analysis from an Elementary Point of View
[3] Causet, Power-Law Distributions in Empirical Data
[4] Bayramlı, Histogram Numaralari, https://burakbayramli.github.io/
dersblog/sk/2015/10/histogram-numaralari.html
[5] Newman, Power laws, Pareto distributions and Zipf’s law
[6] Alstott, powerlaw: A Python Package for Analysis of Heavy-Tailed Distributions

8
Tahmin Aralıkları (Prediction Interval)
Lineer Regresyon yazısında regresyon katsayıları β’yi veriden hesaplamayı öğrendik.
Bu bir anlamda alttaki denklemde verili y, A ile geri kalanları tahmin etmektir.

y = Aβ + 

ki

 ∼ Normal(0, σ2 I)

Yani katsayıların A ile çarpımları artı gürültü (σ ile parametrize edilmiş bir Gaus-
sian üzerinden) bu sonucu verecektir. Tahmin edici,

β̂ = (AT A)−1 AT y

olarak bilinir. Bu formülü pek çok yazıda gördük, mesela [3]. O zaman

β̂ = (AT A)−1 AT (Aβ + )

β̂ = β + (AT A)−1 AT  (1)

Eğer E(β̂) hesaplamak istersek,

E(β̂) = E(β + (AT A)−1 AT )

Fakat E() = 0 olduğu için üstteki hemen E(β̂) = β haline geliyor. Vektör rasgele
değişkenler üzerinde varyans, ya da kovaryans hesabını daha önce görmüştük,
bu hesabı β̂ üzerinde uygularsak,

Var(β̂) = E (β̂ − E(β̂))(β̂ − E(β̂))T


 

Biraz önce E(β̂) = β demiştik, o zaman üstteki

Var(β̂) = E (β̂ − β)(β̂ − β)T


 
(2)

olur. Üstte β̂ − β var, bu (1)’den β çıkartılıyor anlamına gelir, o zaman oradaki β


kaybolur, geriye

β̂ − β = β + (AT A)−1 AT  − β

1
= (AT A)−1 AT 

Üstteki ifadeyi (2) içine koyalım,


 
T −1 T
 T −1 T
T
E (A A) A  (A A) A 

Beklenti içini açalım,

= E[(AT A)−1 AT T A(AT A)−1 ]

Tersi işleminin devriği kayboldu çünkü AT A simetriktir, onun tersi de simetriktir,


simetrik matrisin devriği yine kendisidir.

= (AT A)−1 AT AE[T ](AT A)−1

= E[T ](AT A)−1

Var(β̂) = σ2 (AT A)−1 (3)

Yeni bir tahmin a için

ŷa = aT β̂

β yerine β̂ kullandık. Şimdi tüm ifadenin varyansına bakalım,

Var(ŷa ) = Var(aT β̂)


 
Bundan önce Var(aT β̂) = aT (AT A)−1 a σ2 olduğunu ispatlamak lazım, [1, sf
617] olduğu gibi - öncelikle Var(aT β̂) formülünde a ve β̂ nin birer vektör olduğunu
hatırlayalım, o zaman aT β̂ bir noktasal çarpımdır, yani a1 β̂1 + ... + an β̂n . Demek
ki

Var(aT β̂) = Var(a1 β̂1 + ... + an β̂n )

Şimdi [4] bölümünden hatırlayacağımız üzere,

X
Var(X1 + .. + Xn ) = Var(X1 ) + .. + Var(Xn ) + 2 Cov(Xi , Xj )
i<j

2
Bizim elimizde ai β̂i ’lar var tabii, o zaman

X
Var(aT β̂) = Var(a1 β̂1 ) + .. + Var(an β̂n ) + 2 Cov(ai β̂i , aj β̂j )
i<j

Var(ai β̂i ) = a2i Var(β̂i )

olduğunu hatırlayalım, o zaman iki üstteki

X
= a21 Var(β̂1 ) + .. + a2n Var(β̂n ) + 2 Cov(ai β̂i , aj β̂j )
i<j

Peki Var(β̂i ) nedir? (3)’u hatırlayalım, buradaki matris çarpımından hareketle,


her Var(β̂i ) = cii σ2 diyebiliriz ki cii , (AT A)−1 matrisinin (köşegeninde bulunan)
bir öğesidir.

X
= a21 c11 σ2 + .. + a2n cnn σ2 + 2 Cov(ai β̂i , aj β̂j )
i<j

Aynı şekilde Cov(ai β̂i , aj β̂j ) = 2ai aj cij σ2 diyebiliriz,

X
= a21 c11 σ2 + .. + a2n cnn σ2 + 2 ai aj cij σ2
i<j

X
= a21 c11 + .. + a2n cnn + 2 ai aj cij σ2
 
i<j

 
Üstteki ifadeyi rahat bir şekilde aT (AT A)−1 a σ2 olarak yazabiliriz.
Şimdi güven aralığı yaratmanın zamanı geldi. Hatırlayalım ki β̂1 , β̂2 , , . tahmin
edicilerinin kendileri birer rasgele değişkendir, ve bu değişkenler Normal dağılıma
sahiptirler. O zaman aT β̂ da normal olarak dağılmıştır ve bu dağılımın beklen-
tisinin E(aT β̂) = aT β olduğunu biliyoruz (dikkat eşitliğin sağında şapkasız β
var). O zaman “gerçek” β için bir güvenlik aralığı oluşturmak için aT β̂ − aT β’nin
da Normal olarak dağılmasının zorunlu olduğundan hareketle,

aT β̂ − aT β aT β̂ − aT β
Z= q = p
Var(aT β̂) σ aT (AT A)−1 a

Böylece bir standart normal yarattık, ve bu formülü daha önce güvenlik aralığı
için yaptığımız gibi düzenlersek,

3
p
aT β̂ ± zα/2 σ aT (AT A)−1 a

Daha önce gördüğümüz gibi σ yerine S koyabiliriz, o zaman Öğrenci T dağılımı


elde ederiz (yazının sonunda σ, S teorik bağlantısının sebepleri bulunabilir),

aT β̂ − aT β
T= p
S aT (AT A)−1 a

ki bu güven aralığı

p
aT β̂ ± tα/2 S aT (AT A)−1 a

olarak hesaplanabilecektir, T dağılımının serbestlik derecesi n − (k + 1)’dir, ki n


eldeki veri nokta sayısı, k işe kaç β değişkeninin olduğudur.
Örnek
Basit bir örnek üzerinde görelim ([1, sf 620]’den alındı),

import pandas as pd
import numpy as np
df = pd.read_csv('11.1.csv',sep=' ')
print df.head()
import statsmodels.formula.api as smf
results = smf.ols('y ˜ x', data=df).fit()
mse = np.sum(results.resid**2) / (len(df)-2)
s = np.sqrt(mse)
print 'mse', mse, 's', s
print results.summary()

x y
0 -2 0
1 -1 0
2 0 1
3 1 1
4 2 3
mse 0.366666666667 s 0.605530070819
OLS Regression Results
==============================================================================
Dep. Variable: y R-squared: 0.817
Model: OLS Adj. R-squared: 0.756
Method: Least Squares F-statistic: 13.36
Date: Mon, 11 May 2015 Prob (F-statistic): 0.0354
Time: 17:26:07 Log-Likelihood: -3.3094
No. Observations: 5 AIC: 10.62
Df Residuals: 3 BIC: 9.838
Df Model: 1
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [95.0% Conf. Int.]
------------------------------------------------------------------------------

4
Intercept 1.0000 0.271 3.693 0.034 0.138 1.862
x 0.7000 0.191 3.656 0.035 0.091 1.309
==============================================================================
Omnibus: nan Durbin-Watson: 2.509
Prob(Omnibus): nan Jarque-Bera (JB): 0.396
Skew: -0.174 Prob(JB): 0.821
Kurtosis: 1.667 Cond. No. 1.41
==============================================================================

import numpy.linalg as lin


A = df[['x']]
A['intercept'] = 1.
A = A[['intercept','x']]
ATA_inv = lin.inv(np.dot(A.T,A))
print ATA_inv
beta_hat = np.array(results.params)
a = np.array([[1,1]]).T

[[ 0.2 0. ]
[ 0. 0.1]]

pm = np.dot(np.dot(a.T, ATA_inv),a)[0][0]
pred = np.dot(a.T,beta_hat)[0]
print pm, pred

0.3 1.7

from scipy.stats.distributions import t


t95_val = t.ppf(0.95,len(df)-2)
print 'tval', t95_val
print t95_val*s*pm
print 'Yuzde 90 guven araligi', \
(pred - np.array([1,-1])*t95_val*s*np.sqrt(pm))

tval 2.3533634348
0.427509698202
Yuzde 90 guven araligi [ 0.91947765 2.48052235]

Görüldüğü gibi [1, sf 620] ile aynı sonucu aldık.


Başkanlık Yarışı Tahminleri
Daha önce [5] yazısında gördüğümüz 2016 başkanlık yarışı tahminini şimdi bu
yeni yöntemimizi kullanarak yapalım.

import statsmodels.formula.api as smf


import pandas as pd
df1 = pd.read_csv('../stat_linreg/prez.csv',sep=',')
regr = 'incumbent_vote ˜ gdp_growth + net_approval + two_terms'
results1 = smf.ols(regr, data=df1).fit()
A1 = df1.copy()
A1['intercept'] = 1.
A1 = A1[['intercept','gdp_growth','net_approval','two_terms']]

5
import numpy.linalg as lin
from scipy.stats.distributions import t
t975_val1 = t.ppf(0.975,len(df1)-2)
beta_hat1 = np.array(results1.params)
ATA_inv1 = lin.inv(np.dot(A1.T,A1))
a1 = np.array([[1., 2.0, 0., 1]]).T
pm1 = np.dot(np.dot(a1.T, ATA_inv1),a1)[0][0]
pred1 = np.dot(a1.T,beta_hat1)[0]
mse1 = np.sum(results1.resid**2) / (len(df1)-2)
s1 = np.sqrt(mse1)
print 'Yuzde 95 Guven Araligi', \
(pred1 - np.array([1,-1])*t975_val1*s1*np.sqrt(pm1))
Yuzde 95 Guven Araligi [ 46.95198025 49.64353527]

Yani Demokratların kazanma şansı neredeyse hiç yok gibi. Önceki başkanlık
yarışı tahmini katsayıların güven aralıklarını kullanmıştı; şimdi nihai tahminin
güven aralığına baktık. Aradaki fark şudur - katsayıların güven aralıklarını kul-
landığımızda onları en kötüleri birarada ve en iyileri birada olacak şekilde yanyana
kullanmış olduk; bu tür bir kullanım bu katsayıların arasındaki korelasyonu dikkate
almaz, çünkü, belki bir katsayı X’in en kötümser olduğu noktada katsayı Y daha
iyimser bir tahminde bulunacaktır, çünkü aradaki bağlantı böyledir...? Bu du-
rumlar ilk kullanımda yakalanamazdı. Bu sebeple ilk yöntemle hesaplanan güven
aralığı ikincisine nazaran daha geniş olacaktı, ki bunun olduğunu gördük.
σ, σ̂, S İlişkileri
Öncelikle mümkün bazı notasyonel karışıklığı düzeltmeye uğraşalım; kitaplarda
σ, σ̂ kullanımı tek boyutlu verinin nüfus standart hatası ve onun tahmin edicisi
(estimatör) için de kullanılıyor. Bu yazıda bu farklı, bu yazıdaki σ bir lineer mod-
elin hatasını temsil eden σ.
Bu tür bir σ’nin tahmin edicisi σ̂ şu şekilde tanımlı,

1X
n
2
σ̂ = (Yi − Ŷi )2
n i=1

İspat için [2, sf 557-558]. Fakat üstteki kodda n − 2 kullanımı görüyoruz, bu


nereden geliyor? Bunun için n/(n − 2)σ̂2 formülünün σ2 için bir yansız tahmin
edici (unbiaşed estimatör) olduğunu bilmemiz lazım. İspat için bakınız [2, sf 560].
Yansızlık tanımı için Örneklem Dağılımları yazısı.
Tüm bunları biraraya koyarsak, Yi − Ŷi regresyondan bize döndürülen resid
dizini, ve bu “artıkların” karelerini alıp toplayınca (ki artıklar tahmin ile gerçek
verinin arasındaki fark), ve onları n − 2 ile bölünce σ2 için bir yansız tahmin edici
S2 ’yi nasıl elde ettiğimizi görebiliriz herhalde.
Ek
β̂ Dağılımı
Lineer regresyonu Y = Xβ +  olarak modellediğini farzedelim, ki X, Y, β çok

6
boyutlu değişkenler / matris / vektör ve  ∼ N(0, σI) yani cok boyutlu bir Gaus-
sian. Soru su: Acaba β’nın tahmin edicisi β̂’nin dağılımı nedir?
Tahmin edici hesabi

β̂ = (XT X)−1 XT Y

olduğunu biliyoruz. Y’yi yerine koyarsak,

= (XT X)−1 XT (Xβ + )

T  
=
(XX)−1XT Xβ + (XT X)−1 XT 

= β + (XT X)−1 XT 

Bir yan not, biliyoruz ki çok boyutlu Gaussian mesela G ∼ N(φ, ρ)’a BG + A
şekilde ilgin (affine) transform uygulayınca sonuç N(φ+A, BρBT ) oluyor. Burada
 bir çok boyutlu Gaussian. O zaman üstteki transformu hesaplayabiliriz. β
toplamı basit, esas iki taraftan (XT X)−1 XT ve onun devriği ile çarpılan standart
sapmaya ne olacak ona bakalım,

(XT X)−1 XT σX(X−1 X−T )T

= (XT X)−1 XT σXX−1 X−T

= σ(XT X)−1

Sonra β toplamını hatırlarız, yani β̂ ∼ N(β, σ(XT X)−1 ) olarak dağılmıştır, demek
ki katsayılarımızın regresyon tahmini “gerçek” katsayılar etrafında merkezlenen
bir Gaussian’dır.
Kaynaklar
[1] Wackerly, Mathematical Statistics, 7th Edition
[2] Larsen, Introduction to Mathematical Statistics and Its Applications, 5th Edition
[3] Bayramli, Lineer Cebir, Ders 15,16
[4] Bayramli, Istatistik, Beklenti, Kovaryans ve Korelasyon
[5] Bayramli, Istatistik, Lineer Regresyon

7
Lojistik Regresyon (Logistic Regression)
Lojistik regresyon normal regresyonun θT x olarak kullandığı ağırlıklar (katsayılar)
ile verinin çarpımını alır ve ek bir filtre fonksiyonundan geçirerek onları 0/1
değerleri bağlamında bir olasılığa eşler. Yani elimizdeki veri çok boyutta veri
noktaları ve o noktaların 0 ya da 1 olarak bir ”etiketi” olacaktır. Mesela

from pandas import *


df = read_csv("testSet.txt",sep='\t',names=['x','y','labels'],header=None)
df['intercept']=1.0
data = df[['intercept','x','y']]
labels = df['labels']
print df[['x','y','labels']][:10]

x y labels
0 -0.017612 14.053064 0
1 -1.395634 4.662541 1
2 -0.752157 6.538620 0
3 -1.322371 7.152853 0
4 0.423363 11.054677 0
5 0.406704 7.067335 1
6 0.667394 12.741452 0
7 -2.460150 6.866805 1
8 0.569411 9.548755 0
9 -0.026632 10.427743 0

Görüldüğü gibi veride x, y boyutları için etiketler (labels) verilmiş. Lojistik re-
gresyon bu veriyi kullanarak eğitim sonrası θ’ları elde eder, bunlar katsayılarımızdır,
artık bu katsayıları hiç görmediğimiz yeni bir veri üzerinde 0/1 etiketlerinin tah-
minini yapmak için kullanabiliriz.
Filtre fonksiyonu için kullanılan bir fonksiyon sigmoid fonksiyonudur, g(x) is-
mini verelim,

ex
g(x) =
1 + ex

Bu nasıl bir fonksiyondur, kabaca davranışını nasıl tarif ederiz? Cebirsel olarak
bakarsak, fonksiyon öyle bir durumda ki ne zaman bir x değeri geçersek, bu
değer ne kadar büyük olursa olsun, bölendeki değer her zaman bölünenden 1
daha fazla olacaktır bu da fonksiyonun sonucunun 1’den her zaman küçük ol-
masını garantiler. Çok küçük x değerleri için bölüm sonucu biraz daha büyük
olacaktır tabii, vs.
Daha temiz bir ifade için bölen ve bölüneni e−x ile çarpalım,

ex e−x
g(x) =
e−x + ex e−x

1
g(x) =
1 + e−x

1
Sigmoid fonksiyonun ”-sonsuzluk ile +sonsuzluk arasındaki değerleri 0 ve 1 arasına
eşlediği / indirgediği (map)” ifadesi de litaratürde mevcuttur.

def sigmoid(arr):
return 1.0/(1+exp(-arr))

x = np.array(arange(-10.0, 10.0, 0.1))


plt.plot(x,sigmoid(x))
plt.savefig('stat_logit_02.png')

Üstteki grafiğe bakınca katsayılarla çarpım, toplam ardından sonucun niye bu


fonksiyona verildiğini anlamak mümkün. Sigmoid’in 0 seviyesinden 1 seviyesine
zıplayısı oldukça hızlı ve x kordinatı bağlamında (ve 0.5’ten küçük y’ye eşlenen)
sıfır öncesi bölgesi, aynı şekilde sıfır sonrası (ve 0.5’ten büyük y’ye eşlenen) bölgesi
oldukça büyük. Yani bu fonksiyonu seçmekle veriye katsayılarla çarpılıp 0 ya da
1 bölgesi altına düşmesi için oldukça geniş bir şans veriyoruz. Böylece veriyi iki
parçaya ayırmak için şansımızı arttırmış oluyoruz.
Peki sigmoid fonksiyonu bir olasılık fonksiyonu (dağılımı) olarak kullanılabilir
mi? Entegralini alalım, ve -/+ sonsuzluklar üzerinden alan hesabı yapalım, sonu-
cun 1 çıkması gerekli,

import sympy
x = sympy.Symbol('x')
print sympy.integrate('1/(1+exp(-x))')
x + log(1 + exp(-x))

Daha temizlemek için

x + ln(1 + e−x )

x ifadesi aynı zamanda suna eşittir x = ln(ex ). Bu ifade bize kolaylık sağlayacak
böylece,

ln ex + ln(1 + e−x )

2
diyebiliriz. Doğal log’un (ln) çarpımları toplamlara dönüştürdüğünü biliyoruz,
bunu tersinden uygulayalım,

ln(ex · 1 + ex e−x )

ln(ex + 1) = ln(1 + ex )

print log (1+exp(-inf))


print log(1+exp(inf))

0.0
inf

Demek ki fonksiyon bir olasılık dağılımı olamaz, çünkü eğri altındaki alan son-
suz büyüklüğünde. Aslında bu fonksiyonun kümülatif dağılım fonksiyonu (cu-
mulative distribution function -CDF-) özellikleri vardır, yani kendisi değil ama
türevi bir olasılık fonksiyonu olarak kullanılabilir (bu konumuz dışında). Her
neyse, sigmoid’in bir CDF gibi hareket ettiğini g’nin 0 ile 1 arasında olmasından
da anlıyoruz, sonuçta CDF alan demektir (yoğunluğun entegrali) ve en üst değeri
1 demektir, ki bu CDF tanımına uygundur.
Şimdi elimizde olabilecek k tane değişken ve bu değişkenlerin bilinmeyen kat-
sayıları için 0 ve 1’e eşlenecek bir regresyon oluşturalım. Diyelim ki katsayılar
θ0 , .., θk . Bu katsayıları değişkenler ile çarpıp toplayarak h(x)’e verelim, (0/1)
çıkıp çıkmayacağı katsayılara bağlı olacak, verideki etiketler ile h(x) sonucu arasında
bir bağlantı kurabilirsek, bu bize katsayıları verebilir. Bu modele göre eğer θ’yi
ne kadar iyi seçersek, eldeki veri etiketlerine o kadar yaklaşmış olacağız. Şimdi
sigmoid’i katsayılarla beraber yazalım,

1
hθ (x) = g(θT x) =
1 + e−θT x

”Veriye olabildiğince yaklaşmak için en iyi α’yi bulmak” sözü bize maksimum
olurluk (maximum likelihood) hesabını hatırlatmalı. Bu hesaba göre içinde bilin-
meyen α’yi barındıran formülün üzerinden tüm verinin sonuçlarının teker teker
birbiri ile çarpımı olabildiğince büyük olmalıdır. Bu ifadeyi maksimize edecek α
veriye en uygun α olacaktır.
Şimdi her iki etiket için ve sigmoid’i kullanarak olasılık hesaplarını yapalım,

P(y = 1|x; θ) = hθ (x)

P(y = 0|x; θ) = 1 − hθ (x)

3
Not: Olasılık değerleri (büyük P(·) ile) ve CDF fonksiyonları olurluk hesabında
kullanılabilir. P(·) ile CDF bağlantısı var, P(X < x) gibi kümülatif alansal hesapların
CDF üzerinden gerçekleştirilebildiğini hatırlayalım.
Devam edelim, hepsi bir arada olacak şekilde yanyana koyarsak ve sonuca, y’yi
doğru tahmin edip etmediğimizin ölçümünü de eklersek,

p(y|x; θ) = (hθ (x))y (1 − hθ (x))1−y

Olurluk için tüm veri noktalarını teker teker bu fonksiyona geçip sonuçlarını
çarpacağız (ve verilerin birinden bağımsız olarak üretildiğini farzediyoruz), eğer
m tane veri noktası var ise

Y
m
i i
L(θ) = (hθ (xi ))y (1 − hθ (xi ))1−y
i=1

Eğer log’unu alırsak çarpımlar toplama dönüşür, işimiz daha rahatlaşır,

l(θ) = log L(θ)

X
m
= yi log((hθ (xi ))) + (1 − yi ) log((1 − hθ (xi )))
i=1

İşte bu ifadenin maksimize edilmesi gerekiyor.


Ama daha fazla ilerlemeden önce bir eşitlik ve bir türev göstermemiz gerekiyor.
Önce eşitlik

1 − g(z) = g(−z)

İspat

1 1 + e−z − 1
1− =
1 + e−z 1 + e−z

e−z 1
−z
=
1+e 1 + ez

Hakikaten son eşitliğin sağ tarafına bakarsak, g(−z)’yi elde ettiğimizi görüyoruz.
Şimdi türeve gelelim,

d 1
g 0 (z) =
dz 1 + e−z

4
Ispat

1
= −z 2
(e−z )
(1 + e )

e−z türevinden bir eksi işareti geleceğini beklemiş olabiliriz, fakat hatırlanacağı
üzere

d 1 −1
=
dx 1 + x (1 + x)2

Yani eksiler birbirini yoketti. Şimdi iki üstteki denklemin sağ tarafını açalım

1 e−z
=
1 + e−z 1 + e−z

1 1
=
1 + e 1 + ez
−z

Çarpımda iki bölüm var, bölümler g(z) ve g(−z) olarak temsil edilebilir, ya da
g(z) ve 1 − g(z),

= g(z)(1 − g(z))

Bu bağlamda ilginç bir diğer denklem log şansı (log odds) denklemidir. Eğer ilk
baştaki denklemi düşünürsek,

ez
p = P(y = 1|x; θ) = g(z) =
1 + ez
Bu denklem 1 olma olasılığını hesaplıyor. Temiz bir denklem log şansı olabilir ki
bu denklem olma olasılığını olmama olasılığına böler ve log alır.
 
p
log
1−p

olarak gösterilir. Şimdi biraz daha cambazlık, 1 − g(z) = g(−z) demiştik, ve


1 1
g(−z)’nin de ne olduğunu biliyoruz 1+e z , log şansını bu şekilde yazalım, 1+ez ile
z
bölelim daha doğrusu 1 + e ile çarpalım ve log alalım,

ez
 
log (1 + ez ) = log(ez ) = z = θT x
1 + ez

Artık olurluk denklemine dönebiliriz. Olurluğu nasıl maksimize ederiz? Gradyan


çıkışı (gradient ascent) kullanılabilir. Eğer olurluk l(θ)’nin en maksimal olduğu

5
noktadaki θ’yi bulmak istiyorsak (dikkat sadece olurluğun en maksimal nok-
tasını aramıyoruz, o noktadaki θ’yi arıyoruz), o zaman bir θ ile başlarız, ve adım
adım θ’yi maksimal olana doğru yaklaştırırız. Formül

θyeni = θeski + α∇θ l(θ)

Üstteki formül niye işler? Çünkü gradyan ∇θ l(θ), yani l(θ)’nin gradyanı her
zaman fonksiyon artışının en fazla olduğu yönü gösterir. Demek ki o yöne adım
atmak, yani l(θ)’a verilen θ’yi o yönde değiştirmek (değişim tabii ki θ bazında,
θ’nin değişimi), bizi fonksiyonun bir sonraki noktasına yaklaştıracaktır. Sabit
α bir tek sayı sadece, atılan adımın (hangi yönde olursa olsun) ölçeğini azaltıp
/ arttırabilmek için dışarıdan eklenir. Adım yönü vektör, bu sabit bir tek sayı.
Çarpımları vektörü azaltır ya da çoğaltır.
Not: Bu şekilde azar azar sonuca yaklaşmaya uğraşmak tabii ki her fonksiyon için
geçerli değildir, çünkü eğer fonksiyonda ”yerel maksimumlar” var ise, gradyan
çıkışı bu noktalarda takılıp kalabilir (o yerel tepelerde de birinci türev sıfırlanır,
gradyanın kafası karışır). Gradyan metotunun kullanmadan önce fonksiyonu-
muzun tek (global) bir maksimumu olup olmadığını düşünmemiz gerekir. Fakat
şanlıyız ki olurluk fonksiyonu tam da böyle bir fonksiyondur (şans değil tabii, bu
özelliği sebebiyle seçildi). Fonksiyon içbükeydir (concave), yani tek bir tepe nok-
tası vardır. Bir soru daha: olurluğun içbükey olduğunu nasıl anladık? Fonksiy-
ona bakarak pat diye bunu söylemek mümkün, değişkenlerde polinom bağlamında
küpsel ve daha üstü seviyesinde üstellik yok, ayrıca log, exp içbükeyliği boz-
muyor.
Simdi ∇θ l(θ) turetmemiz gerekiyor.

Eğer tek bir ∂l(θ)


∂θj
’yi hesaplarsak ve bunu her j için yaparsak, bu sonuçları bir
vektörde üstüste koyunca ∇θ l(θ)’yi elde ederiz.

∂ ∂
∂l(θ) ∂θj
g(θT x) ∂θj
g(θT x)
=y − (1 − y)
∂θj g(θT x) 1 − g(θT x)

1 1  ∂
= y − (1 − y) g(θT x)
g(θT x) 1 − g(θT x) ∂θj

Şimdi en sağdaki kısmı açalım,

∂ ∂ T
g(θT x) = g 0 (θT x) θ x = g 0 (θT x)xj
∂θj ∂θj

∂θj
θT x nasıl xj haline geldi? Çünkü tüm θ vektörünün kısmi türevini alıyoruz
fakat o kısmi türev sadece tek bir θj için, o zaman vektördeki diğer tüm öğeler
sıfır olacaktır, sadece θj 1 olacak, ona tekabül eden x öğesi, yani xj ayakta kala-
bilecek, diğer x öğelerinin hepsi sıfırla çarpılmış olacak.

6
Türevin kendisinden de kurtulabiliriz şimdi, daha önce gösterdiğimiz eşitliği de-
vreye sokalım,

= g(θT x)(1 − g(θT x))xj

Bu son formülü 3 üstteki formülün sağ tarafına geri koyarsak, ve basitleştirirsek,

y(1 − g(θT x)) − (1 − y)g(θT x) xj




Çarpımı daha temiz görmek için sadece y, g harflerini kullanırsak,


y(1 − g) − (1 − y)g xj = (y − yg − g + yg)xj = (y − g)xj

yani

= (y − g(θT x))xj

= (y − hθ (x))xj

İşte ∇θ l(θ) için ne kullanacağımızı bulduk. O zaman

θyeni = θeski + α(y − hθ (x))xj

Her i veri noktası için

θyeni = θeski + α(yi − hθ (xi ))xij

Kodu işletelim,

def grad_ascent(data_mat, label_mat):


m,n = data_mat.shape
label_mat=label_mat.reshape((m,1))
alpha = 0.001
iter = 500
theta = ones((n,1))
for k in range(iter):
h = sigmoid(dot(data_mat,theta))
error = label_mat - h
theta = theta + alpha * dot(data_mat.T,error)
return theta

theta = np.array(grad_ascent(array(data),array(labels).T ))
print theta.T

[[ 4.12414349 0.48007329 -0.6168482 ]]

7
def plot_theta(theta):
x = np.array(arange(-3.0, 3.0, 0.1))
y = np.array((-theta[0]-theta[1]*x)/theta[2])
plt.plot(x, y)
plt.hold(True)
class0 = data[labels==0]
class1 = data[labels==1]
plt.plot(class0['x'],class0['y'],'b.')
plt.hold(True)
plt.plot(class1['x'],class1['y'],'r.')
plt.hold(True)

plot_theta(theta)
plt.savefig('stat_logit_03.png')

Üstteki kod bir döngü içinde belli bir x noktasından başlayarak gradyan inişi
yaptı ve optimal θ değerlerini, yani regresyon ağırlıklarını (weights) hesapladı.
Sonra bu ağırlıkları bir ayraç olarak üstte grafikledi. Ayracın oldukça iyi değerler
bulduğu belli oluyor.
Rasgele Gradyan Çıkışı (Stochastic Gradient Ascent)
Acaba θ’yi güncellerken daha az veri kullanmak mümkün mü? Yani yön hesabı
için sürekli tüm veriyi kullanmasak olmaz mı?
Olabilir. Güncellemeyi sadece tek bir veri noktası kullanarak yapabiliriz. Yine
gradyanı değiştirmiş oluruz, sadece azar azar değişim olur, fakat belki de bu
şekilde sonuca daha çabuk ulaşmak mümkün olacaktır.
Kodlama açısından, θ güncellemesi için bulduğumuz formülü tek nokta bazında
da vermiştik. O zaman o tek noktayı sırayla alıp güncellersek, otomatik olarak
yeni bir şekilde gradyan çıkışı yapmış oluruz.

def stoc_grad_ascent0(data_mat, label_mat):


m,n = data_mat.shape
label_mat=label_mat.reshape((m,1))
alpha = 0.01
theta = ones((n,1))

8
for i in range(m):
h = sigmoid(sum(dot(data_mat[i],theta)))
error = label_mat[i] - h
theta = theta + alpha * data_mat[i].reshape((n,1)) * error
theta = theta.reshape((n,1))
return theta

theta = np.array(stoc_grad_ascent0(array(data),array(labels).T ))
print theta.T

[[ 1.01702007 0.85914348 -0.36579921]]

plot_theta(theta)
plt.savefig('stat_logit_04.png')

Neredeyse işimiz tamamlandı. Üstteki grafik pek iyi bir ayraç göstermedi. Niye?
Problem çok fazla salınım (oscillation) var, yani değerler çok fazla uç noktalar
arasında gidip geliyor. Ayrıca veri noktalarını sırayla işliyoruz, veri tabii ki ras-
gele bir şekilde sıralanmış olabilir, ama sıralanmamışsa, o zaman algoritmaya
raslantısal noktaları vermek için kod içinde zar atmamız lazım. Metotun ismi
”rasgele (stochastic)” gradyan çıkışı, bu rasgelelik önemli. 2. problemi düzeltmek
için yapılacak belli, 1. problem için α değeri her döngüde belli oranda küçültülerek
(yani α artık sabit değil) sonuca yaklaşırken oradan buraya savrulmasını engellemiş
olacağız. Yeni kod altta,

def stoc_grad_ascent1(data_mat, label_mat):


m,n = data_mat.shape
iter = 150
label_mat=label_mat.reshape((m,1))
alpha = 0.01
theta = ones((n,1))
for j in range(iter):
data_index = range(m)
for i in range(m):
alpha = 4/(1.0+j+i)+0.0001
rand_index = int(random.uniform(0,len(data_index)))
h = sigmoid(sum(dot(data_mat[rand_index],theta)))
error = label_mat[rand_index] - h

9
theta = theta + alpha * data_mat[rand_index].reshape((n,1)) * error
theta = theta.reshape((n,1))
return theta

theta = np.array(stoc_grad_ascent1(array(data),array(labels).T ))
print theta.T
[[ 14.67440542 1.30317067 -2.08702677]]

plot_theta(theta)
plt.savefig('stat_logit_05.png')

Sonuç çok iyi, ayrıca daha az işlemle bu noktaya eriştik, yani daha az işlem ve
daha hızlı bir şekilde sonuca ulaşmış olduk.
Tahmin (Prediction)
Elde edilen ağırlıkları tahmin için nasıl kullanırız? Bu ağırlıkları alıp, yeni veri
noktası ile çarpıp sonuçları sigmoid’den geçirdiğimiz zaman bu noktanın ”1 etiketi
olma olasılığını” hesaplamış olacağız. Örnek (diyelim ki mevcut veri noktası
içinden bir veriyi, -mesela 15. nokta- sanki yeniymiş gibi seçtik)

pt = df.ix[15,['intercept','x','y']]
print sigmoid(dot(array(pt), theta)),
print 'label =',labels[15]
[ 0.99999653] label = 1

Oldukça yüksek bir olasılık çıktı, ve hakikaten de o noktanın gerçek değeri 1 imiş.
Logit
İstatistik kaynaklarında genellikle “logit” adlı bir regresyon türünden bahsedildiğini
görebilirsiniz, burada aslında lojistik regresyondan bahsediliyor, ki bu konuyu
[10] yazısında bulabiliriz. Ama istatistik literatüründe (yapay öğrenim literatüründen
farklı olarak), terminoloji biraz kafa karıştırıcı olabiliyor. Lojistik regresyon yazısında
odağımız sigmoid fonksiyonuydu, peki logit nereden geliyor? Logit,

logit(x) = log(x/(1 − x))

10
fonksiyonudur, ve bu fonksiyon (0,1) arasındaki bir sayıyı −∞, ∞ arasına eşler
(map). Fonksiyona verilen x bir olasılık, ve bu olasılık, bir olayın (event) olma
/ olmama oranlarının log’una dönüşüyor. Ki bu fonksiyona “log ihtimali (log
odds)” ismi de veriliyor. Hatırlamanın kolay bir yolu belki de logit, “bir şeyi
logla” çağrışımı yapıyor, sonra “neyi logluyoruz?” diye düşünürüz, cevap bir
olasılığı, daha detaylı olarak olma / olmama oranını.

def logit(p): return np.log(p/(1-p))


p = 0.1; print logit(p)
p = 0.5; print logit(p)
p = 0.7; print logit(p)
p = 0.99999; print logit(p)

-2.19722457734
0.0
0.847297860387
11.5129154649

Sigmoid bunun tam tersidir, −∞, ∞ arasındaki bir değeri (0,1) arasına eşler, ki lo-
jistik regresyon katsayılarından bir olasılık üretmek istiyorsak, sigmoid lazım. Bu
ters gidişi ispatlamak kolay, ki bu “ters yönde” harekete logit−1 ismi de veriliyor,
ters yöne doğru gidelim,

p
logit(p) = log( )=x (1)
1−p

p 1 1
⇒ = exp(x) ⇒ x = − 1
1−p e p

1 1 1 + ex 1 ex
⇒ + 1 = ⇒ = ⇒ p =
ex p ex p 1 + ex

Lojistik regresyon modeli

Pr(yi = 1) = logit−1 (Xi β)

ki her Xi bir vektördür, veri noktalarımız Xi , yi olarak eşli olarak gelir. Diye-
lim ki elimizde 1992’de ABD seçimlerinde oy vermiş insanların gelir seviyesi
(income) ve kime oy (vote) verdikleri var. Bush’a verilmiş oyu 1 verilmemişi 0
olarak işaretlersek, bu problemi lojistik regresyon problemine çevirebiliriz,

import pandas as pd
df = pd.read_csv('nes.dat',sep=r'\s+')
df = df[['presvote','year','female','income','black']]
df = df[df['presvote'] < 3] # sadece 2 partinin oylarini al
df = df.dropna()
# 1,2 oylari 1,0 yap, Cumhuriyetciye verildi mi evet/hayir
# haline getir

11
df['presvote2'] = df['presvote'].map(lambda x: x-1)
df = df.drop('presvote',axis=1)
df2 = df[df['year'] == 1992]
print df2[:4]

year female income black presvote2


32093 1992 1 4 0 1
32094 1992 1 2 0 1
32096 1992 1 1 1 0
32097 1992 0 2 0 1

import statsmodels.api as sm
import statsmodels.formula.api as smf
mdlm = smf.logit("presvote2 ˜ income", df2)
mdlmf = mdlm.fit()
print(mdlmf.summary())

Optimization terminated successfully.


Current function value: 0.661553
Iterations 5
Logit Regression Results
==============================================================================
Dep. Variable: presvote2 No. Observations: 1207
Model: Logit Df Residuals: 1205
Method: MLE Df Model: 1
Date: Mon, 23 Feb 2015 Pseudo R-squ.: 0.02134
Time: 09:01:08 Log-Likelihood: -798.49
converged: True LL-Null: -815.91
LLR p-value: 3.598e-09
==============================================================================
coef std err z P>|z| [95.0% Conf. Int.]
------------------------------------------------------------------------------
Intercept -1.3863 0.187 -7.400 0.000 -1.754 -1.019
income 0.3245 0.056 5.775 0.000 0.214 0.435
==============================================================================

En basit haliyle bu denklem,

Pr(yi = 1) = logit−1 (α + βx) (2)

Üstteki katsayı değerlerini baz alarak,

Pr(yi = 1) = logit−1 (−1.38 + 0.32 · income)

Katsayıları irdelemenin iyi bir yolu şudur. Logit tersinden kurtulmak istiyorsak,
(1)’e deki formülü (2)’ye uygularız, iki tarafın logit’ini alırız, sağ taraftaki ters
logit kaybolur,
 
Pr(y = 1)
log = α + βx
Pr(y = 0)

12
Bu formülün sağ tarafına göre, x’e 1 eklemek demek, β(1+x) = βx+β·1 = βx+β,
formüle bir bakıma β eklemek demektir. Bunu bir tarafa koyalım, şimdi üstteki
formülün iki tarafının exp’sini alalım,

Pr(y = 1)
= exp(α + βx)
Pr(y = 0)

Şimdi exp içindeki x’e 1 eklersek, exp(α+βx+β) olur, bu da exp(α) exp(βx) exp(β)
demektir, o zaman iki tarafı da dengelemek için her iki tarafı da exp(β) ile çarpmak
lazım,

Pr(y = 1)
exp(β) = exp(α + βx + β) = exp(α) exp(βx) exp(β)
Pr(y = 0)

O zaman, x’deki bir birimlik değişimin, olma / olmama oranı olan ihtimal (odds)
üzerindeki etkisini hesaplamak istiyorsak, incelediğimiz değişkenin katsayısını
alıp mesela β = 0.3, onun exp’sini hesaplarız, exp(0.32) = 1.37, ve bu değerin
üstteki eşitliğin sol tarafını da çarpacağı bilgisinden hareketle, ihtimalin o kadar
artacak olduğunu rapor edebiliriz. Yani β = 0.3 için bu artış 1.37 katıdır. Yani
gelirde 1 birimlik bir artış (ki gelir veride 1,2,3,4 gibi sayısal aralıklar olarak gösterilmiş)
Bush’a oy verme şansının 1.37 kat arttırıyor. Bu aslında mantıklı, ABD’de Cumhuriyetçiler
“zenginlerin partisi” olarak biliniyor.
İhtimal oranları (odds ratio) ile düşünmek için bazı örnekler, ihtimal oranı 1,
olasılıkların 0.5 olması demektir, yani her iki ihtimal de eşit ağırlıktadır. İhtimal
oranı 0.5, ya da 2.0 (1/3,2/3) olasılıklarına tekabül eder, formülü hatırlayalım,
p/(1 − p).
Katsayıları İrdelemek
Eğer bir katsayı değerinin sıfırdan uzaklığı Std. Hatanın (Error) iki katından fa-
zla ise katsayı istatistiki olarak anlamlı / değerli (significant) demektir ve kul-
lanılabilir. Tabii burada biraz daha ek irdeleme gerekebilir; mesela kişilerin ara-
balarının beygir gücünü kazandıkları maaşa bağlayan bir regresyon, beygir gücü
katsayısı için beygir başına 10 Eur ve std. hata 2 Eur vermişse bu istatistiki olarak
önemli, ama pratikte önemsizdir. Benzer şekilde eğer beygir katsayısı için 10,000
Eur ve std. hata 10,000 Eur bulmuşsak, bu istatistiki olarak önemsiz, ama pratikte
önemlidir.
İlginç Durum
Siyahi oyların bazı yıllara göre analizini yapalım,

print 'coefs','error'

df2 = df[df['year'] == 1960]


mdlm = smf.logit("presvote2 ˜ female + black + income", df2)
mdlmf = mdlm.fit()
print np.vstack((mdlmf.params.index, mdlmf.params,mdlmf.bse)).T

13
df2 = df[df['year'] == 1964]
mdlm = smf.logit("presvote2 ˜ female + black + income", df2)
mdlmf = mdlm.fit()
print np.vstack((mdlmf.params.index, mdlmf.params,mdlmf.bse)).T

df2 = df[df['year'] == 1968]


mdlm = smf.logit("presvote2 ˜ female + black + income", df2)
mdlmf = mdlm.fit()
print np.vstack((mdlmf.params.index, mdlmf.params,mdlmf.bse)).T
coefs error
Optimization terminated successfully.
Current function value: 0.685646
Iterations 5
[['Intercept' -0.15937090803207216 0.22525976274228318]
['female' 0.23863850517270727 0.1365775569712597]
['black' -1.0585625868981525 0.3621668012097297]
['income' 0.03122275696614234 0.06237925936065817]]
Warning: Maximum number of iterations has been exceeded.
Current function value: 0.590399
Iterations: 35
[['Intercept' -1.1551333142403977 0.21592167898447412]
['female' -0.07918311120690241 0.1361066805886836]
['black' -26.62869325566435 93069.88953763059]
['income' 0.190103316020662 0.05839253555236441]]
Optimization terminated successfully.
Current function value: 0.626797
Iterations 7
[['Intercept' 0.47889431087596257 0.24427421556953816]
['female' -0.03135633331713884 0.1481293019619361]
['black' -3.6417024852622455 0.5946042228547078]
['income' -0.02613777851523365 0.06740777911367761]]

1964 yılında siyahi (black) seçmenlerin oylarına ne oldu? Üstteki analizde kat-
sayı müthiş alçak (büyük negatif değer), ve standard hata çok büyük. Eğer o
sene için veriye bakarsak neler olduğunu anlıyoruz; elimizdeki anket verisin-
deki kişilerden siyahi olan kimse 1964 yılında Cumhuriyetçilere oy vermemiş.
Bu durumda katsayı tabii ki büyük negatif değer (çünkü regresyon hedefimiz
Cumhuriyetçilere oy verilip verilmeyeceği), siyahi olmak ile Cumhuriyetçilere
oy vermek arasında negatif bir korelasyon ortaya çıkmış oluyor. Büyük stan-
dart hata iyi durmuyor tabii, ama bunun sebebi özyineli (iteratif) model uyduran
(fitting) algoritmanın bir nüansıdır. Daha ufak bir değer elde etmek için [3]’de
görülen numaralar yapılabilir, fakat pratikte bu büyük değeri görünce analizi ya-
pan kişi veriye bakacak, ve neler olduğunu anlayacaktır.
Bangladeş’te su kuyusu değişiminin lojistik modeli
Verimizde 3,000 haneye gidilerek anketle toplanmış veri var. Veride hanelerin
yakınlarındaki kuyudaki arsenik seviyesi toplanmış, ve paylaşılan verideki tüm
hanelerin kuyular sağlıksız seviyede arsenik içeriyor. Verideki diğer bilgiler en
yakındaki ”sağlıklı” bir kuyuya yakınlık, ve o hanenin bu sağlıklı su kuyusuna
(bir sene sonra yapılan kontrole göre) geçip geçmediği. Ayrıca hanede fikri soru-
lan kişinin eğitim seviyesi ve bu hanedeki kişilerin herhangi bir sosyal topluluğa

14
(community assocation) ait olup olmadıkları.
Amacımız su kuyusunun değişimini modellemek. Bu eylem olup / olmama
bağlamında evet / hayır şeklinde bir değişken olduğu için ikili (binary) olarak
temsil edilebilir ve ikili cevaplar / sonuçlar lojistik regresyon ile modellenebilir-
ler.
Veriye bakalım.

from pandas import *


from statsmodels.formula.api import logit
df = read_csv('wells.dat', sep = ' ', header = 0, index_col = 0)
print df.head()
switch arsenic dist assoc educ
1 1 2.36 16.826000 0 0
2 1 0.71 47.321999 0 0
3 0 2.07 20.966999 0 10
4 1 1.15 21.486000 0 12
5 1 1.10 40.874001 1 14

Model 1: Güvenli su kuyusuna uzaklık


İlk önce modelde kuyu uzaklığını kullanalım.

model1 = logit("switch ˜ dist", df).fit()


print model1.summary()
Optimization terminated successfully.
Current function value: 0.674874
Iterations 4
Logit Regression Results
==============================================================================
Dep. Variable: switch No. Observations: 3020
Model: Logit Df Residuals: 3018
Method: MLE Df Model: 1
Date: Wed, 20 May 2015 Pseudo R-squ.: 0.01017
Time: 21:25:34 Log-Likelihood: -2038.1
converged: True LL-Null: -2059.0
LLR p-value: 9.798e-11
==============================================================================
coef std err z P>|z| [95.0% Conf. Int.]
------------------------------------------------------------------------------
Intercept 0.6060 0.060 10.047 0.000 0.488 0.724
dist -0.0062 0.001 -6.383 0.000 -0.008 -0.004
==============================================================================

Uzaklık (dist) için elde edilen katsayı -0.0062, fakat bu sayı kafa karıştırıcı olabilir
çünkü uzaklık metre olarak ölçülür, o zaman bu katsayı mesela 90 metre ile 91
metre uzaklığın değişime olan etkisini ölçmektedir, kısacası pek faydalı değildir.
Yani uzaklık metre ile ölçüldüğü için 1 metrenin modeldeki etkisi ufak, o yüzden
bu ölçütü ölçeklersek (scale) belki regresyon katsayılarımız daha net çıkar.
Bunu nasıl yapacağız? Ölçeklenmiş yeni bir değişken yaratmak yerine, onu formülün
içinde tanımlayabiliriz. Burada bir ara not: eğer formül içinde +,- gibi operasy-

15
onları aritmetik işlem olarak kullanmak istiyorsak, o zaman ’I()’ çağrısını yap-
mak lazım, çünkü + operasyonu mesela statsmodels formüllerinde başka amaçlar
için kullanılıyor. ’I’ harfi birim (identity) kelimesinden geliyor, yani hiçbir şeyin
değişmediğini anlatmaya uğraşıyoruz, ”içinde ne varsa onu ver” diyoruz .

model1 = logit('switch ˜I(dist/100.)', df).fit()


print model1.summary()

Optimization terminated successfully.


Current function value: 0.674874
Iterations 4
Logit Regression Results
==============================================================================
Dep. Variable: switch No. Observations: 3020
Model: Logit Df Residuals: 3018
Method: MLE Df Model: 1
Date: Wed, 20 May 2015 Pseudo R-squ.: 0.01017
Time: 21:25:40 Log-Likelihood: -2038.1
converged: True LL-Null: -2059.0
LLR p-value: 9.798e-11
==================================================================================
coef std err z P>|z| [95.0% Conf. Int.]
----------------------------------------------------------------------------------
Intercept 0.6060 0.060 10.047 0.000 0.488 0.724
I(dist / 100.) -0.6219 0.097 -6.383 0.000 -0.813 -0.431
==================================================================================

Şimdi modelimizi grafikleyelim. Yanlız değişim (switch) verisini suni olarak


kaydırmamız / seğirtmemiz (jitter) gerekiyor, çünkü değişim 0 ve 1’den başka
bir şey olamaz ve grafik sürekli aynı iki bölgeye nokta basıp duracak.

def binary_jitter(x, jitter_amount = .05):


'''
0/1 vektoru iceren veriye segirtme ekle
'''
jitters = np.random.rand(*x.shape) * jitter_amount
x_jittered = x + np.where(x == 1, -1, 1) * jitters
return x_jittered

plt.plot(df['dist'], binary_jitter(df['switch'], .1), '.', alpha = .1)


plt.plot(np.sort(df['dist']), model1.predict()[np.argsort(df['dist'])], lw = 2)
plt.ylabel('Switched Wells')
plt.xlabel('Distance from safe well (meters)')
plt.savefig('stat_logit_06.png')

16
Mavi noktalar gerçek veri, yeşil çizgi ise uzaklık geçilerek modelin oluşturduğu
”tahmin”. Modelin gerçek veriye ne kadar uyduğunu görüyoruz böylece, yeşil
çizginin yüksek olasılık verdiği bölgelerde üst kısmın daha mavi olmasını bek-
leriz mesela. Üstteki resimde aşağı yukarı bunu gösteriyor.
Bir problemin grafiklemesine başka bir yönden yaklaşalım, kuyu değiştirenlerin
değişim uzaklığının yoğunluğu, bir de kuyu değiştirmeyenlerin değişim uzaklığının
yoğunluğu. Değişimi yapanların dağılımına bakınca, kısa mesafelerde daha fa-
zla yoğunluk görmeyi bekliyoruz, değiştirmeyenlerin ise uzun mesafelerde daha
fazla yoğunluğu olur herhalde.
Yoğunluğu göstermek için çekirdek yoğunluk hesabı (kernel density estimation)
tekniğini kullanıyoruz. Bu teknik her veri noktasına Gaussian, kutu (box), ya da
diğer türden bir ”çekirdek” fonksiyonunu koyar (ve veriyi o fonksiyona geçer,
sonucu kaydeder), ve bu iş bitince tüm çekirdekler üst üste toplanarak genel
dağılım ortaya çıkartılır. Teknik histogram tekniğiyle aynı işi yapmaya uğraşır,
bir anlamda verinin dağılımını daha pürüzsüz (smooth) hale getirir.
Bu teknik istatistikte oldukça yeni bir teknik sayılır, kullanılması için bilgisayar
hesabı gerekiyor (kıyasla histogram elle de yapılabilir), yeni hesapsal tekniklerde
olan ilerlemelerin veri analizine getirdiği bir yenilik yani!
[KDE bölümü atlandı]
Model 2: Güvenli kuyuya olan uzaklık ve kendi kuyusunun arsenik seviyesi
Şimdi arsenik seviyesini modelimize ekleyelim. Bekleriz ki kuyusunda yüksek
arsenik miktarı olan kimselerin kuyu değiştirmesi daha çok beklenen bir şeydir.

model2 = logit('switch ˜ I(dist / 100.) + arsenic', df).fit()


print model2.summary()

Optimization terminated successfully.


Current function value: 0.650773
Iterations 5
Logit Regression Results
==============================================================================
Dep. Variable: switch No. Observations: 3020
Model: Logit Df Residuals: 3017
Method: MLE Df Model: 2

17
Date: Wed, 20 May 2015
Pseudo R-squ.: 0.04551
Time: 21:25:48
Log-Likelihood: -1965.3
converged: True
LL-Null: -2059.0
LLR p-value: 1.995e-41
==================================================================================
coef std err z P>|z| [95.0% Conf. Int.]
----------------------------------------------------------------------------------
Intercept 0.0027 0.079 0.035 0.972 -0.153 0.158
I(dist / 100.) -0.8966 0.104 -8.593 0.000 -1.101 -0.692
arsenic 0.4608 0.041 11.134 0.000 0.380 0.542
==================================================================================

Ki katsayılar da aynen bunu gösteriyor. Güvenli kuyuya olan uzaklık büyüdükçe


değişime negatif etki yapıyor ama kendi kuyusundaki arsenik seviyesinin art-
ması değişimde pozitif etki yapıyor.
Kısmi (marginal) etkiler
Tüm bu değişkenlerin değişim olasılığı üzerindeki etkilerini görmek için verinin
ortalama noktasında bir kısmi olasılık hesabı yapalım.

print model2.get_margeff(at = 'mean').summary()

Logit Marginal Effects


=====================================
Dep. Variable: switch
Method: dydx
At: mean
==================================================================================
dy/dx std err z P>|z| [95.0% Conf. Int.]
----------------------------------------------------------------------------------
I(dist / 100.) -0.2181 0.025 -8.598 0.000 -0.268 -0.168
arsenic 0.1121 0.010 11.217 0.000 0.092 0.132
==================================================================================

Bu sonuca göre, ankette soru sorulan ortalama kişi için en yakın kuyuya olan
uzaklıkta 100 metrelik bir değişim olasılığında %22 düşüş anlamına gelmektedir.
Fakat kendi kuyusundaki arsenikte 1 seviyesinde bir artış değişim olasılığını %11
oranında arttırmaktadır.
Sınıfların ayırılabilirliği
Bu modelin kuyu değiştirenler ile değiştirmeyenleri ne kadar iyi sınıflayabildiğini
anlamak için her sınıftaki kişiyi uzaklık-arsenik uzayında grafikleyebiliriz.
Biz pek bir iyi bir ayırım göremedik, o sebeple modelin oldukça yüksek bir hata
oranının olmasını bekliyoruz. Fakat başka bir şey farkediyoruz, grafiğin ”kısa
mesafe-yüksek arsenik” bölgesinde çoğunlukla değişimciler var, ve ”uzun mesafe-
düşük arsenik” bölgesinde çoğunlukla değiştirmeyenler var.

logit_pars = model2.params
intercept = -logit_pars[0] / logit_pars[2]
slope = -logit_pars[1] / logit_pars[2]

18
dist_sw = df['dist'][df['switch'] == 1]
dist_nosw = df['dist'][df['switch'] == 0]
arsenic_sw = df['arsenic'][df['switch'] == 1]
arsenic_nosw = df['arsenic'][df['switch'] == 0]
plt.figure(figsize = (12, 8))
plt.plot(dist_sw, arsenic_sw, '.', mec = 'purple', mfc = 'None',
label = 'Switch')
plt.plot(dist_nosw, arsenic_nosw, '.', mec = 'orange', mfc = 'None',
label = 'No switch')
plt.plot(np.arange(0, 350, 1), intercept + slope * np.arange(0, 350, 1) / 100.,
'-k', label = 'Separating line')
plt.ylim(0, 10)
plt.xlabel('Distance to safe well (meters)')
plt.ylabel('Arsenic level')
plt.legend(loc = 'best')
plt.savefig('stat_logit_07.png')

Model 3: Etkileşim eklemek


Arsenik seviyesi ve uzaklık değişkenlerinin modele ayrı ayrı yaptığı etkiler yanında,
beraber olarak ta bazı etkiler yapacağını düşünebiliriz. 100 metrelik mesafenin
değişim kararına olan etkisi kuyunuzdaki arsenik seviyesiyle bağlantılı olabilmesi..
İnsanların böyle düşünmesini bekleyebiliriz, yani, bu problem bağlamında, tipik
kişi durup ta ”önce arsenik yokmuş gibi düşüneyim, sadece mesafeye bakayım”,
sonra ”şimdi arseniği düşüneyim, mesafe yokmuş gibi yapayım”, ve bunlardan
sonra ”şimdi bu iki ayrı kararı üst üste koyayım” şeklinde düşünmez.
Statsmodels’de formül arayüzü ile modele etkileşim eklemenin yolu değişkenler
arasında ‘:‘ operatörünü kullanmak ile olur.

model3 = logit('switch ˜ I(dist / 100.) + arsenic + I(dist / 100.):arsenic', df).fit()


print model3.summary()
Optimization terminated successfully.
Current function value: 0.650270
Iterations 5
Logit Regression Results
==============================================================================
Dep. Variable: switch No. Observations: 3020

19
Model: Logit
Df Residuals: 3016
Method: MLE
Df Model: 3
Date: Wed, 20 May 2015
Pseudo R-squ.: 0.04625
Time: 21:26:26
Log-Likelihood: -1963.8
converged: True
LL-Null: -2059.0
LLR p-value: 4.830e-41
======================================================================================
coef std err z P>|z| [95.0% Conf. I
--------------------------------------------------------------------------------------
Intercept -0.1479 0.118 -1.258 0.208 -0.378 0
I(dist / 100.) -0.5772 0.209 -2.759 0.006 -0.987 -0
arsenic 0.5560 0.069 8.021 0.000 0.420 0
I(dist / 100.):arsenic -0.1789 0.102 -1.748 0.080 -0.379 0
======================================================================================

Sonuca göre etkileşimin katsayısı negatif ve istatistiki olarak anlamlı (significant).


Bu katsayının değişim üzerindeki etkisini nicesel olarak hemen bakar bakmaz
anlayamıyor olsak bile, niteliksel olarak etkisi sezgilerimiz ile uyuşuyor. Uzaklık
değişimde negatif etkili, ama bu negatif etki yüksek arsenik seviyesi devreye gir-
ince azalıyor. Diğer yandan arsenik seviyesinin değişimde pozitif etkisi var, ama
o etki en yakın kuyu mesafesi arttıkça azalıyor.
Model 4: Eğitim seviyesi ve ek bazı etkileşimler, ve değişkenleri ortalamak
Eğitim seviyesi kişilerin arseniğin kötü etkilerini anlamasında pozitif etki yap-
ması beklenir, ve bu sebeple eğitim seviyesi değişim kararına pozitif etki yap-
malıdır. Elimizdeki veride eğitim yıl bazında kayıtlanmış, biz bu veri noktasını
ölçekleyeceğiz (aynen uzaklığa yaptımız gibi, çünkü eğitimde 1 senelik değişimin
pek bir anlamı yok), bunu için 4’e böleceğiz. Ayrıca bu yeni değişkenin diğer
değişkenler ile etkileşimini devreye sokacağız.
Ek olarak tüm değişkenleri ortalayacağız ki böylece onları yorumlamamız rahatlaşacak.
Bir kez daha bu işi tamamen statsmodels sayesinde formül içinde halledeceğiz,
dışarıdan on hesap yapıp formüle geçmemiz gerekmeyecek.

model_form = ('switch ˜ center(I(dist / 100.)) + center(arsenic) + ' +


'center(I(educ / 4.)) + ' +
'center(I(dist / 100.)) : center(arsenic) + ' +
'center(I(dist / 100.)) : center(I(educ / 4.)) + ' +
'center(arsenic) : center(I(educ / 4.))'
)
model4 = logit(model_form, df).fit()
print model4.summary()
Optimization terminated successfully.
Current function value: 0.644328
Iterations 5
Logit Regression Results
==============================================================================
Dep. Variable: switch No. Observations: 3020
Model: Logit Df Residuals: 3013
Method: MLE Df Model: 6
Date: Wed, 20 May 2015 Pseudo R-squ.: 0.05497
Time: 21:27:19 Log-Likelihood: -1945.9

20
converged: True
LL-Null: -2059.0
LLR p-value: 4.588e-46
======================================================================================
coef std err z P>|z
--------------------------------------------------------------------------------------
Intercept 0.3563 0.040 8.844 0.00
center(I(dist / 100.)) -0.9029 0.107 -8.414 0.00
center(arsenic) 0.4950 0.043 11.497 0.00
center(I(educ / 4.)) 0.1850 0.039 4.720 0.00
center(I(dist / 100.)):center(arsenic) -0.1177 0.104 -1.137 0.25
center(I(dist / 100.)):center(I(educ / 4.)) 0.3227 0.107 3.026 0.00
center(arsenic):center(I(educ / 4.)) 0.0722 0.044 1.647 0.10
======================================================================================

Modelin başarısını irdelemek: Kutulanmış Kalıntı grafikleri (Binned Residual


plots)
Model kalıntısının (yani model ile gerçek veri arasındaki hatalar -residual-) ile
ayrı ayrı her değişken ile grafikleri, uzaklık-kalıntı, arsenik-kalıntı gibi, bizi mod-
elde gayrı lineerlik olup olmadığı hakkında uyarabilir. Çünkü kalıntının Gaus-
sian bir dağılımda olmasını bekleriz, model hatası tam anlamıyla bir ”gürültü”
halinde olmalıdır, ki doğada gürültünün tanımı Gaussian dağılımına sahip ol-
maktır. Eğer bu grafikte kabaca her yere eşit şekilde dağılmış bir görüntü görmüyorsak,
o zaman modelimizde yakalayamadığımız bir gayrı lineerlik (nonlinearity) vardır,
ya da, birbirinden farklı olan kalıntı grafikleri kalıntıları dağılımlarının birbirinden
farklı olduğunun işaretidir (heteroskedaştıcıty).
İkili bir modelde kalıntıları ham şekilde grafiklemenin pek anlamı yoktur, o sebe-
ple biraz pürüzsüzleştirme uygulayacağız. Altta değişkenler için oluşturduğumuz
kutucuklar (bins) içine kalıntıların ortalamasını koyacağız ve bunları grafikleyeceğiz
(lowess ya da hareketli ortalama -moving average- tekniği de burada ise yaraya-
bilirdi).

def bin_residuals(resid, var, bins):


'''
Compute average residuals within bins of a variable.

Returns a dataframe indexed by the bins, with the bin midpoint,


the residual average within the bin, and the confidence interval
bounds.
'''
resid_df = DataFrame({'var': var, 'resid': resid})
resid_df['bins'] = qcut(var, bins)
bin_group = resid_df.groupby('bins')
bin_df = bin_group['var', 'resid'].mean()
bin_df['count'] = bin_group['resid'].count()
bin_df['lower_ci'] = -2 * (bin_group['resid'].std() /
np.sqrt(bin_group['resid'].count()))
bin_df['upper_ci'] = 2 * (bin_group['resid'].std() /
np.sqrt(bin_df['count']))
bin_df = bin_df.sort('var')
return(bin_df)

21
def plot_binned_residuals(bin_df):
'''
Plotted binned residual averages and confidence intervals.
'''
plt.plot(bin_df['var'], bin_df['resid'], '.')
plt.plot(bin_df['var'], bin_df['lower_ci'], '-r')
plt.plot(bin_df['var'], bin_df['upper_ci'], '-r')
plt.axhline(0, color = 'gray', lw = .5)

arsenic_resids = bin_residuals(model4.resid, df['arsenic'], 40)


dist_resids = bin_residuals(model4.resid, df['dist'], 40)
plt.figure(figsize = (12, 5))
plt.subplot(121)
plt.ylabel('Residual (bin avg.)')
plt.xlabel('Arsenic (bin avg.)')
plot_binned_residuals(arsenic_resids)
plt.subplot(122)
plot_binned_residuals(dist_resids)
plt.ylabel('Residual (bin avg.)')
plt.xlabel('Distance (bin avg.)')
plt.savefig('stat_logit_08.png')

Üstteki kutulama sırasında kullanılan qcut işlemlerin için en altta ek bölümüne


bakın
Model 5: arseniği log ölçeklemek
Kutulanmış artık grafiklerine bakınca arsenik değişkeninde biraz gayrı lineerlik
görüyoruz, çünkü noktaların dağılımı çok fazla belli bir bölgede. Dikkat ede-
lim, model nasıl düşük arseniği gerçekte olduğundan daha fazla olacağını tah-
min etmiş (overestimate), ayrıca yüksek arseniği gerçekte olduğundan daha az
olacağını tahmin etmiş (underestimate). Bu bize arsenik değişkeni üzerinde belki
de log transformasyonu gibi bir şeyler yapmamızın gerektiğinin işareti.
Bu değişimi de direk formül içinde yapabiliriz.

model_form = ('switch ˜ center(I(dist / 100.)) + center(np.log(arsenic)) + ' +


'center(I(educ / 4.)) + ' +
'center(I(dist / 100.)) : center(np.log(arsenic)) + ' +

22
'center(I(dist / 100.)) : center(I(educ / 4.)) + ' +
'center(np.log(arsenic)) : center(I(educ / 4.))'
)

model5 = logit(model_form, df).fit()


print model5.summary()

Optimization terminated successfully.


Current function value: 0.639587
Iterations 5
Logit Regression Results
==============================================================================
Dep. Variable: switch No. Observations: 3020
Model: Logit Df Residuals: 3013
Method: MLE Df Model: 6
Date: Wed, 20 May 2015 Pseudo R-squ.: 0.06192
Time: 21:26:41 Log-Likelihood: -1931.6
converged: True LL-Null: -2059.0
LLR p-value: 3.517e-52
======================================================================================
coef std err z P
--------------------------------------------------------------------------------------
Intercept 0.3452 0.040 8.528 0
center(I(dist / 100.)) -0.9796 0.111 -8.809 0
center(np.log(arsenic)) 0.9036 0.070 12.999 0
center(I(educ / 4.)) 0.1785 0.039 4.577 0
center(I(dist / 100.)):center(np.log(arsenic)) -0.1567 0.185 -0.846 0
center(I(dist / 100.)):center(I(educ / 4.)) 0.3384 0.108 3.141 0
center(np.log(arsenic)):center(I(educ / 4.)) 0.0601 0.070 0.855 0
======================================================================================

Şimdi arsenik için kutulanmış kalıntı grafikleri daha iyi gözüküyor.

arsenic_resids = bin_residuals(model5.resid, df['arsenic'], 40)


dist_resids = bin_residuals(model5.resid, df['dist'], 40)
plt.figure(figsize = (12, 5))
plt.subplot(121)
plot_binned_residuals(arsenic_resids)
plt.ylabel('Residual (bin avg.)')
plt.xlabel('Arsenic (bin avg.)')
plt.subplot(122)
plot_binned_residuals(dist_resids)
plt.ylabel('Residual (bin avg.)')
plt.xlabel('Distance (bin avg.)')
plt.savefig('stat_logit_09.png')

23
Model hata oranları
pred_table() çağrısı bize bu modelin ”kafa karışıklığı matrisini (confusion ma-
trix)” veriyor. Bu matrisi kullanarak modelimizin hata oranını hesaplayabiliriz.
Not: Kafa karışıklığı matrisi sınıflandırma hatalarını verir, ve her türlü hata kom-
binasyonunu içerir, mesela iki sınıf için, gerçekte 0 ama 1 tahmin hataları, gerçekte
1 ama 0 hataları vs. Bu matrisin satırlar gerçek veri, kolonları tahminleri içerir.
Tabii ki köşegendeki sayılar doğru tahmin oranlarıdır.
Sonra bu sonucu, en fazla verilen cevabı herkesin cevabıymış gibi farzeden daha
basit bir ”sıfır (null) modelinin” hata oranı ile karşılaştırmalıyız. Mesela bu-
rada kişilerin %58’i kuyu değiştirmiş, bu durumda sıfır modeli ”herkes kuyu
değiştiriyor” diye modeller, ve bu basit modelin hata payı 42% olur. Bizim model
bu modelden daha iyi bir sonuç verecek midir? Sonuç altta.

print model5.pred_table()
print 'Model Error rate: {0: 3.0%}'.format(
1 - np.diag(model5.pred_table()).sum() / model5.pred_table().sum())
print 'Null Error Rate: {0: 3.0%}'.format(
1 - df['switch'].mean())

[[ 568. 715.]
[ 387. 1350.]]
Model Error rate: 36%
Null Error Rate: 42%

Ek: qcut
Yukarıdaki qcut kullanımını özetlemek gerekirse; arsenik değişkeni için mesela
dağılım bölgeleri (n-tile) üzerinden bir atama yapacağız, önce DataFrame yaratalım,

resid_df = DataFrame({'var': df['arsenic'], 'resid': model4.df_resid})


print resid_df[:10]

resid var
1 3013 2.36
2 3013 0.71

24
3 3013 2.07
4 3013 1.15
5 3013 1.10
6 3013 3.90
7 3013 2.97
8 3013 3.24
9 3013 3.28
10 3013 2.52

model4.
Şimdi 40 tane dağılım bölgesi yaratalım

print qcut(df['arsenic'], 40)

1 (2.327, 2.47]
2 (0.68, 0.71]
3 (1.953, 2.07]
4 (1.1, 1.15]
5 (1.0513, 1.1]
6 (3.791, 4.475]
7 (2.81, 2.98]
8 (3.21, 3.42]
9 (3.21, 3.42]
10 (2.47, 2.61]
11 (2.98, 3.21]
12 (2.98, 3.21]
13 (2.81, 2.98]
14 (2.98, 3.21]
15 (1.66, 1.76]
...
3006 (0.64, 0.68]
3007 (2.327, 2.47]
3008 (0.71, 0.75]
3009 (1.25, 1.3]
3010 (0.71, 0.75]
3011 (0.56, 0.59]
3012 (0.95, 1.0065]
3013 (0.86, 0.9]
3014 [0.51, 0.53]
3015 (0.95, 1.0065]
3016 [0.51, 0.53]
3017 (1.0513, 1.1]
3018 [0.51, 0.53]
3019 (0.62, 0.64]
3020 (0.64, 0.68]
Name: arsenic, Length: 3020, dtype: category
Categories (40, object): [[0.51, 0.53] < (0.53, 0.56] < (0.56, 0.59] <
(0.59, 0.62] ... (3.21, 3.42]
< (3.42, 3.791] < (3.791, 4.475] < (4.475, 9.65]]

Görüldüğü gibi bölgeler bir obje aslında ve içinde levels diye bir değişkeni var.
Ayrıca labels diye bir değişken de var,

print qcut(df['arsenic'], 40).labels

25
[31 6 28 ..., 0 4 5]

ki bu değişken içinde hangi noktanın hangi olasılık bölgesine ait olduğunun ata-
ması var. Mesela 2. nokta 6. bölgeye aitmiş, bu bölge hangisi?

print qcut(df['arsenic'], 40).levels[6]

(0.68, 0.71]

Şimdi şöyle bir atama yaparsak, yani qcut sonucunu direk olduğu gibi resid_df
içine atarsak, qcut içindeki levels, resid_df üzerindeki index (sıra) ile uyum-
landırılacaktır, ve her var için doğru olan qcut sonucu atanmış olacaktır!

resid_df['bins'] = qcut(df['arsenic'], 40)


print resid_df[:10]

resid var bins


1 0.842596 2.36 (2.327, 2.47]
2 1.281417 0.71 (0.68, 0.71]
3 -1.613751 2.07 (1.953, 2.07]
4 0.996195 1.15 (1.1, 1.15]
5 1.005102 1.10 (1.0513, 1.1]
6 0.592056 3.90 (3.791, 4.475]
7 0.941372 2.97 (2.81, 2.98]
8 0.640139 3.24 (3.21, 3.42]
9 0.886626 3.28 (3.21, 3.42]
10 1.130149 2.52 (2.47, 2.61]

Üstte hakikaten bakıyoruz ki 2. nokta var=0.71 doğru aralık olan (0.68, 0.71]
ile eşleşmiş.
Kredi Kart Analizi ve Lojistik Regresyon
Kredi Kart başvurularının kabul edilip edilmediğinin kayıtları üzerinde başvurunun
kabul edilip edilmeyeceğini tahmin etmek için bir model kullanabiliriz. Örnek [1,
sf. 390]’dan alındı. Veri
card = Başvuru kabul edilmiş mi?
reports = Kişi hakkında kötü bir olay rapor edilmiş mi?
income = Yıllık gelir, birim $10000
age = Yaş
owner = Kişi kendi evinin sahibi mi?
dependents = Bakılan / bağımlı kaç kişi var (çocuk, yaşlı kişi, vs)
months = Mevcut adreste kaç aydır yaşanıyor
share = Aylık kredi kart harcamalarının yıllık kazanca olan oranı
selfemp = Kişi kendi işinin sahibi mi?
majorcards = Büyük kredi kart şirketlerinden kaç tane kartı var

26
active = Kaç tane aktif kredi kart hesabı var
expenditure = Aylık kredi kartı harcaması
Tahmin edeceğimiz ilk değişken card olacak, ki bu değişken evet/hayır bazında;
ona bağlı olarak modellenecek değişkenler geri kalanları, bu değişkenlerin kredi
kart kabulünde ne kadar etkili olacağını analiz edeceğiz.
Biraz veri önişlemesi yapalım; 1’den küçük bazı yaş verileri var, onları silelim ve
değişkenlerin histogramını basalım.

import pandas as pd
df = pd.read_csv('CreditCard.csv',index_col=0)

# etiketi 1/0 degerine cevir


df['card'] = (df['card']=='yes').astype(int)
df['owner'] = (df['owner']=='yes').astype(int)

# 1'den kucuk yaslari sil


df = df[df['age'] > 1]
df['log_reports1'] = np.log(df['reports']+1)
df['log_share'] = np.log(df['share'])

fig, axes = plt.subplots(3, 3, figsize=(10, 10))

col='reports';ax=axes[0,0];ax.set_title(col)
df[col].hist(ax=ax)
col='income';ax=axes[0,1];ax.set_title(col)
df[col].hist(ax=ax)
col='share';ax=axes[0,2];ax.set_title(col)
df[col].hist(ax=ax)

col='age';ax=axes[1,0];ax.set_title(col)
df[col].hist(ax=ax)
col='owner';ax=axes[1,1];ax.set_title(col)
df[col].hist(ax=ax)
col='dependents';ax=axes[1,2];ax.set_title(col)
df[col].hist(ax=ax)

col='months';ax=axes[2,0];ax.set_title(col)
df[col].hist(ax=ax)
col='log(share)';ax=axes[2,1];ax.set_title(col)
df[col].hist(ax=ax)
col='log(reports+1)';ax=axes[2,2];ax.set_title(col)
df[col].hist(ax=ax)

plt.savefig('stat_logit_01.png')

27
Görüldüğü gibi share sola doğru çok yamuk (highly skewed) duruyor, bu değişkenin
bu sebeple log’unu aldık. Değişken reports aynı durumda, ayrıca bu değişkenin
çoğu değeri 0 ya da 1, ama maksimum değeri 14. Bu sebeple log(reports+1)
kullandık ki 0’in logunu almak zorunda olmayalım, ki zaten bu tanımsızdır. Bu
transformasyonu yapıyoruz çünkü belli noktalarda aşırı yoğun olan değişkenler
(ki yamukluklarının sebebi bu) çok yüksek katsayı değerlerinin çıkmasını tetikleye-
biliyor, bu yüzden transformasyon ile onları biraz daha yaymaya uğraşıyoruz.
Alttaki regresyon transformasyon yapılmış hali, onun altında yapılmamış hali de
var.

import statsmodels.formula.api as smf


import statsmodels.api as sm
model = "card ˜ log_reports1 + income + log_share + age + " + \
"owner + dependents + months "
model=smf.glm(model, data=df, family=sm.families.Binomial()).fit()
print(model.summary())
print 'BIC', model.bic
print 'AIC', model.aic

Generalized Linear Model Regression Results


==============================================================================
Dep. Variable: card No. Observations: 1312
Model: GLM Df Residuals: 1304
Model Family: Binomial Df Model: 7

28
Link Function: logit Scale: 1.0
Method: IRLS Log-Likelihood: -69.895
Date: Thu, 21 May 2015 Deviance: 139.79
Time: 10:14:51 Pearson chi2: 247.
No. Iterations: 13
================================================================================
coef std err z P>|z| [95.0% Conf. Int.]
--------------------------------------------------------------------------------
Intercept 21.4739 3.674 5.844 0.000 14.272 28.675
log_reports1 -2.9086 1.098 -2.650 0.008 -5.060 -0.757
income 0.9033 0.190 4.760 0.000 0.531 1.275
log_share 3.4230 0.530 6.452 0.000 2.383 4.463
age 0.0227 0.022 1.036 0.300 -0.020 0.066
owner 0.7052 0.533 1.323 0.186 -0.340 1.750
dependents -0.6649 0.267 -2.487 0.013 -1.189 -0.141
months -0.0057 0.004 -1.435 0.151 -0.014 0.002
================================================================================
BIC -9222.02662057
AIC 155.790971664

Değişken reports ve share transforme edilmemiş hali,

import statsmodels.formula.api as smf

reg2 = "card ˜ reports + income + share + age + " + \


"owner + dependents + months "
model2=smf.glm(reg2, data=df, family=sm.families.Binomial()).fit()
print(model2.summary())
print 'BIC', model2.bic
print 'AIC', model2.aic

Generalized Linear Model Regression Results


==============================================================================
Dep. Variable: card No. Observations: 1312
Model: GLM Df Residuals: 1304
Model Family: Binomial Df Model: 7
Link Function: logit Scale: 1.0
Method: IRLS Log-Likelihood: nan
Date: Thu, 21 May 2015 Deviance: 142.88
Time: 10:14:59 Pearson chi2: 229.
No. Iterations: 18
==============================================================================
coef std err z P>|z| [95.0% Conf. Int.]
------------------------------------------------------------------------------
Intercept -4.5817 0.859 -5.334 0.000 -6.265 -2.898
reports -2.0253 0.900 -2.249 0.024 -3.790 -0.261
income 0.3850 0.133 2.884 0.004 0.123 0.647
share 2966.3111 587.349 5.050 0.000 1815.128 4117.495
age 0.0174 0.022 0.801 0.423 -0.025 0.060
owner 0.5966 0.526 1.135 0.256 -0.434 1.627
dependents -0.6130 0.249 -2.457 0.014 -1.102 -0.124
months -0.0046 0.004 -1.201 0.230 -0.012 0.003
==============================================================================
BIC -9218.93777391
AIC nan

29
Görüldüğü gibi share katsayısı oldukça büyük, ve bu modelde modelin veriye
uyum kalitesini ölçen BIC değeri aşağı yukarı 3 civarında büyüdü (daha küçük
BIC daha iyi).
Bir önceki regresyona bakarsak (ki doğru olarak onu kabul ediyoruz artık) değişkenlerin
p-değerine göre log_reports1, share, income, ve dependents değişkenlerinin önemli
(significant) olduğunu görüyoruz. Demek ki bu değişkenlerin kredi kartı başvurusunun
kabulü bağlamında en önemli değişkenler. Sayısal olarak income ve share arttıkça
kabul şansı artıyor, reports ve dependents arttıkça şans azalıyor.
Not: Üstte AIC değeri niye nan oldu? Tabii ondan önce AIC ve BIC nedir tanımlayalım.

AIC = −2 log{L(θ̂ML )} + 2p

BIC = −2 log{L(θ̂ML )} + log(n)p

AIC ve BIC bir modelin veriye ne kadar iyi uyduğunu gösteren ölçütlerdir. Log
olurluk, yani verinin bir modele göre kadar ne kadar olası olduğu AIC’in önemli
bir parçası. Fakat ek olarak modelin parametre sayısı p e 2p olarak AIC’e dahil
edilmiş, yani olurluğu aynı olan iki modelden daha basit olanı tercih edilecektir
[8].
Ayrıca AIC ölçütünün, standart varsayımlar altında, verinin bir parçasını dışarıda
bırakarak yapılan çapraz sağlamaya (cross-validation) eşdeğer olduğu da ispatlanmıştır
[9, sf. 90]. Bu çok ciddi bir avantajdır! Düşünürsek, yeni veri üzerinde elde
edilecek başarının ölçümü çoğunlukla ana “eğitim” verisinin bir kısmı dışarıda
bırakılarak, yani hakikaten “yeni veri” yaratarak hesaplanmaya uğraşılır - AIC
bu işi verinin kendisine bakarak doğal olarak yapıyor.
Bozukluğa dönelim: sebep nedir? Burada tahmin yürütmek gerekirse, AIC hesabındaki
log olurluk (likelihood) hesabı bozukluğa yol açmış olabilir, çünkü problem log
transform edilmemiş veride ortaya çıktı. Hatırlarsak transformasyonda sıfırlara
1 eklenmişti çünkü sıfırın log’u tanımsızdır. Bu tanımsızlık AIC hesabındaki
log olurluk hesabını da bozmuş olabilir. BIC için de aynı şey geçerli olabilirdi,
fakat bu modül değişik bir şekilde bu hesabı yapıyor herhalde (ayrı kişiler ayrı
tekniklerle yazılmış olabilirler).
Kaynaklar
[1] Ruppert, Statistics and Data Analysis for Financial Engineering
[2] Vogel, Logistic models of well switching in Bangladesh, http://nbviewer.ipython.
org/urls/raw.github.com/carljv/Will_it_Python/master/ARM/ch5/
arsenic_wells_switching.ipynb
[3] A Weakly Informative Default Prior Distribution for Logistic and Other Regression
models, http://www.stat.columbia.edu/˜gelman/research/published/
priors11.pdf

30
[5] Harrington, P. Machine Learning in Action
[7] Gelman, Hill, Data Analysis Using Regression and Multilevel/Hierarchical Models
[8] Burnham, Model Selection and Inference
[9] Shalizi, Advanced Data Analysis from an Elementary Point of View
[10] Bayramli, Istatistik, Lojistik Regresyon

31
Sayım, Poisson ve Negatif Binom Bazlı Genel Lineer Modelleri (GLM)
Sayım (count) verisini modellemek için genellikle Poisson dağılımına başvurulur.
Ayrıca ortada bir regresyon problemi var ise, yani belli katsayılar üzerinden çarpılan
değişkenlerin sonucu ile bir sayım arasında ilişki kurulmak istenirse -ki bu Logit
örneğinde görülmüştü, link fonksiyonu sigmoid yerine Poisson olur- o zaman
Poisson GLM kullanılır.
Poisson dağılımını hatırlarsak,

λx
f(x; λ) = e−λ
x!
Eğer bir yi rasgele değişkenini dağılımı λ = θi olan Poisson rasgele değişkeni
diye tanımlamak istersek, ki bu dağılım alttaki tanıma göre her i için değişik olur,

yi ∼ Poisson(θi )

Yoğunluk

f(yi ; θi ) = Poisson(yi ; θi )

olarak ta gösterilebilir. Şimdi GLM, yani regresyon yapmak için θi ’yi biraz daha
detaylandıralım / içini dolduralım,

θi = exp(Xi β)

Poisson dağılımı regresyon kaynağı olacak değişkenlerin lineer kombinasyonu


ile parametrize edilecek, β regresyonun tahmin edeceği katsayılar olacak. θi
ile parametrizasyon sonucu her veri noktası için farklı olabilecek bir θi ortaya
çıkabileceğinden bahsettik, fakat bu parametrizasyonların arkasında hep aynı β
vektörü olacak, bu durumda Poisson GLM’i veriye uydurmak demek veriyi en
iyi açıklayan bu aynı β’yi ortaya çıkartmaktır.
exp alınmış olmasının sebebi ise sadece artı sayılar ile çalışmak istememiz, çünkü
exp alınınca eksi sayılar bile sıfırdan büyük olur,

print np.exp(-2)
print np.exp(1./6)

0.135335283237
1.18136041287

Merak edenler için maksimum olurluk

Y
n
f(y; β, X) = Poisson(yi ; eXi β )
i=1

1
Veri
Devam etmeden önce veriye bakıp Poisson varsayımını kontrol etmek iyi olur.
Mesela örnek verimiz bir bölgede oturan insanların medyan kazanç (median in-
come) ile bu kazanca sahip olan şahısların evlerine ne kadar hırsız girdiği arasındaki
ilişki. Medyan kazanç için kaç eve hırsız girdiği bir sayım verisi, ilk akla gelen
Poisson ile modellenmesi, bakalım,

import pandas as pd
burg = pd.read_csv('burglary.txt',sep=' ')
burg.plot(y='burglaries',x='median_income',kind='scatter')
plt.savefig('stat_count_01.png')

Grafik Poisson’a benziyor.. Diğer yandan aslında negatif binom dağılımına da


benziyor. Şimdilik Poisson varsayımı ile devam edelim. Bu dağılımın önemli bir
varsayımı ortalamasının varyansı ile aynı olmasıdır. Veride durum böyle midir?
Medyan kazancı 59 ile 61 arasında olan kişilere bakalım,

burg_59_61 = burg[(burg['median_income'] > 59) & (burg['median_income'] < 61)]


m = burg_59_61['burglaries'].mean()
v = burg_59_61['burglaries'].std()**2
print m, v, v/m

7.33333333333 22.5384615385 3.07342657343

Veriden örneklem ortalaması ve örneklem varyansını hesapladık. Ne yazık ki


varyans ortalamanın üç katı! Demek ki bu verinin dağılımının Poisson olma
olasılığı düşük. Verinin başka bir bölgesine bakarsak,

burg_59_61 = burg[(burg['median_income'] > 39) & (burg['median_income'] < 41)]


m = burg_59_61['burglaries'].mean()
v = burg_59_61['burglaries'].std()**2
print m, v, v/m

21.8571428571 97.1428571429 4.44444444444

2
Aradaki fark bu sefer daha da büyük. Eğer bu veriye Poisson bazlı bir GLM
uydurmaya kalksaydık, ortaya aşırı saçılmış (överdispersed) bir durum ortaya
çıkardı. Ya da terminoloji olarak ve Poisson bazlı düşünürsek bu verinin aşırı
saçılmış olduğu söylenecekti. Her iki yöntemi de deneyebiliriz, önce Poisson
bazlı sonra Negatif Binomial bazlı bir GLM. İkincisinin daha iyi sonuç verdiğini
daha düşük kalıntı sapma (residual deviance) değerinden anlayabiliriz.

import pandas as pd
import statsmodels.formula.api as smf
import statsmodels.api as sm
model=smf.glm("burglaries ˜ median_income", data=burg,
family=sm.families.Poisson()).fit()
print(model.summary())
model=smf.glm("burglaries ˜ median_income", data=burg,
family=sm.families.NegativeBinomial()).fit()
print(model.summary())

Generalized Linear Model Regression Results


==============================================================================
Dep. Variable: burglaries No. Observations: 500
Model: GLM Df Residuals: 498
Model Family: Poisson Df Model: 1
Link Function: log Scale: 1.0
Method: IRLS Log-Likelihood: -1596.2
Date: Mon, 09 Mar 2015 Deviance: 1452.6
Time: 16:10:11 Pearson chi2: 1.47e+03
No. Iterations: 8
=================================================================================
coef std err z P>|z| [95.0% Conf. Int.]
---------------------------------------------------------------------------------
Intercept 5.6124 0.056 100.228 0.000 5.503 5.722
median_income -0.0613 0.001 -56.191 0.000 -0.063 -0.059
=================================================================================
Generalized Linear Model Regression Results
==============================================================================
Dep. Variable: burglaries No. Observations: 500
Model: GLM Df Residuals: 498
Model Family: NegativeBinomial Df Model: 1
Link Function: log Scale: 0.354315963879
Method: IRLS Log-Likelihood: -1482.4
Date: Mon, 09 Mar 2015 Deviance: 208.25
Time: 16:10:12 Pearson chi2: 176.
No. Iterations: 7
=================================================================================
coef std err z P>|z| [95.0% Conf. Int.]
---------------------------------------------------------------------------------
Intercept 5.5857 0.133 42.103 0.000 5.326 5.846
median_income -0.0608 0.002 -27.925 0.000 -0.065 -0.057
=================================================================================

Titanik Verisi
Daha ilginç bir veri batan Titanik gemisinin kayıtları. Bu kayıtlarda yolcuların
sağ kurtulup kurtulmadığı onlar hakkında baz bilgi ile beraber kişi seviyesinde

3
kaydedilmiş. Hangi sınıfta (whichclass) seyahat etmiş, yetişkin mi (adult) çocuk
mu, cinsiyeti erkek mi kadın mı (man / woman), hayatta kaldı mı (survived) gibi
bilgiler bu kayıtlarda. Bu veriye bakıp istatistiki olarak mesela yolcunun seyahat
ettiği sınıfın hayatta kalmaya etki edip etmediği görülebilir. Ham verinin birkaç
satırına bakalım,

import pandas as pd
tmp = pd.read_csv("titanic.csv",sep=',',index_col=0)
print tmp.head(5)
class age sex survived
1 1st class adults man yes
2 1st class adults man yes
3 1st class adults man yes
4 1st class adults man yes
5 1st class adults man yes

Tahmin bağlamında verinin 1/0 etiketlerine sahip olmasından hareketle ilk akla
gelen ona bir lojistik regresyon ya da Logit modeli uydurmak olabilir. Fakat bu
verinin her satırı üzerinden Logit yapmak yerine grup toplamları üzerinden Pois-
son ya da Negatif Binom yapmak daha uygun olur. Toplamlara bakalım (ayrı bir
dosyada),

import pandas as pd
df = pd.read_csv("titanicgrp.csv",sep=',',index_col=0)
print df
survive cases age sex whichclass
1 1 1 0 0 1
2 13 13 0 0 2
3 14 31 0 0 3
4 5 5 0 1 1
5 11 11 0 1 2
6 13 48 0 1 3
7 140 144 1 0 1
8 80 93 1 0 2
9 76 165 1 0 3
10 57 175 1 1 1
11 14 168 1 1 2
12 75 462 1 1 3

Poisson ile ilerlemeden önce, bir soru soralım: niye 1. sınıfta kurtulan çocuk
sayısı 2. ve 3. sınıftakinden daha az?

print df[(df['age']==0) & (df['whichclass']==1) ].sum()['survive']


print df[(df['age']==0) & (df['whichclass']==2) ].sum()['survive']
print df[(df['age']==0) & (df['whichclass']==3) ].sum()['survive']
6
24
27

Bu bizi şaşırtıyor, çünkü o sınıftan daha fazla kişinin kurtulmasını bekleriz. Fakat
sebep başka, sebep 1. sınıfta seyahat eden toplam çocuk sayısının zaten az olması.
Toplamlara bakarsak,

4
print '1. sinif cocuk sayisi,',
df[(df['age']==0) & (df['whichclass']==1) ].sum()['cases']
print '2. sinif cocuk sayisi,',
df[(df['age']==0) & (df['whichclass']==2) ].sum()['cases']
print '3. sinif cocuk sayisi,',
df[(df['age']==0) & (df['whichclass']==3) ].sum()['cases']

1. sinif cocuk sayisi, 6


2. sinif cocuk sayisi, 24
3. sinif cocuk sayisi, 79

0 zaman direk sayımı modellemek yerine, bir şekilde 6 içinden 6 kurtulmasının,


79 içinden 27 kurtulmaktan daha iyi olduğunu gösterebilecek bir model eki bize
gerekiyor. Yoksa şu anki haliyle 6 ve 27 ana regresyon hedefleri olarak alınacaktır,
ki bu doğru olmaz.
Kaydırma (offset) numarası burada ise yarar. Ondan önce, oran kavramını bir
şekilde modele dahil etmeyi görelim; Diyelim ki θi sayısının (ki bu mesela hay-
atta kalma sayısı) hangi toplam içinden çıktığını belirtmek için bir ui değişkeni
tasarlayalım, ve oranı şöyle modele dahil edelim,

θi
= exp(Xi β)
ui

Eğer 79’dan 27 kişi kurtulduysa ui = 79 ve θi = 27 olacak. Şimdi bir nu-


mara daha yapacağız, çünkü 100 içinden 10 gelmesi ile 200 içinden 20 gelmesi
arasındaki farkı da modellemek istiyoruz, normal şartlarda bu iki oran aynıdır
(1/10). Fakat bir fark olmalı. İki tarafın log’unu alırsak,
 
θi
log = Xi β
ui

log θi − log ui = Xi β

log θi = log ui + Xi β

Böylece ui değişkeni bir kaydırma operasyonu ile olduğu haliyle modele eklenmiş
oldu! Modelde bu değişkenin bir katsayısı olacak, maksimum olurluk onu öğrenmeye
çalışacak, vs. Tek bir ek işlem lazım, regresyona veriyi vermeden önce kaydırılan
değişkenin (toplam sayımın) log’u alınır (Poisson modelleri kendi içinde hedef
değişkenini zaten log’lar, ona dokunmaya gerek yok).
Şimdi Titanik verisini modelleyelim.

import pandas as pd
import statsmodels.formula.api as smf
import statsmodels.api as sm

5
df = pd.read_csv("titanicgrp.csv",sep=',',index_col=0)
df['lncases'] = df['cases'].map(lambda x:np.log(x))

model=smf.glm("survive ˜ age + sex + C(whichclass)", data=df, offset=df['lncases'],


family=sm.families.Poisson()).fit()
print(model.summary())

Generalized Linear Model Regression Results


==============================================================================
Dep. Variable: survive No. Observations: 12
Model: GLM Df Residuals: 7
Model Family: Poisson Df Model: 4
Link Function: log Scale: 1.0
Method: IRLS Log-Likelihood: -48.530
Date: Thu, 19 Mar 2015 Deviance: 38.304
Time: 14:15:55 Pearson chi2: 39.1
No. Iterations: 9
======================================================================================
coef std err z P>|z| [95.0% Conf. Int.]
--------------------------------------------------------------------------------------
Intercept 0.4845 0.160 3.035 0.002 0.172 0.797
C(whichclass)[T.2] -0.3783 0.118 -3.217 0.001 -0.609 -0.148
C(whichclass)[T.3] -0.7691 0.107 -7.185 0.000 -0.979 -0.559
age -0.4830 0.146 -3.317 0.001 -0.768 -0.198
sex -1.1657 0.095 -12.267 0.000 -1.352 -0.979
======================================================================================

Negatif Binom Modelleri


Üstteki sonuçlar hiç fena değil. Fakat verinin kurtulan kişi sayısının dağılımının
Poisson olduğu varsayımı her zaman doğru olmayabilir. Bu durumlarda Negatif
Binom kullanımı daha doğru olabilir. NB regresyonu için üstte gördüğümüz tüm
kavramlar hala geçerli, sadece perde arkasında

yi ∼ NegativeBinomial(θi )

kullanımı olacaktır, ve tabii ki farklı bir kütüphane çağrısı yapılır, ama geri kalan
her şey aynı.

modelnb=smf.glm("survive ˜ age + sex + C(whichclass)", data=df, offset=df['lncases'],


family=sm.families.NegativeBinomial()).fit()
print(modelnb.summary())

Generalized Linear Model Regression Results


==============================================================================
Dep. Variable: survive No. Observations: 12
Model: GLM Df Residuals: 7
Model Family: NegativeBinomial Df Model: 4
Link Function: log Scale: 0.222676200695
Method: IRLS Log-Likelihood: -50.130
Date: Thu, 19 Mar 2015 Deviance: 1.9976
Time: 14:16:24 Pearson chi2: 1.56
No. Iterations: 13
======================================================================================

6
coef std err z P>|z| [95.0% Conf. Int.]
--------------------------------------------------------------------------------------
Intercept 0.5197 0.340 1.527 0.127 -0.147 1.187
C(whichclass)[T.2] -0.2573 0.354 -0.728 0.467 -0.950 0.436
C(whichclass)[T.3] -0.9164 0.352 -2.605 0.009 -1.606 -0.227
age -0.6795 0.286 -2.380 0.017 -1.239 -0.120
sex -0.8033 0.284 -2.825 0.005 -1.361 -0.246
======================================================================================

Görüldüğü gibi kalıntı sapmada (residual deviance) seviyesinde büyük bir düşüş
oldu, yani hata azaldı. Bu regresyon çıktısında bazı katsayılar Poisson GLM’dekiyle
aynı olsa da bazıları değişti. Daha doğru olan değerler bunlar.
Katsayıları Yorumlamak
Elde edilen sonuçları pek çok şekilde yorumlamak mümkün, fakat en faydalı
olanı kategorik değişkenler için hesaplanabilen bir Oluş Oran Hızıdır (İncidence
Rate Ratio -IRR-). İsim biraz garip, evet, İngilizcesi de öyle. Bu gayet basit
bir operasyon, sadece katsayının exp’sini almak yeterli. İRR ne sağlar? Aynı
büyüklükteki bir oluş sayısının içinden iki grubu (ve onu gösteren değişken üzerinden)
karşılaştırmayı. Mesela her ikisi de t büyüklüğünde (yani aynı büyüklükte) olan
yetişkin ve çocuk gruplarının birbirinle oranla hayatta kalma şansı nedir? Mod-
ele dönersek, yetişkinler için oran,

θadults /t = exp(β0 +β1 (1)+β2 (sex)+β2 (whichclass = 2)+β2 (whichclass = 3)

Çocuklar için oran (sadece üstteki β1 (1) yerine β1 (0) olacak),

θchildren /t = exp(β0 +β1 (0)+β2 (sex)+β2 (whichclass = 2)+β2 (whichclass = 3)

Bu iki oranı bölersek İRR ortaya çıkar,

θadults /t exp(β0 + β1 (1) + β2 (sex) + β2 (whichclass = 2) + β2 (whichclass = 3))


=
θchildren /t exp(β0 + β1 (0) + β2 (sex) + β2 (whichclass = 2) + β2 (whichclass = 3))

Toplamların exp’sı her terimin exp’sinin çarpımıdır. Bu çarpımların çoğu iptal


olur, geriye sadece,

exp(β1 (1))
= = e β1
exp(β1 (0))

kalır. Yani İRR’i hesaplamak bir katsayının exp’sini almaktan ibarettir. Biz altta
tüm katsayıların exp’sini aldık,

print 'exp katsayilar'


print np.exp(modelnb.params)

7
exp katsayilar
Intercept 1.681497
C(whichclass)[T.2] 0.773108
C(whichclass)[T.3] 0.399941
age 0.506850
sex 0.447870
dtype: float64

Bizim aradığımız sonuç eβ1 = e−0.678 = 0.50, üstte görülen soldan 2. değer.
İRR’de bölen çocuk ve değer 1’den küçük olduğuna göre, demek ki yetişkenlerin
çocuklara göre hayatta kalma oranı yarı yarıya! Çocuklar daha şanslı.
Not: Bir sürü işlem yaptık, insanın aklına gelebilir, acaba bu cevabı ana veri
üzerinde sadece basit bölme operasyonları ile yapamaz mıydık?

adults = np.array(df[(df['age']==1)].sum()[['survive','cases']])
ratea = adults[0] / float(adults[1])
children = np.array(df[(df['age']==0)].sum()[['survive','cases']])
ratec = children[0] / float(children[1])
print ratea, ratec, 'nihai sonuc', ratea/ratec

0.366197183099 0.522935779817 nihai sonuc 0.700271806276

0.70 sonucu üstteki 0.50’den oldukça farklı. Daha doğru olan GLM değeri.
Tahmin Üretmek
Katsayıları kullanarak tahmin nasıl üretiriz? Yeni veri noktasına tekabül eden
katsayıları alıp çarpıp, toplarız, ve sonuç üzerine exp uygularız. Bu bize θi /ui
oranını verecektir.
Örnek, acaba 3. sınıftaki erkek çocukların hayatta kalma oranı nedir?

p = model.params
arr = np.array(df[ (df['whichclass']==3) & (df['sex']==1) & (df['age']==0) ])
print 'veri', arr[0][0] / arr[0][1]
print 'tahmin', np.exp(p[0] + p[2] + p[4])

veri 0.270833333333
tahmin 0.234504990187

Acaba 2. sınıftaki yetişkin erkeklerin hayatta kalma oranı nedir?

p = model.params
arr = np.array(df[ (df['whichclass']==2) & (df['sex']==1) & (df['age']==1) ])
print 'veri', arr[0][0] / arr[0][1]
print 'tahmin', np.exp(p[0] + p[1] + p[4] + p[4])

veri 0.0833333333333
tahmin 0.108052057562

Eğer üretilen tahminler için bir güven aralığı tanımlamak istiyorsak, conf_ınt()
ile tüm katsayılar için %95 güven aralığını alabiliriz,

print model.conf_int()

8
0 1
Intercept 0.171628 0.797290
C(whichclass)[T.2] -0.608738 -0.147836
C(whichclass)[T.3] -0.978885 -0.559276
age -0.768391 -0.197547
sex -1.351899 -0.979415

Bu sonuç bir Pandas DataFrame’i, rahatlıkla istediğimiz satırı, kolonuna erişebiliriz.


Kolon 0 alt değeri, kolon 1 üst değeri taşıyor. Bu güven aralıkları üzerinde de exp
hesabı yapmak mümkündür.
Kaynaklar
[1] Zwilling, Negative Binomial Regression, http://www.mathematica-journal.
com/2013/06/negative-binomial-regression
[2] SAS, Usage Note 24188: Modeling rates and estimating rates and rate ratios (with
confidence intervals), http://support.sas.com/kb/24/188.html
[3] Gelman, Hill, Data Analysis Using Regression and Multilevel/Hierarchical Models

9
Çok Seviyeli Modeller (Multilevel Models)
Lineer, lojistik regresyon tek seviyeli modellerdir; modellenen verinin regresy-
ona bildirilen tüm katsayılarının hepsi, aynı anda kullanılır. Fakat bazı durum-
larda, mesela coğrafi bir parametrenin modelin parçası olduğu durumlarda daha
değişik bir yaklaşım gerekli olabilir. Eğer regresyonumuzun katsayılarının belli
bir grup için (şehir, okul, zaman, bölge, vs), her grup için farklı şekillerde veriye
uydurulmasını (fit) istiyorsak, o zaman çok seviyeli modelleri kullanmak gereke-
bilir.
Altta gösterilen iki parametreli klasik regresyon

yi = α + βxi + i

çok seviyeli modellerde mesela α’yi, yani kesisi (intercept) her grupta farklı ola-
cak şekilde uydurabilir,

yi = αj[i] + βxi + i

Bu durumda her grup j’nin kendi kesi değeri olacaktır. Ya da her grubun kendi
eğimi (slope) olacak şekilde β’nin gruptan gruba değişmesine izin verilebilir,

yi = α + βj[i] xi + i

Ya da her ikisinin birden değişmesine izin verilebilir,

yi = αj[i] + βj[i] xi + i

Terminoloji
Literatürde bazen çok seviyeli modeller hakkında sabit etkiler (fixed effects), ras-
gele etkiler (random effects) gibi kelimeler kullanıldığını görürsünüz. Bu termi-
nolojiye göre grup seviyesinde değişmesine izin verilen αj , βj gibi parametrelere
“sabit etki” adı veriliyor, çünkü o parametreler grup içinde değişmemektedir,
modelin geri kalanı ise rasgele etki olacaktır. Bu iki kavramın karışımı da (ki
neredeyse her zaman öyle olur) “karışık etki (mixed effects)” modeli olarak anılıyor.
Bu terminoloji biraz kafa karıştırıcı olabilir, bilinmesi iyidir böylece literatürü
takip edebiliriz, ama biz [1]’deki tavsiyeyi kullanıp “çok seviyeli modeller” ke-
limelerini kullanacağız.
Örnek
Yeni bir ilacın etkili olup olmadığını anlamak için hastalar (subject) üzerinde
deneyler yapılır [2]. Bu veride ilginç olan hastanın durumunun tekrar tekrar belli
aralıklarla ölçülmesi, ve durumun (status) yeni bir veri satırı olarak kaydedilmesi.
Ayrıca rasgele seçilen hastalara ya ilaç, ya da etkisiz ilaç (placebo) veriliyor. Veride

1
cinsiyet (gender), yaş (age), tedavi merkezi numarası (centre) kolonları var. İlk
aydaki durum “başlangıç noktası (baseline)” olarak ayrı bir kolona ayrılıyor, ve
ilk ay satırları regresyon öncesi siliniyor. Soru şudur: ilaç etkili midir?
Soru bir evet/hayır sorusu olduğu için lojistik regresyon kullanacağız.

import statsmodels.api as sm, pandas as pd


import statsmodels.formula.api as smf
df = pd.read_csv('respiratory.csv',index_col=0)
baseline = df[df['month'] == 0][['subject','status']].set_index('subject')
df['status'] = (df['status'] == 'good').astype(int)
df['baseline'] = df.apply(lambda x: baseline.ix[x['subject']],axis=1)
df['centre'] = df['centre'].astype(str)
df = df[df['month'] > 0]
print (df.head(4).to_string())
centre treatment gender age status month subject baseline
112 1 placebo female 46 0 1 1 poor
223 1 placebo female 46 0 2 1 poor
334 1 placebo female 46 0 3 1 poor
445 1 placebo female 46 0 4 1 poor

mdlm = smf.logit("status ˜ baseline + month + treatment + gender + \


age + C(centre)", df)
mdlmf = mdlm.fit()
print(mdlmf.summary())
Optimization terminated successfully.
Current function value: 0.543694
Iterations 6
Logit Regression Results
==============================================================================
Dep. Variable: status No. Observations: 444
Model: Logit Df Residuals: 437
Method: MLE Df Model: 6
Date: Tue, 13 Nov 2018 Pseudo R-squ.: 0.2071
Time: 12:00:13 Log-Likelihood: -241.40
converged: True LL-Null: -304.47
LLR p-value: 8.385e-25
======================================================================================
coef std err z P>|z| [0.025 0.
--------------------------------------------------------------------------------------
Intercept 1.1436 0.426 2.682 0.007 0.308 1
baseline[T.poor] -1.8841 0.241 -7.802 0.000 -2.357 -1
treatment[T.treatment] 1.3006 0.237 5.488 0.000 0.836 1
gender[T.male] 0.1194 0.295 0.405 0.686 -0.458 0
C(centre)[T.2] 0.6723 0.240 2.805 0.005 0.203 1
month -0.0643 0.100 -0.646 0.518 -0.259 0
age -0.0182 0.009 -2.050 0.040 -0.036 -0
======================================================================================

Statsmodels altyapısı kategorik gördüğü değerleri 1-hot kodlamasıyla 1/0 değerli


kolonlara çevirir, yani treatment[T.treatment] tedavi uygulanıp uygulanmadığını
gösteren 1/0 değerli kolondur. Bir başkası treatment[T.placebo]; fakat bu kolon
regresyonda “önemli” bulunmadığı için üstte gösterilmemiş.

2
Görülen katsayılara göre tedavinin (treatment) katsayısı 1.3, exp(1.3) = 3.66.
Yani tedavi katsayısındaki 1 birimlik değişiklik (ki bu 0/1 bazlı bir değişken
olduğu için tedavi uygulamak ya da uygulamamak anlamına gelir), hastanın
iyileşmesinde 3.66 kat etki yaratıyor.
Fakat bu regresyon sonuçlarındaki standart hatalarının bazılarından pek mem-
nun değiliz, mesela gruplararası değişkenlerin (between-subject covariates), yaş
gibi, standart hataları aşırı ufak. Bunun sebebi regresyon işleminin tüm veri
satırlarını bağımsız (independent) kabul etmesidir, yani her satırdaki verinin çoğu
aynı kişiye ait olsa bile farklı kişilere aitmiş gibi işlenmektedir. Regresyon sonuçlarını
irdelerken sürekli tetikte olmak gerekir, görüldüğü gibi ufak hata bile bazen iyi
bir şey olmayabiliyor!
Peki çözüm nedir? Çok seviyeli modeller burada devreye girebilir. Eğer kişiyi
ve ona tekabül eden tüm verileri bir grup olarak alırsak, o kişi için alınan tüm
ölçümlerin tekrar eden kısımlarının genele daha az etkide bulunmasını sağlayabiliriz.
Altta glmer adlı komut üzerinden çok seviyeli regresyon örneğini görüyoruz,
ayrıca R diliyle bağlantı kurmak ta burada gösteriliyor; Python statsmodels’a
bu fonksiyon daha taşınmadı. Daha fazla detay için [3]’e bakılabilir.

%load_ext rpy2.ipython
%R library(lme4)

%R -i df
%R p1 = "status ˜ baseline + month + treatment + gender "
%R p2 = "+ age + centre + (1 | subject) "
%R params = paste(p1,p2)
%R resp_lmer <- glmer(as.formula(params), family = binomial(), data = df)
%R -o res res = summary(resp_lmer)
%R -o exp_res exp_res = exp(fixef(resp_lmer))
print res
print exp_res

Generalized linear mixed model fit by maximum likelihood (Laplace


Approximation) [glmerMod]
Family: binomial ( logit )
Formula: status ˜ baseline + month + treatment + gender + age + centre +
(1 | subject)
Data: df

AIC BIC logLik deviance df.resid


444.3 477.1 -214.2 428.3 436

Scaled residuals:
Min 1Q Median 3Q Max
-2.8574 -0.3590 0.1427 0.3693 2.2393

Random effects:
Groups Name Variance Std.Dev.
subject (Intercept) 3.89 1.972
Number of obs: 444, groups: subject, 111

3
Fixed effects:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.68254 0.84436 1.993 0.046296 *
baselinepoor -3.07838 0.60272 -5.107 3.26e-07 ***
month -0.10133 0.12518 -0.809 0.418257
treatmenttreatment 2.16325 0.55644 3.888 0.000101 ***
gendermale 0.20249 0.67270 0.301 0.763402
age -0.02546 0.02014 -1.264 0.206125
centre2 1.04667 0.54784 1.911 0.056064 .
---

Correlation of Fixed Effects:


(Intr) bslnpr month trtmnt gndrml age
baselinepor -0.367
month -0.383 0.041
trtmnttrtmn -0.178 -0.301 -0.031
gendermale 0.065 -0.102 -0.003 0.219
age -0.655 -0.015 0.009 -0.050 -0.263
centre2 -0.184 0.150 -0.015 0.058 -0.147 -0.223

(Intercept) baselinepoor month treatmenttreatment


5.37919357 0.04603378 0.90363768 8.69940763
gendermale age centre2
1.22445202 0.97485954 2.84815273

(1+subject) kullanımı gruplamayı kişi bazında yapıyor ve her grup için kesinin
değişmesine izin veriliyor. Regresyonun sonucu 2.16, exp(2.16) = 8.67, yani bu
ilaç aslında hastanın iyileşmesinde 8.67 kat etkili! Bu çok daha büyük bir rakam
ve gerçek sonuç aslında bu. Yaş değişkeninin standart hatasına bakarsak, daha
büyük olduğunu görüyoruz, yani bu katsayı daha uygun bir seviyeye gelmiş
bulunuyor.
Kaynaklar
[1] Gelman, Hill, Data Analysis Using Regression and Multilevel/Hierarchical Models
[2] Everitt, A Handbook of Statistical Analysis Using R
[3] Bayramlı, iPython, rpy2, rmagic, https://burakbayramli.github.io/
dersblog/sk/2015/02/ipython-rpy2-rmagic.html

4
Algılayıcı Birleştirimi, Füzyonu (Sensor Fusion)
Tek boyutlu ortamda bir büyüklüğü mesela bir lokasyon bilgisi x’i, iki kere ölçüyoruz,
ve bu ölçümü iki değişik algılayıcıya yaptırıyoruz, ve yine diyelim ki iki değişik
alet bir cismin olduğu uzaklığını / yerini bize geri döndürüyor. Devam ede-
lim, bu bilgilerde belli ölçüde gürültü var; bu aletlerin hatalı ölçümü yüzünden
olabilir, çevre şartları sebebiyle olabilir, örnek olarak iki z1 , z2 ölçümü için iki
değişik belirsizlik (uncertainty) olduğunu farzedelim, bunlar σ1 , σ2 . Soru şu: bu
iki ölçümü kullanarak daha iyi bir x tahmini yapabilir miyiz?
Bunun için iki ölçümü bir şekilde birleştirmemiz gerekiyor. Her ölçümü Gaus-
sian / Normal dağılım olarak modelleyebiliriz, o zaman iki Gaussian dağılımı
bir şekilde birleştirmemiz (fusion) lazım.
Ölçümleri temsil etmek için Gaussian biçilmiş kaftan. Ölçümdeki belirsizliği
standart sapma (standart deviation) üzerinden rahatlıkla temsil edebiliriz. Peki
birleştirimi nasıl yapalım?
Bu tür problemlerde maksimum olurluk (maximum likelihood) kullanılması gerektiğini
aşağı yukarı tahmin edebiliriz, çünkü maksimum olurluk verinin olurluğunu
(olasılığını yani) maksimize ederek bilinmeyen parametreleri tahmin etmeye uğraşır.
Çoğunlukla bu tekniği hep tek bir dağılım bağlamında görürüz, bazı bilinmeyen
parametreleri olan tek bir dağılıma değişik veri noktaları verilerek olasılık sonuçları
çarpılır, ve elde edilen formül maksimize edilmeye uğraşılırken aynı anda bilin-
meyen parametrelerin optimal değerleri saptanmaya uğraşılır. Bizim bu prob-
lemimizde iki değişik dağılım olacak, maksimum olurluk illa tek bir dağılımla
kullanılabilir diye bir kural yok.
Problemimizde iki ölçümü, iki Gaussian ile temsil edebiliriz, ve bu iki Gaussian’a
verilen iki ölçüm noktasını olurluğunu bu Gaussian’ların sonuçlarını çarparak
hesaplayabiliriz. Peki bilinmeyen parametre nedir? Onu da her iki Gaussian için de
aynı olduğunu farzettiğimiz orta nokta (mean) olarak alabiliriz, ve x olarak belirtiriz.
Yani

L(x) = p(z1 |x, σ1 )p(z2 |x, σ2 )

−(z1 − x)2 −(z2 − x)2


L(x) ∼ exp × exp
2σ21 2σ22

1D Gaussian formülünü hatırlarsak,


1 (z − x)2
p(z; x, σ) = √ exp −
σ 2π 2σ2

Ders notları [1]’de iki üstteki formülün nasıl maksimize edilerek bir xMLE formülüne
erişildiğini görebiliriz.

1
Formül başındaki sabit kısmının L(x)’de kullanılmadığını görüyoruz, çünkü mak-
simizasyon açısından düşünürsek o kısım tekrar tekrar çarpılacak ve hesapla-
maya çalıştığımız değişkenler açısından bu sürekli tekrar bir fark yaratmaz.
Bu metot işler. Fakat biz alternatif olarak daha temiz olacak değişik bir yoldan
gideceğiz. Elimizdeki her iki ölçümü iki farklı tek boyutlu Gaussian yerine 2
boyutlu tek bir Gaussian içine koyacağız, iki ölçümü tek bir 2 boyutlu vektör
içinde belirteceğiz yani, ve tek bir olasılık hesabını p(z; x, Σ)’i baz alacağız. Be-
lirsizlikler ne olacak? Ölçüm belirsizliklerini bu 2D Gaussian’ın kovaryansında
çapraza (diagonal) koyabiliriz, çapraz dişindaki matris öğeleri sıfır yapılırsa iki
ölçümün birbirinden bağımsızlığını temsil etmiş oluruz. Maksimizasyon? Tek bir
ölçümün olurluğunu maksimize edeceğiz, bu tek bir ölçümün olasılığını hesapla-
maktan ibarettir, ve bu hesap sırasında bilinmeyen değişkenleri içeren yeni bir
formül ortaya çıkacaktır. Maksimize etmeye uğraşacağımız bu formül olur.
Çok boyutlu Gaussian’ı hatırlayalım (artık z, x birer vektör),

1 1
p(z; x, Σ) = exp − (z − x)T Σ−1 (z − x)
(2π) det(Σ)1/2
k/2 2

Kısaca,

1 1
= exp − (z − x)T Σ−1 (z − x)
C 2

Bir numara, exp ve parantez içi negatif ibareden kurtulmak için − ln p alalım,

1
L = − ln p(z) = (z − x)T Σ−1 (z − x)
2

Şimdi iki ölçümü, belirsizliği vektör / matris öğeleri olarak gösterelim,

T  −1 
σ21 0
 
1 z1 − x z1 − x
=
2 z2 − x 0 σ22 z2 − x

Çapraz matrisin tersini almak için çaprazdaki öğelerin tersini almak yeterlidir,

T 
σ−2
  
1 z1 − x 1 0 z1 − x
=
2 z2 − x 0 σ−2
2 z2 − x
 
1  −2 z1 − x
σ1 (z1 − x) σ−2

= 2 (z2 − x) z2 − x
2

1 2 1 −2 2
= σ−2
1 (z1 − x) + σ2 (z2 − x)
2 2

2
Maksimize etmek için, formül karesel olduğuna göre, bilinmeyen x değişkenine
göre türev alıp sıfıra eşitleyebiliriz,

dL
= σ−2 −2 −2 −2
1 z1 − σ1 x + σ2 z2 − σ2 x = 0
dx
x üzerinden gruplarsak,

−x(σ−2 −2 −2 −2
1 + σ2 ) + σ1 z1 + σ2 z2 = 0

Gruplanan kısmı eşitliğin sağına alalım,

σ−2 −2 −2 −2
1 z1 + σ2 z2 = x(σ1 + σ2 )

σ−2 −2
1 z1 + σ2 z2
= xMLE
σ−2
1 + σ−2
2

Gayet temiz bir şekilde sonuca eriştik.


Örnek
Elimizde belirsizlikleri σ1 = 10, σ2 = 20 olan iki algılayıcı var. Bu algılayıcılar
aynı obje hakkında z1 = 130, z2 = 170 olarak iki ölçüm gönderiyorlar. Bu ölçümleri
birleştirelim. Hatırlarsak 10−2 ile çarpmak 102 ile bölmek aynı şey.

130/102 + 170/202
xMLE = = 138.0
1/102 + 1/202

Sonuç belirsizliği daha az olan ölçüme daha yakın çıktı, bu akla yatkın bir sonuç.
Çok Boyutlu Gaussian Füzyon
Peki ya elimizdeki ölçümlerin kendisi çok boyutlu ise? Yani z1 , z2 birer vektör
ise?
Yine maksimum olurluk üzerinden bir formül türetebiliriz. Bu durumda tek
olasılık hesabı yetmez, iki ayrı dağılım olmalı,

1 1
p(z1 ; x, Σ1 ) = exp − (z1 − x)T Σ−1
1 (z1 − x)
C1 2

1 1
p(z2 ; x, Σ2 ) = exp − (z2 − x)T Σ−1
2 (z2 − x)
C2 2

Orta nokta x her iki formülde aynı çünkü değişmeyen olan o; aynı orta nokta için
tahmin üretmeye uğraşıyoruz. Bu durum bildik maksimum olurluk hesaplarına

3
benziyor, fakat ilk başta belirttiğimiz gibi farklı türden olasılık fonksiyonlarının
(bu sefer çok boyutlu) farklı veri noktaları üzerinden çarpılması.
Devam edelim. Daha önce ln alarak exp’yi yoketmiştik. Bunun bir diğer faydası
ln alınınca çarpımların toplama dönüşmesidir,

L = p(z1 ; x, Σ1 )p(z2 ; x, Σ2 )

− ln L = − ln p(z1 ; x, Σ1 ) − ln p(z2 ; x, Σ2 )

1 1
L = − ln L = (z1 − x)T Σ−1 T −1
1 (z1 − x) + (z2 − x) Σ2 (z2 − x)
2 2

Şimdi eşitliğin sağ tarafının x’e göre türevini alalım, vektör ve matris bağlamında
türev nasıl alınır? Herhangi bir M’in simetrik olduğu durumlarda (ki kovaryans
matrisleri her zaman simetriktir, çünkü mesela iki değişkenli durumda x1 , x2 ko-
varyansı -ilişkisi- x2 , x1 kovaryansından farklı olamaz),

∂ T
[x Mx] = 2Mx
∂x

olduğunu biliyoruz [2]. O zaman türev sonucu şöyle olur,

dL
= (z1 − x)T Σ−1 T −1
1 + (z2 − x) Σ2
dx

Sıfıra eşitleyip çözelim,

(z1 − x)Σ−1 −1
1 + (z2 − x)Σ2 = 0

z1 Σ−1 −1 −1 −1
1 − xΣ1 + z2 Σ2 − xΣ2 = 0

Yine x altında gruplayalım,

−x(Σ−1 −1 −1 −1
1 + Σ2 ) + z1 Σ1 + z2 Σ2 = 0

z1 Σ−1 −1 −1 −1
1 + z2 Σ2 = x(Σ1 + Σ2 )

Eğer iki belirsizliğin toplamını Σ−1


x olarak özetlersek, yani

Σ−1 −1 −1
x = Σ1 + Σ2

4
Not: Aslında Σx te diyebilirdik, fakat tersi alınmış matrislerin toplamı olduğunu
temsil etmesi için “tersi alınmış bir sembol” kullandık. Tabii diğer yandan tersin
tersini alınca ele geçecek Σx ’in de bir anlamı olduğu iddia edilebilir, bu Σx en
olası x tahmininin yeni belirsizliğidir de bir bakıma.
Simdi ana formule donelim,

z1 Σ−1 −1 −1
1 + z2 Σ2 = xΣx

Σx (z1 Σ−1 −1
1 + z2 Σ2 ) = xMLE

Örnek
Elimizde iki tane iki boyutlu ölçüm var,

   
1 2
z1 = , z2 =
1 −1

Ölçümler iki değişik algılayıcıdan geliyor, belirsizlikleri

   
1 0 4 0
Σ1 = , Σ2 =
0 4 0 1

Nihai ölçüm nedir?

from mpl_toolkits.mplot3d import Axes3D


from matplotlib import cm
import matplotlib.mlab as mlab

x = np.arange(-10.0, 10.0, 0.1)


y = np.arange(-10.0, 10.0, 0.1)

X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, sigmax=1.0, sigmay=4.0,mux=1., \
muy=1.,sigmaxy=0.0)
Z2 = mlab.bivariate_normal(X, Y, sigmax=4.0, sigmay=1.0,mux=2., \
muy=-1.,sigmaxy=0.0)

# iki yuzeyi ayni grafikte birlestirmek icin herhangi iki nokta arasinda
# daha fazla (maksimum) olani al, cunku nihai yuzey olarak onu gormek
# istiyoruz zaten
Z = np.maximum(Z1,Z2)

fig = plt.figure()

ax = Axes3D(fig)
ax.view_init(elev=50., azim=80)

5
ax.plot_surface(X,Y,Z,cmap=cm.jet)
plt.savefig('fusion_1.png')

İki ölçümü Gaussian olarak ekrana bastık, bu Gaussian’ların orta noktası z1 , z2 , bu


durumu maksimum olurluk için aynı olduğunu farz ettiğimiz x ile karıştırmayalım;
o x modelleme sırasında olduğunu farzettiğimiz ideal bir Gaussian idi. Üstte
sadece veri noktalarını ekrana basıyoruz.
Üstten bakışla kontur (contour) olarak gösterirsek

CS = plt.contour(X, Y, Z1,rotation=70)
CS = plt.contour(X, Y, Z2,rotation=70)
plt.savefig('fusion_3.png')

Resimde önce ilk ölçüm, sonra onunla yanyana olacak ikinci ölçüm koyulmuş.

     
1 0 0.25 0 1.25 0
Σ−1
x = Σ−1
1 + Σ−1
2 = + =
0 0.25 0 1 0 1.25

Tersini alalım

6
 
0.8 0
Σx =
0 0.8

xMLE = Σx (z1 Σ−1 −1


1 + z2 Σ2 )

        
0.8 0 1 0 1 0.25 0 2 1.2
xMLE = + =
0 0.8 0 0.25 1 0 1 −1 −0.6

Sonuç grafiklenirse suna benzer (ki yeni belirsizlik Σx ’i de grafikte kullanalım),

Z3 = mlab.bivariate_normal(X, Y, sigmax=0.8, sigmay=0.8,mux=1.2, \


muy=-0.6,sigmaxy=0.0)

fig = plt.figure()

ax = Axes3D(fig)
ax.view_init(elev=40.,azim=80)

ax.plot_surface(X,Y,Z3,cmap=cm.jet)
plt.savefig('fusion_2.png')

Yeni tahminimiz böyle çıktı. Çok daha emin olduğumuz bir noktada en olası
ölçümü ortaya çıkardık. Kontur olarak grafiklersek,

CS = plt.contour(X, Y, Z3)
plt.savefig('fusion_4.png')

7
[1] Zisserman, Lectures 3 & 4: Estimators, www.robots.ox.ac.uk/˜az/lectures/
est/lect34.pdf
[2] Hart, Duda, Pattern Classification

8
Markov Zincirleri (Markov Chains)
Markov Zincirlerinde (MZ) i konumundan j konumuna geçiş olasılığını, Pij gösterir.
Farklı şekile P(Xn+1 = j|Xn = i) olarak açılabilir. Açılımdan görüleceği üzere
bir MZ sonraki adıma geçiş olasılığı için sadece bir önceki adıma bakar. Bu tür
önce/sonra yapısındaki iki boyutlu hal, çok rahat bir şekilde matrise çevirilebilir.
Önceki konum satırlar, sonraki konum kolonlar olarak temsil edilir mesela.
Örnek
Bir sonraki günde yağmur yağmayacağını bir MZ olarak tasarlayalım [1, sf 196].
Bir sonraki günde yağmur yağmayacağını sadece bugün etkiliyor olsun. Eğer
bugün yağmur yağıyorsa yarın yağmur yağması 0.7, eğer bugün yağmıyor ise
yarın yağması 0.4. MZ şöyle

 
0.7 0.3
P=
0.4 0.6

Geçiş olasılıklarından bahsettiğimize göre ve elimizde sınırlı / belli sayıda konum


(state) olduğu için, bir MZ’nin her satırındaki olasılıkların toplamı tabii ki 1’e eşit
olmalıdır.
n
MZ’lerin ilginç bir özelliği n adım sonra i, j geçişinin Pi,j hesabıyla yapılabilmesidir.
Yani P’yi n defa kendisiyle çarpıp i, j indislerindeki öğeye bakarsak n adım son-
rasını görüyoruz. İspat altta [1, sf. 195].
Bulmak istediğimiz n adım sonrası geçiş olasılıkları, yani i adımında olan sürecin
n adım sonra j adımında olma olasılığı. Aradığımız,

n
Pij = P(Xn+k = j|Xk = i), n > 0, i, j > 0

1
Tabii ki Pij = Pij . Chapman-Kolmogorov denklemleri bu n-adım geçişlerini
hesaplamak için bize bir yöntem sağlıyoar. Bu denklemler,

X

n+m n m
Pij = Pik Pkj , ∀n, m > 0, ∀i, j (1)
k=0

n+m
Pij formülü şunu söylüyor, i’de başlayan süreç n + m geçiş sonrası j’e varacak,
ve geçtiği yol onu n anında k’den geçirecek. O zaman tüm bu geçiş noktaları k’ler
üzerinden bir toplam alırsak sürecin n + m adım sonrası j’de olma olasılığını elde
etmiş oluyoruz.
Formel olarak

n+m
Pij = P(Xn+m = j|X0 = i)

1
söylenmiş oluyor. Üstteki olasılık hesabına / birleşik olasılığa k’den geçme ak-
siyonunu ekleyip aynı anda tüm k’ler üzerinden toplam alırsak (entegre edip
çıkartma tekniği -integrate out-) hiçbir şey değiştirmemiş oluruz,

X

= P(Xn+m = j, Xn = k|X0 = i)
k=0

X

= P(Xn+m = j, Xn = k, X0 = i)P(Xn = k|X0 = i)
k=0

Üstteki ifade diyor ki,

X

n+m m n
Pij = Pkj Pik
k=0

Ayrıca dikkat edersek (1)’deki tarif

Pn+m = Pn · Pm

işlemini ima ediyor. Nokta işareti çarpım işlemi, çünkü hatırlarsak matris çarpımının
tanımı şöyleydi; elimizde N x M boyutunda A matrisi var, B ise M x K boyutunda
olsun, her ikisinin i satırı j kolonundaki öğesi aij , bij ise, A · B çarpımı bir N x K
P
matrisidir, bu matrisin i, j öğesi Mk=1 aik bkj ile verilir. Toplamın üst sınırı sonsuz
değil M fakat sonsuzluk üst sınırı genel bir formül için tanımlanmış zaten.
İlk örneğe dönersek, eğer bugün yağmur yağıyorsa 4 gün sonra yağmur yağma
olasılığı nedir?

import numpy.linalg as lin


P = np.array([[0.7,0.3],[0.4,0.6]])
P4 = lin.matrix_power(P,4)
print P4
[[ 0.5749 0.4251]
[ 0.5668 0.4332]]

Aradığımız geçiş için kordinat 0,0’a bakıyoruz ve sonuç 0.5749. Numpy matrix_power
bir matrisi istediğimiz kadar kendisiyle çarpmamızı sağlıyor.
Durağan Dağılım (Stationary Distribution)
Eğer yağmur örneğindeki matrisi çarpmaya devam edersek, mesela 8 kere ken-
disiyle çarpsak sonuç ne olurdu?

import numpy.linalg as lin


P = np.array([[0.7,0.3],[0.4,0.6]])
P8 = lin.matrix_power(P,8)
print P8

2
[[ 0.57145669 0.42854331]
[ 0.57139108 0.42860892]]

Dikkat edilirse, her satır bir değere yaklaşmaya başladı. Bu değer MZ’nin durağan
dağılımıdır, belli koşullara uyan her MZ’nin böyle bir durağan dağılımı vardır.
Bu koşullar MZ’nin periyodik olmayan (aperiodic) ve tekrar eden (recurrent) ol-
masıdır. Bu şartlar çok “özel” şartlar değildir aslında, daha çok “normal” bir
MZ’yi tarif ediyor diyebiliriz. Tüm konumları tekrar eden yapmak kolaydır, MZ
tek bağlı (singly connected) hale getirilir, yani her konumdan her diğer konuma
bir geçiş olur, ve periyodik olmaması için ise MZ’de olmadığı zamanlarda bir
konumdan kendisine geçiş sağlanır (az bir gürültü üzerinden).
Neyse, matematiksel olarak durağanlık şu denklemi ortaya çıkartır,

π = πP

Burada durağan dağılım π’dir. Bu denklem tanıdık geliyor mu? Devriğini alarak
şöyle gösterelim, belki daha iyi tanınır,

PT πT = πT

Bir şey daha ekleyelim,

P T πT = 1 · πT

Özdeğer/vektör formuna benzemiyor mu? Evet. Bu form,

Ax = λx

MZ denklemi şunu söylüyor, 1 değerindeki özdeğere ait özvektör bir MZ’nin


durağan dağılımıdır. Bu arada, MZ geçiş matrisi P’nin en büyük özdeğerinin
her zaman 1 olduğunu biliyoruz (çünkü üstteki tarif ettiğimiz özel şartlara sahip
olan türden matrisler böyle özdeğerlere sahip olmalı). Bu durumda en büyük
özdeğere ait özvektörü hesaplamak yeterli olacaktır. Bunu yapmayı zaten [2]’de
öğrenmiştik, üst metot (power method) sayesinde bu hesap kolayca yapılabiliyor.
MZ kavramının ilginç bir uygulaması için [3] yazısına bakılabilir.
Çizitler ve Matrisler
Markov matrisleri kavramını biraz daha ilerletebiliriz. Üstteki Markov örneği
için mesela alttaki çizit gösterilebilir,

3
Örnekteki durumda 1’den başlayınca hangi olasılıkla hangi diğer düğüme at-
landığı görülebiliyor. Bu geçiş olasılıklarına göre zar atılıp geçiş yapılabilir. Markov
matrisleri bu bağlamda kendi içindeki geçişleri gösteriyor, sürekli 1,2,3,.. düğümleri
arasında gidip geliyoruz. 1’den 3’e geçiş için 1’inci satır 3’üncü kolona bakıyoruz,
bir sonraki geçiş için P2 ’nin 3’üncü satırına bakıyoruz.
Bu kavramı daha da genişletebiliriz. Bir çizitin katman katman, farklı blokları
arasındaki geçişleri de ayrı matris çarpımları olarak gösterebiliriz.

Mesela her X bölümündeki konumlardan Y bölümündeki konumlara geçişleri,


oradan Z konumlarına geçişleri matris olarak göstermek mümkün, bu durumda
matris çarpımı X ve Z arasındaki tüm geçişlerin bir toplamı haline gelir, tüm
mümkün gidiş yollarının ağırlığını bu çarpımda görebiliriz. Üstteki örnekte mesela
her geçiş bir olasılık hesabı taşıyabilirdi, o zaman M · N çarpımında her Z kon-
umuna herhangi bir X konumundan varma olasılığını taşırdı. Ya da tüm bir Z
konumuna varma olasılığı en fazla olan X başlangıcını bu matriste görebilirdik.
Bu tür bir yaklaşımın kullanma alanı geniştir. Mesela her katmanda farklı karar
seçenekleri, olasılıkları olabilir, ve ara katmanlar binlerce, milyonlarca seçimi
içerebilir. Fakat zincirleme bir matris çarpımı ile o tüm ara katmanların toplamını
almış oluyoruz, ve elimizde üstteki başlangıç ve bitiş için 3 x 2 boyutunda bir ma-
tris kalıyor.
Kaynaklar
[1] Ross, Introduction to Probability Models, 10th Ed
[2] Bayramlı, Lineer Cebir, Ders 21
[3] Bayramlı, Lineer Cebir, Google Nasıl İşler?
[4] Math3ma, https://www.math3ma.com/blog/matrices-probability-
graphs

4
Monte Carlo, Entegraller, MCMC
Fizik, biyoloji ve özellikle makina öğrenimi problemlerinde bazen çok boyutlu
bir fonksiyon üzerinden entegral almak gerekebiliyor. En basit örnek, mesela bir
dağılımın başka bir fonksiyon ile çarpımının beklentisini (expectation) hesapla-
mak gerektiğinde, ki bu
Z
E(f) = p(x)h(x) dx

entegralidir, x ∈ Rn , p(x) dağılım fonksiyonu, h(x) herhangi bir başka fonksiyon


olmak üzere, o zaman tüm x değerlerini göz önüne alarak (ayrıksal bağlamda ya
teker teker geçerek, ya da analitik olarak) entegral hesabını yapmak gerekecekti.
Fakat p(x) bir dağılım olduğuna göre, ve bizim geçtiğimiz her x için bir olasılık
değeri varsa, bu işi tersine çevirerek, p(x)’teki olasılıklara göre belli (az) sayıda x
ürettirirsek, ve sadece bu x’leri entegral hesabında kullanırsak yaklaşıksal açıdan
gerçek entegral hesabına yaklaşmış oluruz.
Bu mantıklı değil mi? Düşünürsek, mesela 10 değeri 0.4 olasılığında ise, 5 değeri
0.1 olasılığında ise, hem sayı, hem olasılığı ile çarpmak yerine “daha fazla 10
değeri üretmek” ve bu değerleri h’e geçmek, toplamak, sonra bölmek, vs. yaklaşıksal
olarak aynı kapıya çıkar. Yani

1 X
N
EN = h(x(i) )
N 1=1

üstteki entegralin yaklaşıksal temsilidir, x(i) p(x) olasılığına göre üretilen sayıları
temsil ediyor. Üstteki bağlantının teorik olarak ispatı da var, bu ispatı burada
vermeyeceğiz.
İşte Monte Carlo entegral hesabının artasında yatan numara budur.
Demek ki Monte Carlo entegralının işlemesi için p(x)’den örnekleme yapmak
gerekiyor. Şimdi ikinci numaraya gelelim. Bazen ne yazık ki p(x)’den örnekleme
yapmak kolay olmuyor. Mesela alttaki bölümdeki entegralın hesabı zorlaşıyor,
R
h(x)p(x) dx
I= R
p(x) dx

ki bölünende yine h(x)’e göre beklenti almış oluyoruz. Bu durumda q(x) adında
kolay örneklenebilen başka bir yoğunluk fonksiyonu buluyoruz. Ve formülü şu
hale getirerek bir şey değiştirmiş olmayız [3],

R p(x)
h(x) q(x) q(x) dx
I= R p(x)
q(x)
dx

1
Bu formül bir nevi q(x)’e göre alınmış beklentilerin oranı. Aynı numarayı kul-
lanıp entegralı toplam haline getirebiliriz, xi değerleri i = 1, .., N i.i.d olarak
q(x)’ten örneklenir, o zaman I’yi yaklaşık olarak Î olarak hesaplarız,

1
PN p(x)
N =1h(x) q(x) dx
Î = 1
P p(x)
N q(x)
dx

Bölünendeki bir q(x)’in yokolduğuna dikkat.


Yeni bir değişken w̃i = p(x)/q(x) oranı tanımlayabiliriz, normalize edilmiş halde,

w̃i p(xi )/q(xi )


wi = P == P
w̃j p(xi )/q(xi )

Son formülü iki üstteki formül içine koyarsak,

X
N
Î = wi h(xi )
i=1

Bu metota Önemsel Örnekleme metotu adı veriliyor çünkü üstteki ağırlıklar bir
nevi “önemi” temsil ediyorlar. Bir örnek [1]’den görelim; q(x) için birörnek bir
dağılım seçilmiş, belli değerler arasında hep aynı değeri donduruyor.

def qsample(): return np.random.rand()*4.

def p(x): return 0.3*np.exp(-(x-0.3)**2) + 0.7* np.exp(-(x-2.)**2/0.3)

def q(x): return 4.0

def importance(nsamples):
samples = np.zeros(nsamples,dtype=float)
w = np.zeros(nsamples,dtype=float)
for i in range(nsamples):
samples[i] = qsample()
w[i] = p(samples[i])/q(samples[i])
return samples, w

x = np.arange(0,4,0.01)
x2 = np.arange(-0.5,4.5,0.1)
realdata = 0.3*np.exp(-(x-0.3)**2) + 0.7* np.exp(-(x-2.)**2/0.3)
box = np.ones(len(x2))*0.8
box[:5] = 0; box[-5:] = 0
plt.plot(x,realdata,'k',lw=6)
plt.plot(x2,box,'k--',lw=6)
samples,w = importance(5000)
plt.hist(samples,normed=1,fc='k')
plt.savefig('stat_mcmc_02.png')

2
Altta Örnekleme ve Öneme Göre Tekrar Örnekleme (Sampling İmportance Re-
sampling) metotu için örnek kod,

def p(x): return 0.3*exp(-(x-0.3)**2) + 0.7* exp(-(x-2.)**2/0.3)

def q(x): return 4.0

def sir(n):
sample1 = np.zeros(n)
w = np.zeros(n)
sample2 = np.zeros(n)
sample1 = np.random.rand(n)*4
w = p(sample1)/q(sample1)
w /= sum(w)
cumw = zeros(len(w))
cumw[0] = w[0]
for i in range(1,len(w)): cumw[i] = cumw[i-1]+w[i]
u = np.random.rand(n)
index = 0
for i in range(n):
indices = where(u<cumw[i])
sample2[index:index+size(indices)] = sample1[i]
index += size(indices)
u[indices]=2
return sample2

x = np.arange(0,4,0.01)
x2 = np.arange(-0.5,4.5,0.1)
realdata = 0.3*np.exp(-(x-0.3)**2) + 0.7* np.exp(-(x-2.)**2/0.3)
box = np.ones(len(x2))*0.8
box[:5] = 0
box[-5:] = 0
plt.plot(x,realdata,'k',lw=6)
plt.plot(x2,box,'k--',lw=6)
plt.savefig('stat_mcmc_03.png')

3
MCMC
Yine p(x)’den örnekleme yapılamadığı durum, bu sefer p(x) yerine onu yaklaşıksal
olarak temsil eden bir π(x)’i elde etmekle uğraşılıyor. Bu π(x) işe bir Markov
Zincirinin (Markov Chain -yine MC harfleri!-) durağan dağılımı olarak hayal
ediliyor.
Markov Zinciri teorisinde bir geçiş matrisi, yan Markov Zincirinin kendisi ver-
ilir, ve durağan dağılımın hesaplanması istenir. MCMC problemlerinde ise, yani
Monte Carlo entegralı için Markov Zinciri kullanıldığı durumlarda elimizde bir
π(x) dağılımı vardır ve bir Markov Zinciri oluşturmamız gerekir. Nihai dağılımı
biliriz, ve bu dağılıma “giden” geçişleri üretiriz. Bu geçişleri öyle ayarlayabiliriz
ki üretilen rasgele sayılar hedef dağılımından geliyormuş gibi olur.
Geçişleri üretmek için literatürde bir çok teknik vardır. Önemsel Örnekleme (Im-
portance Sampling), Örnekleme ve Öneme Göre Tekrar Örnekleme (Sampling
İmportance Resampling), Metropolis-Hastings, Gibbs Örneklemesi gibi teknikleri
vardır, ve detayları değişik olsa da hepsi de MCMC kategorisine girer, ve yap-
maya çalıştıkları π(x)’e giderken bir şekilde bir geçişleri, zinciri ortaya çıkartmak
ve bu geçişleri entegral hesabında kullanmaktır.
Üstteki tekniklerden en yaygın kullanılanı Metropolis-Hastings algoritmasıdır.
Şunu vurgulamak önemli, geçişleri üretmek, “bir tür sanal Markov Matrisi” yarat-
maktır aslında. Ve her MCMC algoritması bunu farklı şekillerde yapabilir; mesela
MH daha basit başka bir dağılım ile ana dağılım arasında sürekli karşılaştırmalar
yapar, belli aralıklarda geçiş yapar, diğerlerinde yapmaz, ve bunun bir yan etkisi
olarak ortaya bir Markov Zinciri çıkartmış / onu kullanmış olur. O geçişlerin bir
Markov Zinciri’ne eşdeğer olduğunun matematiksel olarak ispatı da vardır.
Not: Bu alandaki makalelerde bir dağılımın “belli bir çarpımsal sabite kadar”
bilindiği (known up to a multiplicative constant) söylenir. Bu söz aslında şu an-
lama gelir. Mesela ayrıksal bir dağılımımız var, ama bu dağılımın kendisini, şu
halini biliyoruz
[ 4.3 2. 8.4 8.7 1.8]

4
Bu bir dağılım değil, çünkü öğelerin toplamı 1 değil. Onu bir dağılım haline
çevirmek için, tüm öğeleri toplamak ve bu vektördeki tüm sayıları bu toplam ile
bölmek gerekir. Toplam 25.2, bölersek
[ 0.17063492 0.07936508 0.33333333 0.3452381 0.07142857]

İlk vektör “belli bir çarpımsal sabite kadar” bilinen dağılım, çarpımsal sabit 25.2.
Esas dağılım ikinci vektör.
Peki niye bu sözü söyleyenler toplamı hesaplayıp gerçek dağılımı hesaplamıyorlar?
Sebep performans. Bazen ayrıksal dağılım o kadar yüksek boyutlu, fazla öğe
içeren bir halde oluyor ki, performans açısından bu basit toplam hesabını yap-
mak bile çok pahalı oluyor. İşte MCMC metotlarının bir güzel tarafı daha burada,
dağılımın kendisi olmasa bile belli bir çarpımsal sabite kadar bilinen versiyonları
ile gayet rahat bir şekilde işliyorlar.
Metropolis-Hastings

def p(x):
mu1 = 3; mu2 = 10
v1 = 10; v2 = 3
return 0.3*np.exp(-(x-mu1)**2/v1) + 0.7* np.exp(-(x-mu2)**2/v2)

def q(x):
mu = 5; sigma = 10
return np.exp(-(x-mu)**2/(sigma**2))

stepsize = 0.5
x = np.arange(-10,20,stepsize)
px = np.zeros(x.shape)
for i in range(len(x)): px[i] = p(x[i])
N = 5000

# independence chain
u = np.random.rand(N)
mu = 5
sigma = 10
y = np.zeros(N)
y[0] = np.random.normal(mu,sigma)
for i in range(N-1):
ynew = np.random.normal(mu,sigma)
alpha = min(1,p(ynew)*q(y[i])/(p(y[i])*q(ynew)))
if u[i] < alpha:
y[i+1] = ynew
else:
y[i+1] = y[i]

# random walk chain


u2 = np.random.rand(N)
sigma = 10
y2 = np.zeros(N)
y2[0] = np.random.normal(0,sigma)
for i in range(N-1):
y2new = y2[i] + np.random.normal(0,sigma)

5
alpha = min(1,p(y2new)/p(y2[i]))
if u2[i] < alpha:
y2[i+1] = y2new
else:
y2[i+1] = y2[i]

plt.figure(1)
nbins = 30
plt.hist(y, bins = x)
plt.plot(x, px*N/np.sum(px), color='r', linewidth=2)

plt.savefig('stat_mcmc_01.png')

Gibbs Örneklemesi
Bu örnekleme metodu Metropolis yönteminin bir versiyonu olarak kabul edilir,
Metropolis yöntemlerinde bir teklif (proposal) dağılımı Q vardır, ve bu dağılımın
örneklenmek istenen P ile ilişkisine göre zar atılıp elde edilen yeni nokta kabul
edilir, ya da kenara atılır. Gibbs ile de bir Q vardır, ama bir cinlik yapılmıştır,
Q için P’nin kendisi, daha doğrusu onun koşullu dağılım hali kullanılır. Bu
koşullu dağılım her i için P(xi |{xj }j6=i , burada xi çok boyutlu x’in bir öğesidir,
{xj }j6=i işe i olmayan diğer tüm öğelerdir. Yani i olmayan her değişken koşulunda
i örneklenir. Bu kullanımın Metropolis yöntemi ile aynı olduğu ispatlanmıştır.
Koşullu dağılımın kullanılmasının ana sebebi ise çok boyutlu P zor bir dağılım
olsa bile çoğunlukla onun koşullu ve tek boyutlu dağılımının rahatça örneklenebilir
halde olmasıdır.
Algoritma şöyle; Rasgele bir başlangıç noktasından başlanır, ve biri harici tüm
değişkenler sabit tutulup sabit olmayan değişken örneklenir. Bu işlem sürekli
uygulanır, bu yapılınca sanki örneklenen dağılımın en olası yerleri gezilmiş olur.
Mesela 2 boyutta, bir x(t) noktasından başladığımızı farzedelim, P(x1 |x2 ) dağılımından
bir x1 örneklenir, (b) şeklinde koşullu dağılımın tek boyutlu bir Gaussian olduğunu
görüyoruz (çünkü ana dağılım iki boyutlu Gaussian), bu tek boyutlu dağılımdan
bir örneklem alınıyor, doğal olarak o tek boyutlu dağılımın tepe noktasının altına
yakın bir yerden.

6
Sonra bu nokta sabitleniyor (yani yeni bir koşullu dağılım yaratılıyor, ve örneklenen
x1 şimdi sağ tarafta), yani P(x2 |x1 ) dağılımından. Bu bizi x(t+1) konumuna (state)
götürüyor, bu böyle devam ediyor. K değişken (boyutundaki) içeren bir sistemde,
genel formüller şöyle,

(t+1)
x1 ∼ P(x1 |xt2 , xt3 , .., xtK )

(t+1)
x2 ∼ P(x2 |xt1 , xt3 , .., xtK )

(t+1)
x3 ∼ P(x3 |xt1 , xt2 , .., xtK )

vs..
Monte Carlo ile pi Hesabı
Yaklaşık olarak π’yi nasıl hesaplarız? İçinde π olan hangi formülü biliyoruz?
Çember alanı formülü. Bunu nasıl kullanabiliriz. Yarıçapı r olan bir çember
düşünelim, ve bu çember bir kare içinde olsun, yani karenin kenarları 2r,

7
Bu durumda kırmızıyla işaretli bölgenin alanı r2 . Mavi çemberin alanı ise πr2 ,
çemberin kırmızı bölge içine düşen kısmi πr2 /4. O zaman ufak karenin oradaki
2
çember kısminin alanına olan oranı p = πr4 olur. O zaman, eğer iki boyutlu
birörnek bir dağılımdan (yani üstteki karenin içine düşecek sayılar) örneklem
alırsak, bu her sayı için çember içine mi düşüyor, dışına mı düşüyor hesabı kolay,
x, y sayısı için x2 +y2 < r2 ise çember içinde, değilse dışında. İçeri düşen sayıların
oranını p kabul ederiz, bu sayıyı 4 ile çarpınca yaklaşık π elde edilir.

import random

NB_POINTS = 10**4
LENGTH = 10**5
CENTER = [LENGTH/2,LENGTH/2]

def in_circle(point):
x,y = point
center_x, center_y = CENTER
radius = LENGTH/2
return (x - center_x)**2. + (y - center_y)**2. < radius**2.

def compute_pi(nb_it):
inside_count = sum(1.0 for _ in range(nb_it) if \
in_circle( (random.randint(1,LENGTH),random.randint(1,LENGTH)) ) )
return (inside_count / nb_it) * 4.

if __name__ == "__main__":
print u'yaklaşık', compute_pi(NB_POINTS), u'gerçek', np.pi

yaklaşık 3.1432 gerçek 3.14159265359

Kaynaklar
[1] Marsland, Algorithmic Machine Learning
[2] MacKay, Information Theory, Inference and Learning Algorithms
[3] Turner, An Introduction to Particle Filtering, http://www.lancaster.ac.
uk/pg/turnerl/PartileFiltering.pdf

8
Değişim Noktası Analizi (Changepoint Analysis)
İngiltere’de 1851 ve 1962 yılları arasında kömür madenlerinde olan kazaların
sayısı yıllık olarak kayıtlıdır. Acaba bu kazaların dağılımına bakarak, değişimin
olduğu seneyi bulabilir miyiz? Böyle bir değişim anı neyi gösterir? Belki maden-
lerle alakalı regülasyonlarda, denetimlerde bir değişiklik olmuştur, ve kaza oranı
azalmıştır [1, 2], [3, sf. 141]. Veriye bakalım.

import pandas as pd
coal = pd.read_csv('coal.txt',header=None)

coal.hist(bins=7)
plt.savefig('stat_coal_02.png')

Eğer veride bir değişim noktası var ise, bu durum veride iki fark bölge olduğunu
gösterir, ki bu bölgelerin iki farklı dağılımla temsil edileceğini tahmin edebiliriz.
Aynı zaman diliminde vuku bulan olay toplamlarının (event counts) Poisson
dağılımına sahip olduğunu biliyoruz. O zaman, belki de ilk yapmamız gereken
bu veriye iki tane Poisson uydurmak, yani veriyi iki Poisson dağılımının karışımı
olarak temsil etmek. Karışımlar konusu [5] yazısında görülebilir, buradaki tek
fark Bernoulli yerine Poisson kullanılacak olması. İdeal olarak uydurma operasy-
onu için Beklenti-Maksimizasyon (Expectation-Maximization -EM-) kullanılır. Fakat
denklemleri türetmek zaman alabilir, biz şuradaki tavsiyeyi [4, sf. 11] takip ed-
erek bu örnek için uydurmayı bir gayrı lineer optimizasyon paketi lmfit ile ya-
pacağız (tavsiyenin R kodu coal.r içinde).

from scipy.stats.distributions import poisson


from lmfit import Parameters, minimize
from lmfit.printfuncs import report_fit

def f(pars,x):
m1 = pars['m1'].value
lam1 = pars['lam1'].value
lam2 = pars['lam2'].value
model = m1*poisson(lam1).pmf(x) + (1-m1)*poisson(lam2).pmf(x)

1
return model

def residual(pars,y,x):
return -np.log(f(pars,x).T[0])

fit_params = Parameters()
fit_params.add('m1', value=0.5, min=0,max=1.)
fit_params.add('lam1', value=1.0, min=1.,max=7.)
fit_params.add('lam2', value=2.0, min=2.,max=7.)

out = minimize(residual, fit_params, args=(coal,coal,))


report_fit(fit_params)

[[Variables]]
m1: 0.51428096 +/- 0.406949 (79.13%) (init= 0.5)
lam1: 1.00000004 +/- 0.557045 (55.70%) (init= 1)
lam2: 3.35150806 +/- 1.791094 (53.44%) (init= 2)
[[Correlations]] (unreported correlations are < 0.100)
C(m1, lam1) = 0.905
C(m1, lam2) = 0.878
C(lam1, lam2) = 0.772

Sonuçlar yaklaşık λ1 = 1, λ2 = 3 (tam sayıya yuvarladık, çünkü olay sayısı tam


sayı olmalı). Bu iki dağılımı verinini normalize edilmiş histogramı üzerinde gösterirsek,

from scipy.stats.distributions import poisson


coal.hist(bins=7,normed=True)
plt.hold(True)
p = poisson(1.0)
x = np.arange(1,10)
plt.plot(x, p.pmf(x))
p = poisson(3.0)
plt.hold(True)
plt.plot(x, p.pmf(x))
plt.savefig('stat_coal_03.png')

Peki bu bulguyu şimdi değişim noktası keşfine nasıl çevireceğiz? Dikkat, üstteki
iki dağılımın ayrıldığı λ anı değil aradığımız, verideki senesel akış içinde hangi
sene sonrası bir dağılımın diğerinin yerine geçtiği.

2
Şöyle bir yaklaşım olabilir mi acaba: bir döngü içinde potansiyel ayraç noktası
olabilecek tüm seneler için veriyi iki parçaya ayırırız. Sıfır hipotezi nedir? Bu
veri parçaları üstteki bulduğumuz Poisson dağılımlarından geliyor. O zaman
şöyle devam ederiz: Üstteki optimizasyondan elimizde her iki dağılımın beklen-
tisi, yani λ değerleri var, ve Poisson dağılımlarının bir avantajı beklentisinin ve
varyansının aynı olması! Şimdi, eğer her iki parçanın sayısal ortalamasını ve sıfır
hipoteze göre bilinen µ, σ2 (her ikisi de λ) üzerinden standardize edersek, yani
N(0, 1) haline getirirsek, elimize iki tane N(0, 1) geçer, diyelim ki Z1 , Z2 . Bunların
karelerinin toplamının chi kare olacağını biliyoruz. Sıfır hipotezine göre böyle
olmalı. O zaman bundan “sapma” sıfır hipotezinden ne kadar uzaklaşıldığını
gösterir, bu bağlamda en yüksek p-değerini veren ayraç noktası bize değişim
anını verir.
Daha detaylı matematiği vermek gerekirse; Merkezi Limit Teori’sine göre bir-
birinden bağımsız, aynı dağılımlı X1 , .., Xn ’in, ki her birinin beklentisi E(Xi ) = µ
ve varyansı Var(Xi ) = σ2 , o zaman sayısal ortalama X̄ üzerinden, ve n → ∞

X̄ − µ
Z= √
σ n

yani standard normal Z ∼ N(0, 1). Daha önce belirttiğimiz gibi Poisson için µ =
σ2 .
Gerekli olan diğer teori: χ2n ∼ Z21 + ... + Z2n , yani n tane standart normalın toplamı
yaklaşık olarak serbestlik derecesi n olan chi kare dağılımı. Bu iki bilgiyi yan
yana koyarsak, ve üstte bahsettiğimiz döngüyü yazarsak,

from scipy.stats import chi2


# buyuk olan lambda degerini ilk parca icin kullaniyoruz, cunku
# test ettigimiz kaza oranlarinin once fazla sonra az olmasi
lam1 = 3.; lam2 = 1.
dof = 2
res = []
cutoffs = range(20,80)
for cutoff in cutoffs:
p1 = coal[0:cutoff]; p2 = coal[cutoff+1:]
z1 = (p1.mean()-lam1) / lam1*np.sqrt(len(p1))
z2 = (p2.mean()-lam2) / lam2*np.sqrt(len(p2))
chi = z1**2+z2**2
res.append(float(1-chi2.cdf(chi,dof)))

print 1851 + cutoffs[np.array(res).argmax()]

1885

Tarihten biliyoruz ki değişimin sebebi büyük ihtimalle İngiltere’de 1887 yılında


kanunlaşan Kömür Madenleri Yasası’dır [3]. Yakınlık fena değil.
Ödev: Verinin iki tane Poisson karışımıyla temsil edilmesi gerektiğinden emin ol-
mak istiyorsak, AIC kullanarak tek Poisson uyumu, daha sonra karışımın uyumu

3
için ayrı ayrı AIC’leri hesaplayarak hangisinin daha düşük olduğuna göre bu
kararı verebiliriz.
Bayes ve MCMC
Bir değişik yöntem Bayes yaklaşımını kullanarak ve hesapsal olarak Markov Chain
Monte Carlo (MCMC) tekniği. Kazaların sayısının tümünü iki Poisson dağılımının
ortak dağılımı (joint distribution) üzerinden modelleyeceğiz, ve bu dağılımların
birinci Poisson’dan ikincisine geçtiği anı hesaplamaya uğraşacağız.
Poisson dağılımı

e−θ θy
p(y|θ) =
y!

Eldeki n tane veri noktası y = y0 , y1 , ..., yn ’nin hep birlikte θ ile tanımlı bir Poisson
dağılımından gelip gelmediğinin ne kadar mümkün olduğu (likelihood) hesabı
şöyledir:
P
e−nθ θ yi
p(y|θ) = Q
yi !

Formülün bölünen kısmındaki tüm y noktaları toplanıyor, bölen kısminde ise


tüm y değerleri teker teker faktoryel hesabı sonrası birbiri ile çarpılıyor.
Şimdi yukarıdaki θ değişkeni de noktasal bir değer yerine bir ”dağılıma”, mesela
θ Gamma dağılımına sahip olabilirdi: Gamma(α, β). Formülde α, β sabit değerlerdir
(fonksiyon değişkeni değil). Gamma olasılık formülü şöyledir:

βα α−1 −βθ
p(θ) = θ e
Γ (α)

O zaman p(y|θ) formülünü bulmak için Bayes teorisini kullanmamız gerekecekti.


Bayes teorisi bilindiği gibi

p(y|θ)p(θ)
p(θ|y) =
p(y)

p(θ|y) ∝ p(y|θ)p(θ)

İkinci formüle dikkat, eşitlik yerine orantılı olma (proportional to) işaretini kul-
lanıyor. Sebep: bölen kısmındaki p(y)’yi kaldırdık, sonuç olarak soldaki p(θ|y)
değeri artık bir dağılım değil – bu bir bakımdan önemli ama örnekleme amacı için
bir fark yaratmıyor, basitleştirme amacıyla bunu yaptık, böylece p(y)’yi hesapla-
mamız gerekmeyecek, ama örnekleme üzerinden diğer tüm hesapları hala yapa-
biliriz. Tamam.

4
Şimdi Bayes Teorisini Gamma önsel (apriori) ve Poisson olurluğu (likelihood)
üzerinden kullanırsak,
P
βα α−1 −βθ e−nθ θ y
p(θ|y) = θ e × Q
Γ (α) y!

Benzer terimleri yanyana getirelim:

βα P
p(θ|y) = Q θα−1 θ y e−βθ e−nθ
Γ (α) y!

Şimdi sol taraftaki bölümü atalım; yine üsttekine benzer numara, bu kısım gid-
ince geri galan dağılım olamayacak, ama ona ”oranlı” başka bir formül olacak.

P
p(θ|y) ∝ θα−1 θ y −βθ −nθ
e e

P
∝ θα−1+ y −(β+n)θ
e

Bu dağılım nedir? Formülün sağ tarafı Gamma P dağılımının formülüne benzemiyor


mu? Evet, formülün sağ tarafı Gamma(α+ y, β+n) dağılımı, yani ona orantılı
olan bir formül. Yani Bayes teorisi üzerinden şunu anlamış olduk; eğer önsel
dağılım Gamma ise, Poisson mümkünlük bizi tekrar Gamma sonuç dağılımına
götürüyor. Gamma’dan başlayınca tekrar Gamma’ya ulaşıyoruz. Bu bir rahatlık,
bir kolaylık, bir matematiksel numara olarak kullanılabilir. Sonsal (posterior)
dağılımların şekli, hesaplanma, cebirsel işlemler açısından önemli, eğer temiz,
kısa, öz olurlarsa hesap işlerimiz kolaylaşır.
Not: Hatta üzerinde çalıştığımız problem sebebiyle eğer Poisson mümkünlük
olacağını biliyorsak, sadece bu sebeple bile önsel dağılımı, üstteki kolaylık bilindiği
için, özellikle Gamma seçebiliriz, çünkü biliriz ki Gamma ile başlarsak elimize
tekrar Gamma geçecektir.
Şimdi kömür madeni verisine gelelim. Bu madendeki kazaların sayısının Pois-
son dağılımından geldiğini öne sürüyoruz, ve kazaların ”iki türlü” olduğunu
bildiğimizden hareketle, birinci tur kazaların ikinci tur kazalardan değişik Pois-
son parametresi kullandığını öne süreceğiz.
O zaman değişim anını, değişim senesini nasıl hesaplarız?
Kazaların ilk k senede ortalama θ ile, ve k ve n arasındaki senelerde ortalama λ
Poisson ile dağıldığını söyleyelim: Yani

Yi = Poisson(θ) i = 1, .., k

Yi = Poisson(λ) i = k + 1, .., n

5
Burada Yi sene i sırasında olan kazaların sayısını belirtiyor. Bayes kuralını hatırlarsak
θ ve λ parametrelerine önsel dağılım atayacağız. Bu dağılım Gamma olacak. Yani
θ ∼ Gamma(a1 , b1 ) ve λ ∼ Gamma(a2 , b2 ).
Ayrıca k değerini de bilmiyoruz, k değeri yani ”değişim noktası” Poisson dağılımların
birinden ötekine geçtiği andır. Bu seneyi bulmaya çalışıyoruz. Şimdi tüm verinin,
tüm seneleri kapsayacak şekilde modelini kurmaya başlayalım. k parametresinin
aynen öteki parametreler gibi bir önsel dağılımı olacak (ki sonradan elimize k için
de bir sonsal dağılımı geçecek), ama bu parametre elimizdeki 112 senenin her-
hangi birinde ”eşit olasılıkta” olabileceği için onun önsel dağılımı Gamma değil
k ∼ Unif(1, 112) olacak. Yani ilk başta her senenin olasılığı birbiriyle eşit, her sene
1
112
olasılık değeri taşıyor.
Bu modelin tamamının olurluğu nedir?

1 Y
k
e−θ θyi Yn
e−λ λyi
L(θ, λ, k|y) = × ×
112 i=1 yi ! i=k+1
yi !

Sonsal geçişini yapınca yukarıda olduğu gibi Gamma dağılımlarını elde ederiz:

Pk P
yi −(b1 +k)θ a2 −1+ n
L(θ, λ, k|y) ∝ θa1 −1+ i=1 e λ i=k+1 yi −(b2 +n−k)λ
e
1
112
’yibir sabit olduğu için formülden attık, bu durum orantılı hali etkilemiyor.
Üstteki formül içindeki Gamma dağılımlarını görebiliyoruz, hemen yerlerine koyalım:

X
k X
n
L(θ, λ, k|y) ∝ Gamma(a1 + yi , b1 + k) Gamma(a2 + yi , b2 + n − k)
i=1 i=k+1

Gibbs örneklemeye gelelim. Bu örneklemeye göre şartsal dağılım (conditional


distribution) formülü bulunmaya uğraşılır, hangi değişkenlerin verili olduğuna
göre, o değişkenler sabit kabul edilebilir, ve orantısal formülden atılabilir. Bu her
değişken için teker teker yapılır.
Sonra hesap sırasında her şartsal dağılıma teker teker zar attırılır, ve elde edilen
değer, bu sefer diğer şartsal dağılımlara değer olarak geçilir. Bu işlem sonuca
erişilinceye kadar özyineli (iterative) olarak tekrar edilir (mesela 1000 kere). O
zaman,

X
k
θ|Y1 , .., Yn , k ∼ Gamma(a1 + yi , b1 + k)
i=1

X
n
λ|Y1 , .., Yn , k ∼ Gamma(a2 + yi , b2 + n − k)
i=k+1

6
Pk Pn
yi −kθ yi kλ
p(k|Y1 , .., Yn ) ∝ θ i=1 e λ i=k+1 e

En son formülde içinde k olan terimleri tuttuk, gerisini attık. Formül e terimleri
birleştirilerek biraz daha basitleştirilebilir:

Pk Pn
yi yi (λ−θ)k
p(k|Y1 , .., Yn ) ∝ θ i=1 λ i=k+1 e

Bir basitleştirme daha şöyle olabilir

X
k
K= yi
i=1

Pn Pn P
yi yi − ki=1 yi
λ i=k+1 =λ i=1

Üstel işlemlerde eksi işareti, üstel değişken ayrılınca bölüm işlemine dönüşür:
Pn
yi
λ i=1
= Pk
λ i=1 yi

Pn
yi
λ i=1
=
λK
Pn
yi

i=1
p(k|Y1 , .., Yn ) ∝ θ e(λ−θ)k
λK
 K P
θ n
= λ i=1 yi e(λ−θ)k
λ
Pn
yi
λ i=1 terimi k’ye değil n’ye bağlı olduğu için o da final formülden atılabilir

 K
θ
p(k|Y1 , .., Yn ) ∝ e(λ−θ)k
λ

p(k) için ortaya çıkan bu formüle bakarsak, elimizde verilen her k değeri için
bir olasılık döndürecek bir formül var. Daha önceki Gamma örneğinde formüle
bakarak elimizde hemen bir Gamma dağılımı olduğunu söyleyebilmiştik. Bu
kodlama sırasında işimize yarayacak bir şeydi, hesaplama için bir dağılıma ”zar
attırmamız” gerekiyor, ve Gamma örneğinde hemen Python Numpy kütüphanesindeki
random.gamma çağrısına Gamma’dan gelen rasgele sayılar ürettirebiliriz. Üstteki
formüle bakarsak, hangi dağılıma zar attıracağız?
Cevap şöyle: p(k|..) pdf fonsiyonundaki k değişkeni 1, .., 119 arasındaki tam sayı
değerleri alabilir, o zaman ortada bir ayrıksal (discrete) dağılım var demektir. Ve

7
her k noktası için olabilecek olasılık değerini üstteki p(k|..) formülüne hesaplattırabiliyorsak,
ayrıksal bir dağılımı her nokta için üstteki çağrı, ve bu sonuçları normalize ed-
erek (vektörün her elemanını vektörün toplamına bölerek) bir dağılım şekline
dönüştürebiliriz. Daha sonra bu ”vektörsel dağılım” üzerinden zar attırırız. Python
kodundaki w_choice ya da R dilindeki sample çağrısı bu işi yapar.

import math
import random

np.random.seed(0); random.seed(0)

# samples indexes from a sequence of probability table


# based on those probabilities
def w_choice(lst):
n = random.uniform(0, 1)
for item, weight in enumerate(lst):
if n < weight:
break
n = n - weight
return item

#
# hyperparameters: a1, a2, b1, b2
#
def coal(n,x,init,a1,a2,b1,b2):
nn=len(x)
theta=init[0]
lam=init[1]
k = init[2]
z=np.zeros((nn,))
for i in range(n):
ca = a1 + sum(x[0:k])
theta = np.random.gamma(ca, 1/float(k + b1), 1)
ca = a2 + sum(x[(k+1):nn])
lam = np.random.gamma(ca, 1/float(nn-k + b2), 1)
for j in range(nn):
z[j]=math.exp((lam-theta)*(j+1)) * (theta/lam)**sum(x[0:j])
# sample
zz = z / sum(z)
k = w_choice(zz)
print float(theta), float(lam), float(k)

data = np.loadtxt("coal.txt")
coal(1100, data, init=[1,1,30], a1=1,a2=1,b1=1,b2=1)

3.32561369453 0.931821137936 42.0

Kodları işletince elimize k = 42 değeri geçecek, yani değişim anı 1851+42 = 1893
senesidir. Kaynaklar:
[1] Ioana A. Cosma, Ludger Evers, Markov Chain Monte Carlo Methods (Lecture)
[2] Koop, Bayesian Econometric Methods
[3] Anderson, A. (1911). Labour legislation. In H. Chisholm (Ed.), Encyclopedia

8
britannica (11th ed., Vol. 16, sf. 7-28)
[4] Zuccini, Hidden Markov Models for Time Series An Introduction Using R
[5] Bayramli, Istatistik, Çok Değişkenli Bernoulli Karışımı
[6] Bayesian estimation of changepoints, https://ruivieira.dev/bayesian-
estimation-of-changepoints.html
[7] Coal-Mine Accidents: Their Causes and Prevention, https://pubs.usgs.gov/
bul/0333/report.pdf

9
Çok Değişkenli Bernoulli Karışımı (Mixture of Multivariate Bernoulli)
Eğer verimizi, her biri verinin değişik bir bölümünü, yönünü temsil eden bir
“dağılım grubu” yani karışım ile modellemek istiyorsak, karışım modellemesi
kullanılabilir. Mesela boy ve ağırlık verisinde bayanlar ve erkekler ayrı dağılımlara
sahip olabilir, bu durumu modele dahil etmek modelin tahmin gücünü arttırır.
Karışım modellerinin güzel bir tarafı kümeleme teknikleri ile başta “bilinmeyen”
kümelerinin neye benzediğini bulmaları, ayrıca her veri noktasının bu kümelere
olasılıksal olarak aidiyetini, “yakınlığını” hesaplamamızı mümkün kılmaları.
Formel olarak bir karışım dağılımı f her biri ayrı bir dağılım olan f1 , f2 , ..., fK ile K
öğeden oluşan, bir yeni dağılımdır diyoruz, eğer

X
K
f(x) = λk fk (x)
k=1

P
ise, ve λk karışım oranları, λk > 0, k λk = 1 olacak şekilde.
Üstteki model üzerinden zar atılabilecek bir model aynı zamanda (tüm olasılıksal
dağılımlar simule edilebilir tabii, ama üstteki için simulasyon oldukça direk), λ
içindeki olasılıklara göre zar atıp bir karışım öğesi seçilir, daha sonra bu öğenin
dağılımına gidilip ona zar attırılır. Bunun olabileceğini ispatlamak için, Z rasgele
değişkeninin λk ile dağıldığını (ayrıksal dağılım) düşünelim, yani

Z ∼ Mult(λ1 , .., λk )

fk (x) bir diğer açıdan f(x|Z = k)’dir, notasyonel olarak böyle. O zaman,

X
K
= f(x|Z = k)λk
k=1

X
K
= f(x|Z = k)P(Z = k)
k=1

X
K
= f(x, k)
k=1

= f(x)

Yani λ olasılıklarına göre fk seçmek üstteki ifadedeki koşullu olasılık durumuna


karşılık geliyor, koşullu olasılık P(A|B) B’nin verildiği / bilindiği durumda A’nin
olasılığı hatırlayacağımız üzere.

1
Karışımın içindeki dağılımlar parametrik dağılımlar olduğu zaman onları nasıl
hesapsal olarak kestiririz? Bir dağılımın parametrelerini kestirebilmek için en iyi
yöntemlerden biri maksimum olurluk (maximum likelihood) yöntemi. Olurluk
eldeki verinin belli dağılım parametreleri üzerinden olasılığı, yani “verinin olasılığı”.
Örneklemlerin bağımsız olduğundan hareketle x1 , x2 , ..., xN verisi için olurluk,

Y
N
f(xi ; θ)
i=1

Her zaman olduğu gibi çarpımı toplam haline döndürmek için log alırız,

X
N
`(θ) = log f(xi ; θ)
i=1

Karışımları da dahil edersek,

X
N X
K
= log λk f(xi ; θk ) (2)
i=1 k=1

Şimdi log olurluğun mesela θj ’ye göre türevini almayı deneyelim, yani j’inci
öğenin parametresine göre bir kısmi türev.

∂` X N
1 ∂f(xi ; θj )
= PK λj
∂θj i=1 k=1 λk f(xi ; θk )
∂θj

Bölüm ve bölene f(xi ; θj ) ekleyelim, bu sonucu değiştirmez,

X
N
λj f(xi ; θj ) 1 ∂f(xi ; θj )
= PK
i=1 k=1 λk f(xi ; θk )
f(xi ; θj ) ∂θj

X
N
λj f(xi ; θj ) ∂ log f(xi ; θj )
= PK
i=1 k=1 λk f(xi ; θk )
∂θj

Eğer elimizdeki, karışım olmayan, basit bir parametrik model olsaydı, log olurluk
şuna benzeyecekti,

∂ log f(xi ; θj )
∂θj

Bu formül iki üstteki formülün en sağındaki çarpan sadece. Demek ki “karışım


olmak” log olurluğu bir tür belli ağırlıklara göre ortalanan (weighted) normal

2
olurluk haline getirdi. Karışımın log olurluğunu maksimize etmek istiyorsak, bu
ağırlığı alınmış olurluğu maksimize etmemiz gerekli. Bu ağırlığın alındığı kısmı
iki üstteki formülden çekip çıkartırsak,

λj f(xi ; θj )
wij = PK
k=1 λk f(xi ; θk )

Bu ağırlık hesabı i, j için yapılacak. Bu noktaya niçin geldik hatırlayalım, olurluk


üzerinden parametreleri hesaplamak istiyoruz. Fakat üstteki formülde wij hesabı
için θj ’in bilinmesi gerekiyor!
Ne yapacağız? Şu wij ’ye yakından bakalım. Daha önce belirttiğimiz gibi λj
Z’nin j olma olasılığı, o zaman bölünendeki ifade X = xi Z = j olmasının or-
tak (joint) dağılımıdır, yani P(Z = j, X = xi ) diyelim. Koşullu dağılım duru-
mundan başlayarak bu sonuca nasıl erişildiğini görmüştük. Bölendeki ifade ise
f(xi )’dir, bir kısmı dağılımdır - tüm k’ler üzerinden olasılığın bir bölümü topla-
narak kısmen çıkartılmış halidir (marginalized out) - o zaman tüm bölümden ele
geçen sonuç Z = j’nin X = xi verildiği, koşullu olasılığıdır,

λj f(xi ; θj )
wij = PK = P(Z = j|X = xi ; θ) (1)
k=1 λk f(xi ; θk )

O zaman

∂` X N
∂ log f(xi ; θj )
= wij
∂θj i=1
∂θj

wij ile, veriye göre, Z’nin sonsal (posterior) hesaplamış oluyoruz. Yani karışımsal
modeli hesaplarken bir ağırlıksal olurluk hesabı yapıyoruz, ki bu ağırlıklar son-
sal dağılımlardan gelen değerlere ihtiyaç duyuyor. Ama bu sonsal dağılımlar da
aslında hesaplamaya çalıştığımız parametrelere ihtiyaç duyuyor, yani bir kördüğüm!
Ama şöyle bir deyiş vardır; kimisine kördüğüm gibi gözüken, bir başkasına ardışıl
yaklaşıksal prosedür gibi gözükür (succcessive approximation procedure) [hoca
şakadan uydurdu bu deyişi, ama teknik doğru]. Demek istiyorum ki eğer kördüğümde
takılı kaldıysak, bir taraf için tahmin yapıp diğer tarafı hesaplarız, sonra bu hesa-
planan değerleri kullanarak ilk tarafı hesaplarız. Bunu sürekli devam ettiririz.
Ünlü Beklenti-Maksimizasyon (Expectation-Maximization -EM-) prosedürü tam
da bunu yapıyor. Detaylar için [3, sf. 450]. EM özyinesel çalışan bir rutindir,
birkaç adımda sonuca erişir, ve her adımda olurluğu iyileştirmesi ve yerel mak-
simuma erişmesi garantidir; Tabii başlangıç noktasına göre bu yerel maksimum
tamamın (global) maksimumu olmayabilir, o zaman EM yerel maksimumda takılıp
kalmış olur (stuck at local maxima), bu sebeple EM’i birkaç değişik rasgele başlangıç
noktasından başlatıp en iyi yerel maksimimumu, yani en iyi olurluğu veren parame-
treleri bulmak iyi bir yaklaşımdır.

3
wij ’ye Değişik bir Yönden Erişmek
θj hesabı için formülasyonu biraz değiştirmek lazım. Tüm ortak dağılımı yazalım,
ayrıca zik değişkenini katalım, Z değişkeni multinom idi, onu 0/1 değerleri içeren
vektörel olarak tasarlayalım, yani z veri noktası i ve bileşen k için, Zi ise i’inci
nokta için

Y
K
zik
P(Xi = xi , Zi = k) = f(xi ; θk )P(Zi = k)
k=1

Şimdi log alalım,

X
K

= zij ln f(xi ; θk )P(Zi = k)
k=1

Tüm veri noktaları için

X
N X
K

`(θ) = zij ln f(xi ; θk )P(Zi = k)
i=1 k=1

X
N X
K

= zik ln f(xi ; θj ) + ln(λj )
i=1 k=1

Şimdi bu ifadenin beklentisini almamız lazım; bunun sebebi EM’in yakınsaması


(convergence) ile alakalı [3, sf. 450]. Beklentiyi “eksik” olan yani bilinmeyen
küme ataması üzerinden alıyoruz, θk ,P(Zi = k) ve xi sabit olarak kalıyor,

X
N X
K

E[l(θ)] = E[zik ] ln f(xi ; θj ) + ln(λj )
i=1 k=1

4
Hesaplanacak tek şey burada E[zik ]. Peki bu beklenti nedir?

E[zik ] = 1 · P(zik = 1|xi ) + 0 · P(zik = 1|xi )

= P(zik = 1|xi )

Bu formül (1)’deki formülün aynısıdır! Yeni notasyon üzerinden tabii; o zaman

E[zik ] = wik

Yani

X
N X
K

E[l(θ)] = wik ln f(xi ; θj ) + ln(λj ) (4)
i=1 k=1

EM Hesap Adımları
wij hesabına EM’in “beklenti adımı (expectation step)” ismi veriliyor, çünkü görüldüğü
gibi beklenti alıyoruz. Bu adım için θ’nin bilindiği farz edilir, bilinmiyorsa, ki
hesap döngüsünün ilk adımında durum böyledir, o zaman rasgele θ kullanılır.
Döngünün diğer adımlarında döngünün bir önceki adımındaki değerler kullanılır.
Maksimizasyon adımı için bilinen wij için θ’nin hesaplanması gerekir; bu adıma
maksimizasyon adı verilmesi de mantıklı, çünkü altta da görüleceği üzere, kısmi
türevler alıp sıfıra eşitleyerek maksimal değerler hesaplayacağız.
Bu hesap şöyle: Eğer (4) çok değişkenli Bernoulli modeli içinse, ki xid i’inci veri
noktasının D boyutlu Bernoulli için d’inci hücresinin değeri, θjd ise j’inci karışım
öğesinin D boyut içinden d’inci olasılık değeri olsun, f içinde yerine koyunca ve
f üzerinde log etki yapınca çarpım yine toplam olur,

X
N X
K  X
D 
θxkd 1−xid

= wik ln(λk ) + ln id
(1 − θkd )
i=1 k=1 d=1

X
N X
K  X
D 
E[l(θ)] = wik ln(λk ) + xid ln θkd + (1 − xid ) ln(1 − θkd )
i=1 k=1 d=1

Şimdi θkd hesabı için ona göre türevi alıp sıfıra eşitleriz,

∂ X N
∂ ∂  
E[l(θ)] = wik xid (ln θkd ) + (1 − xid ) ln(1 − θkd ) = 0
∂θkd i=1
∂θkd ∂θkd

5
X
N
xid 1 − xid
wik ( − )=0
i=1
θkd 1 − θkd

X
N
wik xid X
N
wik − wik xid
=
i=1
θkd i=1
1 − θkd

1 X X
N N
1
wik xid = wik − wik xid
θkd i=1 1 − θkd i=1

1 − θkd X X
N N
wik xid = wik − wik xid
θkd i=1 i=1

P P
1 − θkd wik − i wik xid
= i P
θkd i wik xid

P
1 wik
−1= P i −1
θkd i wik xid

P
i wik xid
θ̂kd = P
i wik

Ya da
P
wik xi
θ̂k = Pi
i wik

λj Hesabı
Şimdi λj ’ye
Pgöre bir türev almamız, sıfıra eşitlememiz ve çözmemiz lazım. Tek
bir pürüz k λk = 1 olması şartı, yani tüm ağırlıkların toplamı 1’e eşit olmalı ve
bu şartı bir şekilde denklemlere dahil etmemiz lazım. Lagrange çarpan tekniği
burada kullanılır [1, sf. 395].

∂  X 
`(θ) + α( λk − 1)
∂λj k

Ondan önce olurluğun λj ’ye göre kısmi türevi lazım, (1) formülüne dönersek, ve
kısmi türevi alırsak,

∂` X N
f(xi ; θj ) X f(xi ; θj )
N
= PK =
∂λj i=1 k=1 λk f(xi ; θk ) i=1
f(xi )

6
O zaman iki üstteki türev su hale gelir, sıfıra da eşitlersek,

X
N
f(xi ; θj )
+α=0
i=1
f(xi )

Biraz düzenleyip iki tarafı da λj ile çarpalım,

X
N
f(xi ; θj )λj
= −αλj
i=1
f(xi )

Eşitliğin sol tarafında toplam içinde yine (1)’de görülen wij ’ye eriştik! Yerine
koyalım,

X
N
wij = −αλj (3)
i=1

P
Şimdi tüm öğeler / kümeler üzerinden bir toplam alalım (yani k ’yi her iki
tarafa da uygulayalım),

X
K X
N X
K
wij = −α λj
k=1 i=1 k=1

P P
k λj = 1, j wij = 1 olduğu için,

N = −α

Üstteki formülü (3) içine koyarsak, ve tekrar düzenlersek,

PN
i=1 wij
λj =
N

import numpy as np

def loginnerprodexp(t,a):
eps=1e-15
t[t>0.] = 1
tmp = np.dot(t,np.exp(a)) + eps
b=np.log(tmp)
return b

def logsumexp(a):
return np.log(np.sum(np.exp(a), axis=0))

def do_EMmixtureBernoulli(Y,K,iter,tol):

7
N,D=Y.shape
OMY=1+(-1*Y) # "One minus Y", (1-Y)
tmp=np.random.rand(N,K)
tmp2=np.sum(tmp,axis=1).reshape((N,1))
tmp3=np.tile(tmp2,(1,K))
lR=np.log(np.divide(tmp, tmp3))
L = []
for i in range(iter):
# lPi log Mixture params Kx1
lPi=np.tile(-1 * np.log(N),(K,1))+logsumexp(lR).T.reshape((K,1))
const=np.tile(logsumexp(lR).T.reshape((K,1)),(1,D))
# lP log Bernoulli params KxD
lP=loginnerprodexp(Y.T,lR).T - const
# lOMP log(1-P), also KxD
lOMP=loginnerprodexp(OMY.T,lR).T-const

# *** E-step
lR=np.tile(lPi.T,(N,1))+np.dot(Y,lP.T) + np.dot(OMY,lOMP.T) # + const
Z=logsumexp(lR.T)

lR=lR-np.tile(Z.T.reshape((N,1)),(1,K))
L.append(np.sum(Z))
if (i>1):
if np.abs(L[i]-L[i-1]) < tol: break

iters = i
return lR,lPi,lP,L,iters

def EMmixtureBernoulli(Y,K,iter,tol,attempts):
Lbest = -np.inf
eps=1e-15
# EM'i farkli noktalardan birkac kere (attempts kadar) baslat
# En iyi sonucun sonuclarini elde tut
for attempt in range(attempts):
lRtmp,lPitmp,lPtmp,L,iters = do_EMmixtureBernoulli(Y,K,iter,eps)
if L[iters]>Lbest:
lR=lRtmp
lPi=lPitmp
lP=lPtmp
Lbest=L[iters]
itersbest=iters
aic = -2*Lbest + 2*lP.shape[0]*lP.shape[1]
return lR, lPi, lP, Lbest, aic

Kodda kullanılan log-toplam-exp numarası için Ekler’e bakılabilir.


Örnek olarak ikisel olarak siyah/beyaz olarak kodlanmış üç tane farklı sayının
8x8 boyutundaki imajlarını içeren veriyi kullanabiliriz. Küme sayısını 3 olarak
verdik.
Veriden bazı örnekler görelim,

Y = np.loadtxt('binarydigits.txt')
plt.imshow(Y[4,:].reshape((8,8),order='C'), cmap=plt.cm.gray)

8
plt.savefig('mixbern_04.png')
plt.imshow(Y[7,:].reshape((8,8),order='C'), cmap=plt.cm.gray)
plt.savefig('mixbern_05.png')

import numpy as np
import mixbern

K=3; iter=40; eps=1e-15; attempts=5


lR,lPi,lP,lbest,aic = mixbern.EMmixtureBernoulli(Y,K,iter,eps,attempts)
labels = np.argmax(lR.T,axis=0)
print labels
print 'log olurluk', lbest, 'aic', aic

[0 0 0 2 2 1 2 0 2 2 1 1 2 1 0 0 0 1 0 1 1 0 0 1 0 2 0 2 1 1 1 2 0 0 0 0 0
0 1 2 0 0 0 0 0 1 2 0 0 2 2 2 1 2 1 2 2 0 0 1 2 1 2 1 0 1 0 0 2 2 2 1 0 2
2 2 0 1 1 2 2 0 1 0 2 0 0 2 2 0 0 2 0 2 1 2 0 1 0 2]
log olurluk -3049.95050527 aic 6483.90101054

Elde edilen sonuçlara göre, ve paylaştığımız say resimlerindeki sıraya bakarsak,


mesela ilk üç sayı imajını birbirine benziyor olması lazım. Yine aynı sırada gider-
sek Daha sonra 4. ve 6. sayıların birbirine benziyor olması lazım, ve 8. imajın
ilk üç imaja benziyor olması lazım, vs. Resimlere bakınca bunun hakikaten böyle
olduğunu görüyoruz. Demek ki kümeleme başarıyla gerçekleştirilmiş.
Her veri noktasının üyeliğini için wij ’ye baktık (kodda lR, üyeliğin log’u), i hangi
kümeye en fazla yakın ise (yüksek olasılık) bunu bir aidiyet olarak kabul ettik.
Daha ilginç bir hesap şu; her θk (kodda lP, log’u alınmış parametreler) artık bir
kümeyi “temsil” ediyor (multinom bir değişken bu hatırlarsak) ve bu dağılımların
her biri, bir nevi “şablon” haline dönüşmüş olmalı; öyle ya, Z ile zar atıyoruz
bir dağılım seçiyoruz, sonra o dağılıma bir daha zar attırıyoruz, ve herhangi
bir sayının imajını üretmek istiyorsak şablon gerçeğine oldukça yakın olmalı!
Yani mantıki olarak düşünürsek, eğer model veriye iyi uymuş ise, her şablon
dağılımının 0,7,5 sayılarının şeklini aşağı yukarı temsil etmesini bekleriz. Kon-
trol edelim,

dim = (8,8)
templates = np.exp(lP)
digit0 = np.reshape(templates[0,:], dim,order='C')
plt.imshow(digit0, cmap=plt.cm.gray)
plt.savefig('mixbern_01.png')
digit1 = np.reshape(templates[1,:], dim,order='C')

9
plt.imshow(digit1, cmap=plt.cm.gray)
plt.savefig('mixbern_02.png')
digit2 = np.reshape(templates[2,:], dim, order='C')
plt.imshow(digit2, cmap=plt.cm.gray)
plt.savefig('mixbern_03.png')

Hakikaten de şeklen benziyorlar!


Kaynaklar
[1] Zaki, Data Mining and Analysis: Fundamental Concepts and Algorithms
[2] Alfons Juan, Enrique Vidal, Bernoulli mixture models for binary images
[3] Shalizi, Advanced Data Analysis from an Elementary Point of View
[4] Bishop, C., Pattern Recognition and Machine Learning

10
Gaussian Karışım Modeli (GMM) ile Kümelemek
Gaussian (normal) dağılımı tek tepesi olan (unimodal) bir dağılımdır. Bu de-
mektir ki eğer birden fazla tepe noktası olan bir veriyi modellemek istiyorsak,
değişik yaklaşımlar kullanmamız gerekir. Birden fazla Gaussian’ı ”karıştırmak
(mixing)” bu tür bir yaklaşım. Karıştırmak, karışım içindeki her Gaussian’dan ge-
len sonuçları toplamaktır, yani kelimenin tam anlamıyla her veri noktasını teker
teker karışımdaki tüm dağılımlara geçip sonuçları ve bir ağırlık üzerinden topla-
maktır. Çok boyutlu Gaussian’lar için mesela,

X
f(x) = πk N(x|µk , Σk )
z

πk karıştırma oranlarıdır (mixing proportions). Bernoulli karışımlarını anlatan


yazıya kıyasla, oradaki θ’yi 0/1 hücreleri için olasılıklar olarak aldık, şimdi θ
içinde µk , Σk var, yani θ = (µk , Σk ).
İki Gaussian olsa π1 , π2 oranları 0.2, 0.8 olabilir ve her nokta her Gaussian’a ver-
ildikten sonra tekabül eden ağırlıkla mesela sırayla 0.2, 0.8 ile çarpılıp toplanır.
Maksimizasyon adımı için gereken hesapların türetilmesi [5, sf. 392]’de bulun-
abilir.
Örnek olarak alttaki veriye bakalım.

data = np.loadtxt('biometric_data_simple.txt',delimiter=',')

women = data[data[:,0] == 1]
men = data[data[:,0] == 2]

plt.xlim(55,80)
plt.ylim(80,280)
plt.plot (women[:,1],women[:,2], 'b.')
plt.hold(True)
plt.plot (men[:,1],men[:,2], 'r.')
plt.xlabel('boy (inch)')
plt.ylabel('agirlik (pound)')
plt.savefig('mixnorm_1.png')

1
Bu grafik kadınlar ve erkeklerin boy (height) ve kilolarını (weight) içeren bir veri
setinden geliyor, veri setinde erkekler ve kadınlara ait olan ölçümler önceden
işaretlenmiş / etiketlenmiş (labeled), biz de bu işaretleri kullanarak kadınları
kırmızı erkekleri mavi ile grafikledik. Ama bu işaretler / etiketler verilmiş olsun
ya da olmasın, kavramsal olarak düşünürsek eğer bu veriye bir dağılım uydur-
mak (fit) istersek bir karışım kullanılması gerekli, çünkü iki tepe noktasiyle daha
rahat temsil edileceğini düşündüğümüz bir durum var ortada.

# Multivariate gaussian, contours


#
import scipy.stats
import em

data = np.loadtxt('biometric_data_simple.txt',delimiter=',')

women = data[data[:,0] == 1]
men = data[data[:,0] == 2]

plt.xlim(55,80)
plt.ylim(80,280)
plt.plot (women[:,1],women[:,2], 'b.')
plt.hold(True)
plt.plot (men[:,1],men[:,2], 'r.')
plt.xlabel('boy (inch)')
plt.ylabel('agirlik (pound)')
plt.hold(True)

x = np.arange(55., 80., 1)
y = np.arange(80., 280., 1)
X, Y = np.meshgrid(x, y)

Z = np.zeros(X.shape)
nx, ny = X.shape
mu1 = np.array([ 72.89350086, 193.21741426])
sigma1 = np.matrix([[ 7.84711283, 25.03111826],
[ 25.03111826, 1339.70289046]])
for i in xrange(nx):
for j in xrange(ny):
Z[i,j] = em.norm_pdf(np.array([X[i,j], Y[i,j]]),mu1,sigma1)

2
levels = np.linspace(Z.min(), Z.max(), 4)

plt.contour(X, Y, Z, colors='b', levels=levels)


plt.hold(True)

Z = np.zeros(X.shape)
nx, ny = X.shape
mu2 = np.array([ 66.15903841, 135.308125 ])
sigma2 = np.matrix([[ 14.28189396, 51.48931033],
[ 51.48931033, 403.09566456]])
for i in xrange(nx):
for j in xrange(ny):
Z[i,j] = em.norm_pdf(np.array([X[i,j], Y[i,j]]),mu2,sigma2)

levels = np.linspace(Z.min(), Z.max(), 4)

plt.contour(X, Y, Z, colors='r', levels=levels)


plt.savefig('mixnorm_2.png')

Bu karışım içindeki Gaussian’ları üstteki gibi çizebilirdik (gerçi üstteki aslında


ileride yapacağımız net bir hesaptan bir geliyor, ona birazdan geliyoruz, ama
çıplak gözle de bu şekil uydurulabilirdi). Modeli kontrol edelim, elimizde bir
karışım var, nihai olasılık değeri p(x)’i nasıl kullanırız? Belli bir noktanın olasılığını
hesaplamak için bu noktayı her iki Gaussian’a teker teker geçeriz (örnekte iki
tane), ve gelen olasılık sonuçlarını karışım oranları ile çarparak toplarız. Ağırlıklar
sayesinde karışım entegre edilince hala 1 değeri çıkıyor zaten bir dağılımın uy-
ması gereken şartlardan biri bu. Ayrıca bir dağılımın diğerinden daha önemli
olduğu ağırlıklar üzerinden modele verilmiş oluyor.
Etiketler Bilinmiyorsa
Eğer etiketler bize önceden verilmemiş olsaydı, hangi veri noktalarının kadınlara,
hangilerinin erkeklere ait olduğunu bilmeseydik o zaman ne yapardık? Bu veriyi
grafiklerken etiketleri renkleyemezdik tabii ki, şöyle bir resim çizebilirdik ancak,

import scipy.stats
data = np.loadtxt('biometric_data_simple.txt',delimiter=',')

3
women = data[data[:,0] == 1]
men = data[data[:,0] == 2]

plt.xlim(55,80)
plt.ylim(80,280)
plt.plot (data[:,1],data[:,2], 'k.')
plt.xlabel('boy (inch)')
plt.ylabel('agirlik (pound)')
plt.savefig('mixnorm_3.png')

Fakat yine de şekil olarak iki kümeyi görebiliyoruz. Acaba öyle bir yapay öğrenim
algoritması olsa da, biz bir karışım olduğunu tahmin edip, sonra o karışımı veriye
uydururken, etiket değerlerini de kendiliğinden tahmin etse?
Alttaki kod Beklenti-Maksimizasyon üzerinden kümeleme yapar. Konunun teorik
kısmı altta ve [6] yazısında bulunabilir.
Türetmek
Karışımda birden fazla çok boyutlu Gaussian olacak, bu Gaussian’lardan i’inci
Gaussian


1 (x − µ)T Σ−1
i (x − µi )
fi (x) = f(x; µi , Σi ) = exp − (1)
(2π)d/2 |Σi |1/2 2

olur, x çok boyutlu veri noktasıdır, ve kümeleme başlamadan önce µi , Σi bilin-


mez, küme sayısı k bilinir. O zaman karışım modeli

X
k X
k
f(x) = fi (x)P(Ci ) = f(x; µi , Σi )P(Ci )
i=1 i=1

P
P(Ci )’a karışım oranları deniyor, ki i P(Ci ) = 1. Bazı metinlerde bu πi olarak
ta gösterilebiliyor. Tüm veri için maksimum olurluk

4
X
n X
n X
k 
L= ln f(xj ) = ln f(xj ; µi , Σi )P(Ci )
j=1 j=1 i=1

Şimdi herhangi bir parametre θi için (yani µi ya da Σi ),

X
n 
∂L ∂
= ln f(xj )
∂θi ∂θi j=1

X
n
1 ∂f(xj ) 
= ·
j=1
f(xj ) ∂θi

Xn 
1 X ∂
k


f(xj ; σa , Σa )P(Ca )
j=1
f(xj)
a=1
∂θi

Xn 
1 ∂ 

· f(xj ; σi , Σi )P(Ci )
j=1
f(x j ) ∂θi

En son adım mümkün çünkü θi parametresi i’inci kümeye (Gaussian’a) ait, ve


diğer kümelerin bakış açısına göre (onlara göre kısmi türev alınınca) bu parame-
tre sabit sayılıyor.
Şimdi |Σi | = 1
|Σ−1 |
eşitliğinden hareketle (1)’deki çok boyutlu Gaussian’ı şöyle
yazabiliriz,

f(xj ; σi , Σi ) = (2π)−d/2 |Σ−1 |1/2 exp g(µi , Σi )


 

ki

1
g(µi , Σi ) = − (xj − µi )T Σ−1
i (xj − µi )
2

Yani log-olurluk fonksiyonunun türevi şu şekilde yazılabilir,

∂L X n 
1 ∂

|Σi | exp g(µi , Σi ) P(Ci )
−d/2 −1 1/2
  
= (2π) (3)
∂θi j=1
f(xj ) ∂θi

µi için maksimum-olurluk kestirme hesabı yapmak için log olurluğun θi = µi ’a


göre türevini almamız
 gerekiyor.
 Üstteki formülde gördüğümüz gibi µi ’a bağlı
olan tek terim exp g(µi , Σi ) . Şimdi

∂     ∂
exp g(µi , Σi ) = exp g(µi , Σi ) · g(µi , Σi ) (2)
∂θi ∂θi

5
ve

g(µi , Σi ) = Σ−1
i (xj − µi )
∂µi

formüllerini kullanarak log olurluğun µi ’ya göre türevi

∂L X n 
1

(2π)−d/2 |Σ−1 |1/2
P(Ci )Σ−1 (xj − µi )
 
= i exp g(µ i , Σ i )
∂µi j=1
f(xj )

X
n 
f(xj ; µi , Σi )P(Ci )

= · Σ−1
i (xj − µi )
j=1
f(xj )

X
n
= wij Σ−1
i (xj − µi )
j=1

Üstteki forma erişmek için (2) ve alttaki formülü kullandık.

P(xj |Ci )P(Ci )


P(Ci |xj ) = Pk
a=1 P(xj |Ca )P(Ca )

ki bunun anlamı

f(xj ; µi , Σi )P(Ci )
wij = P(Ci |xj ) =
f(xj )

Üstteki kısmi türevi sıfıra eşitleyip çözer ve her iki tarafı Σi ile çarparsak,

X
n
wij (xj − µi ) = 0
j=1

elde ederiz, bu demektir ki

X
n X
wij xj = µi wij
j=1 j=1

o zaman

Pn
j=1 wij xj
µi = Pn
j=1 wij

Kovaryans Matrisi Σi ’i Hesaplamak

6
Σi hesabı için (3) kısmi türevinin |Σ−1
i |
1/2
exp(g(µi , Σi )) üzerindeki çarpım kuralı
−1
(product rule) kullanılarak Σi ’ye göre alınması gerekiyor.

Her kare matris A için ∂|A|


∂A
= |A| · (A−1 )T olduğundan hareketle, |Σ−1
i |
1/2
’nin
Σ−1
i ’ya göre türevi

i |
∂|Σ−1 1/2
1 1 −1 1/2
−1
= · |Σ−1
i |
−1/2
· |Σ−1
i | · Σi = |Σi | · Σi
∂Σi 2 2

Şimdi A ∈ Rd×d ve vektörler a, b ∈ Rd için ∂A
aT Ab = abT olmasından hareketle
(3)’teki exp[g(µi , Σi )]’in Σ−1
i gore türevi,

∂ 1
exp g(µi , Σi ) = − exp g(µi , Σi )(xj − µi )(xj − µi )T
   
∂Σ −1 2

Üstteki ve iki üstteki formül üzerinde türev çarpım kuralını kullanırsak,


i |
|Σ−1 1/2
 
−1
exp g(µi , Σi ) =
∂Σi

1  1 −1 1/2
= |Σ−1 |1/2
|Σ | (xj − µi )(xj − µi )T
  
Σ i exp g(µ i , Σ i ) − exp g(µ i , Σ i )
2 i 2 i

1
· |Σ−1
i |
1/2
· exp g(µi , Σi ) Σi − (xj − µi )(xj − µi )T
  
=
2

Üstteki son formülü (3)’e sokarsak, Σ−1


i ’e göre log olurluğun türevi

1 X (2π)−d/2 |Σ−1
n
i |
1/2

∂L exp g(µi , Σi )P(Ci ) T

= Σ i − (xj − µ i )(xj − µ i )
∂Σ−1
i
2 j=1 f(xj )

1 X f(xj ; µi , Σi )P(Ci )
n
· Σi − (xj − µi )(xj − µi )T

=
2 j=1 f(xj )

1X
n
wij Σi − (xj − µi )(xj − µi )T

=
2 j=1

Türevi sıfıra eşitlersek,

X
n
wij Σi − (xj − µi )(xj − µi )T = 0

j=1

7
olur, ve devam edersek alttaki sonucu elde ederiz,

Pn
wij (xj − µi )(xj − µi )T
Σi =
j=1
Pn
j=1 wij

Karışım Ağırlıkları P(Ci )’i Hesaplamak


P
Bu hesabı yapmak için (3) türevinin P(Ci )’a göre alınması lazım fakat ka=1 P(Ca ) =
1 şartını zorlamak için Lagrange çarpanları tekniğini kullanmamız gerekiyor. Yani
türevin alttaki gibi alınması lazım,


 X
k


ln L + α P(Ca ) − 1
∂P(Ci ) a=1

Log olurluğun P(Ci )’a göre kısmi türevi alınınca,

∂L X f(xj ; µi , Σi )
n
=
∂P(Ci ) j=1
f(xj )

O zaman iki üstteki türevin tamamı şu hale gelir,

X
n 
f(xj ; µi , Σi )

j=1
f(xj )

Türevi sıfıra eşitlersek ve her iki tarafı P(Ci ) ile çarparsak,

X
n
f(xj ; µi , Σi )P(Ci )
= −αP(Ci )
j=1
f(xj )

X
n
wij = −αP(Ci ) (4)
j=1

Üstteki toplamı tüm kümeler üzerinden alırsak

X
k X
n X
k
wij = −α P(Ci )
i=1 j=1 i=1

ya da n = −α.
P
Son adım ki=1 wij = 1 sayesinde mümkün oldu. n = −α’yi (4) içine sokunca
P(Ci )’in maksimum olurluk hesabını elde ediyoruz,

8
Pn
j=1 wij
P(Ci ) =
n
from scipy.stats import multivariate_normal as mvn
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import numpy.linalg as linalg
import math, random, copy, sys
import scipy.stats

class Cov_problem(Exception): pass

def norm_pdf(b,mean,cov):
k = b.shape[0]
part1 = np.exp(-0.5*k*np.log(2*np.pi))
part2 = np.power(np.linalg.det(cov),-0.5)
dev = b-mean
part3 = np.exp(-0.5*np.dot(np.dot(dev.transpose(),np.linalg.inv(cov)),dev))
dmvnorm = part1*part2*part3
return dmvnorm

def gm_log_likelihood(X, center_list, cov_list, p_k):


"""Finds the likelihood for a set of samples belongin to a Gaussian mixture
model.

Return log likelighood


"""
samples = X.shape[0]
K = len(center_list)
log_p_Xn = np.zeros(samples)
for k in range(K):
p = logmulnormpdf(X, center_list[k], cov_list[k]) + np.log(p_k[k])
if k == 0:
log_p_Xn = p
else:
pmax = np.max(np.concatenate((np.c_[log_p_Xn], np.c_[p]), axis=1), axis=1)
log_p_Xn = pmax + np.log( np.exp( log_p_Xn - pmax) + np.exp( p-pmax))
logL = np.sum(log_p_Xn)
return logL

def gm_assign_to_cluster(X, center_list, cov_list, p_k):


samples = X.shape[0]
K = len(center_list)
log_p_Xn_mat = np.zeros((samples, K))
for k in range(K):
log_p_Xn_mat[:,k] = logmulnormpdf(X, center_list[k], cov_list[k]) + np.log(p_k
pmax = np.max(log_p_Xn_mat, axis=1)
log_p_Xn = pmax + np.log( np.sum( np.exp(log_p_Xn_mat.T - pmax), axis=0).T)
logL = np.sum(log_p_Xn)

log_p_nk = np.zeros((samples, K))


for k in range(K):
log_p_nk[:,k] = log_p_Xn_mat[:,k] - log_p_Xn

9
maxP_k = np.c_[np.max(log_p_nk, axis=1)] == log_p_nk
maxP_k = maxP_k * (np.array(range(K))+1)
return np.sum(maxP_k, axis=1) - 1

def logmulnormpdf(X, MU, SIGMA):


if MU.ndim != 1:
raise ValueError, "MU must be a 1 dimensional array"
mu = MU
x = X.T
if x.ndim == 1:
x = np.atleast_2d(x).T
sigma = np.atleast_2d(SIGMA) # So we also can use it for 1-d distributions
N = len(MU)
ex1 = np.dot(linalg.inv(sigma), (x.T-mu).T)
ex = -0.5 * (x.T-mu).T * ex1
if ex.ndim == 2: ex = np.sum(ex, axis = 0)
K = -(N/2)*np.log(2*np.pi) - 0.5*np.log(np.linalg.det(SIGMA))
return ex + K

def gmm_init(X, K, verbose = False,


cluster_init = 'sample', \
cluster_init_prop = {}, \
max_init_iter = 5, \
cov_init = 'var'):
samples, dim = np.shape(X)
if cluster_init == 'sample':
if verbose: print "Using sample GMM initalization."
center_list = []
for i in range(K):
center_list.append(X[np.random.randint(samples), :])
elif cluster_init == 'box':
if verbose: print "Using box GMM initalization."
center_list = []
X_max = np.max(X, axis=0)
X_min = np.min(X, axis=0)
for i in range(K):
init_point = ((X_max-X_min)*np.random.rand(1,dim)) + X_min
center_list.append(init_point.flatten())
elif cluster_init == 'kmeans':
if verbose: print "Using K-means GMM initalization."
# Normalize data (K-means is isotropic)
normalizerX = preproc.Normalizer(X)
nX = normalizerX.transform(X)
center_list = []
best_icv = np.inf
for i in range(max_init_iter):
m, kcc = kmeans.kmeans(nX, K, iter=100, **cluster_init_prop)
icv = kmeans.find_intra_cluster_variance(X, m, kcc)
if best_icv > icv:
membership = m
cc = kcc
best_icv = icv
cc = normalizerX.invtransform(cc)
for i in range(cc.shape[0]):
center_list.append(cc[i,:])

10
print cc
else:
raise "Unknown initialization of EM of MoG centers."

# Initialize co-variance matrices


cov_list = []
if cov_init=='iso':
for i in range(K):
cov_list.append(np.diag(np.ones(dim)/1e10))
#cov_list.append(np.diag(np.ones(dim)))
elif cov_init=='var':
for i in range(K):
cov_list.append(np.diag(np.var(X, axis=0)/1e10))
else:
raise ValueError('Unknown option used for cov_init')

p_k = np.ones(K) / K # Uniform prior on P(k)


return (center_list, cov_list, p_k)

def em_gm(X, K, max_iter = 50, verbose = False, \


iter_call = None,\
delta_stop = 1e-6,\
init_kw = {}, \
max_tries = 10,\
diag_add = 1e-3):

samples, dim = np.shape(X)


clusters_found = False
while clusters_found==False and max_tries>0:
max_tries -= 1
# Initialized clusters
center_list, cov_list, p_k = gmm_init(X, K, **init_kw)
# Now perform the EM-steps:
try:
center_list, cov_list, p_k, logL = \
gmm_em_continue(X, center_list, cov_list, p_k,
max_iter=max_iter, verbose=verbose,
iter_call=iter_call,
delta_stop=delta_stop,
diag_add=diag_add)
clusters_found = True
except Cov_problem:
if verbose:
print "Problems with the co-variance matrix, tries left ", max_tries

if clusters_found:
return center_list, cov_list, p_k, logL
else:
raise Cov_problem()

def gmm_em_continue(X, center_list, cov_list, p_k,


max_iter = 50, verbose = False, \
iter_call = None,\

11
delta_stop = 1e-6,\
diag_add = 1e-3,\
delta_stop_count_end=10):
"""
"""
delta_stop_count = 0
samples, dim = np.shape(X)
K = len(center_list) # We should do some input checking
if diag_add!=0:
feature_var = np.var(X, axis=0)
diag_add_vec = diag_add * feature_var
old_logL = np.NaN
logL = np.NaN
for i in xrange(max_iter):
try:
center_list, cov_list, p_k, logL = __em_gm_step(X, center_list,\
cov_list, p_k, K, diag_add_vec)
except np.linalg.linalg.LinAlgError: # Singular cov matrix
raise Cov_problem()
if iter_call is not None:
iter_call(center_list, cov_list, p_k, i)
# Check if we have problems with cluster sizes
for i2 in range(len(center_list)):
if np.any(np.isnan(cov_list[i2])):
print "problem"
raise Cov_problem()

if old_logL != np.NaN:
if verbose:
print "iteration=", i, " delta log likelihood=", \
old_logL - logL
if np.abs(logL - old_logL) < delta_stop: #* samples:
delta_stop_count += 1
if verbose: print "gmm_em_continue: delta_stop_count =", delta_stop_co
else:
delta_stop_count = 0
if delta_stop_count>=delta_stop_count_end:
break # Sufficient precision reached
old_logL = logL
try:
gm_log_likelihood(X, center_list, cov_list, p_k)
except np.linalg.linalg.LinAlgError: # Singular cov matrix
raise Cov_problem()
return center_list, cov_list, p_k, logL

def __em_gm_step(X, center_list, cov_list, p_k, K, diag_add_vec):


samples = X.shape[0]
# New way of calculating the log likelihood:
log_p_Xn_mat = np.zeros((samples, K))
for k in range(K):
log_p_Xn_mat[:,k] = logmulnormpdf(X, center_list[k], cov_list[k]) + np.log(p_k
pmax = np.max(log_p_Xn_mat, axis=1)
log_p_Xn = pmax + np.log( np.sum( np.exp(log_p_Xn_mat.T - pmax), axis=0).T) # Mayb
logL = np.sum(log_p_Xn)

12
log_p_nk = np.zeros((samples, K))
for k in range(K):
log_p_nk[:,k] = log_p_Xn_mat[:,k] - log_p_Xn

p_Xn = np.e**log_p_Xn
p_nk = np.e**log_p_nk

# M-step:
for k in range(K):
ck = np.sum(p_nk[:,k] * X.T, axis = 1) / np.sum(p_nk[:,k])
center_list[k] = ck
cov_list[k] = np.dot(p_nk[:,k] * ((X - ck).T), (X - ck)) / sum(p_nk[:,k])
p_k[k] = np.sum(p_nk[:,k]) / samples

return (center_list, cov_list, p_k, logL)

data = np.loadtxt('biometric_data_simple.txt',delimiter=',')
data = data[:,1:3]
import em
mc = [0.4, 0.4, 0.2]
centroids = [ np.array([0,0]), np.array([3,3]), np.array([0,4]) ]
ccov = [ np.array([[1,0.4],[0.4,1]]), np.diag((1,2)), np.diag((0.4,0.1)) ]
cen_lst, cov_lst, p_k, logL = em.em_gm(data, K = 2, max_iter = 400)
for cen in cen_lst: print cen
for cov in cov_lst: print cov

[ 66.22733783 135.69250285]
[ 72.92994695 194.55997484]
[[ 14.62653617 53.38371315]
[ 53.38371315 414.95573112]]
[[ 7.77047547 24.7439079 ]
[ 24.7439079 1369.68034031]]

Kod biometric_data_simple.txt verisi üzerinde işletildiğinde rapor edilen µ, Σ


değerlerini grafikleyince başta paylaştığımız grafik görüntüleri çıkacaktır, yani
kümeleme başarıyla işletilmiştir.
En İyi K Nasıl Bulunur
Bu sayıyı keşfetmek artık kolay; K-Means ile atılan bir sürü taklaya, ki çoğu
gayrı matematiksel, sezgisel, uydurulmuş (heuristic) yöntemlerdi, artık gerek
yok. Mesela 10 ila 30 arasındaki tüm küme sayılarını deneriz, ve en iyi AIC vereni
seçeriz.

import pandas as pd
ff = '../../app_math/kmeans/synthetic.txt'
df = pd.read_csv(ff,comment='#',names=['a','b'],sep=" ")

from sklearn.mixture import GMM


for i in range(10,30):
g = GMM(n_components=i).fit(df)
print i, 'clusters', g.aic(df)

10 clusters 124325.897319

13
11 clusters 124132.382945
12 clusters 123931.508911
13 clusters 123865.913489
14 clusters 123563.524338
15 clusters 123867.79925
16 clusters 123176.509776
17 clusters 123239.708813
18 clusters 123019.873822
19 clusters 122728.247239
20 clusters 122256.554363
21 clusters 122259.954752
22 clusters 122271.805211
23 clusters 122265.886637
24 clusters 122265.344662
25 clusters 122277.924153
26 clusters 122184.54412
27 clusters 122356.971927
28 clusters 122195.916167
29 clusters 122203.347265

Görüldüğü gibi AIC azalıyor, azalıyor, ve K=20’de azıcık artıyor, sonra 25’e kadar
artmaya devam ediyor, sonra tekrar düşmeye başlıyor ama bizi ilgilendiren uzun
süreli düşüşten sonraki bu ilk çıkış. O nokta optimal K değerini verecektir, ki bu
sayı 20.

from sklearn.mixture import GMM


g = GMM(n_components=20).fit(df)

plt.scatter(df.a,df.b)
plt.hold(True)
plt.plot(g.means_[:,0], g.means_[:,1],'ro')
plt.savefig('stat_gmm_03.png')

Gaussian Karışımları ile Deri Rengi Saptamak


Bir projemizde dijital resimlerdeki deri rengi içeren kısımları çıkartmamız gerekiy-
ordu; çünkü fotoğrafın diğer renkleri ile ilgileniyorduk (resimdeki kişinin üzerindeki
kıyafetin renkleri) ve bu sebeple deri renklerini ve o bölgeleri resimde sapta-
mak gerekti. Bizim de önceden aklımızda kalan bir tembih vardı, Columbia

14
Üniversitesi’nde yapay öğrenim dersi veren Tony Jebara derste paylaşmıştı bir
kere (bu tür gayrı resmi, lakırdı seviyesinde tiyolar bazen çok faydalı olur), deri
rengi bulmak için bir projesinde tüm deri renklerini R,G,B olarak grafiğe basmışlar,
ve beyaz olsun, zenci olsun, ve sonuç grafikte deri renklerinin çok ince bir bölgede
yanyana durduğunu görmüşler. İlginç değil mi?
Buradan şu sonuç çıkıyor ki diğer renklerin arasında deri renklerine odaklanan,
onları “tanıyan” bir yapay öğrenim algoritmasının oldukça şansı vardır. Ama
ondan önce veriye bakıp grafiksel olarak ne olduğunu görelim.

import pandas as pd, zipfile


with zipfile.ZipFile('skin.zip', 'r') as z:
d = pd.read_csv(z.open('skin.csv'),sep=',')
print d[:3]
Unnamed: 0 rgbhex skin r g b h \
0 0 #200e08 False 0.125490 0.054902 0.031373 0.041667
1 1 #6d6565 False 0.427451 0.396078 0.396078 0.000000
2 2 #1f2c4d False 0.121569 0.172549 0.301961 0.619565

s v
0 0.750000 0.125490
1 0.073394 0.427451
2 0.597403 0.301961

Burada önemli olan R,G,B ve H,S,V kolonları. Bu iki grup değişik renk kodlama
yöntemini temsil ediyorlar. Grafikleyelim,

nd = d[d['skin'] == False]
sd = d[d['skin'] == True]
plt.plot(nd['r'],nd['g'],'.')
plt.hold(True)
plt.plot(sd['r'],sd['g'],'rx')
plt.savefig('stat_gmm_01.png')

Ya da H,S üzerinden

nd = d[d['skin'] == False]
sd = d[d['skin'] == True]

15
plt.plot(nd['h'],nd['s'],'.')
plt.hold(True)
plt.plot(sd['h'],sd['s'],'rx')
plt.savefig('stat_gmm_02.png')

Demek ki Jebara haklıymış. Veriye bakınca bir kabaca / sezgisel (intuitive) bazı
çıkarımlar yapmak mümkün. Mesela her iki grafikte de deri renklerini belirten
bölgenin grafiği sanki 3 boyutlu bir Gaussian’ın üstten görünen / kontur (con-
tour) hali. Bunu bilmek bir avantaj, bu avantajı kullanmak lazım. Modelimiz
gerçek dünya verisine ne kadar yakınsa, yapay öğrenim şansı o kadar fazlalaşacaktır.
Eğer o bölgeye bir Gaussian uydurursak (fit) tanıma şansımız artacaktır.
O zaman deri rengi tanıma şu şekilde yapılabilir. Scikit Learn kütüphanesinin
Gaussian Karışımları (GMM) paketini kullanabiliriz. Tek problem bu karışımlar
olasılık fonksiyonunu öğreniyorlar, sınıflama (classification) yapmıyorlar. Önemli
değil, şöyle bir ek kod ile bunu halledebiliriz; iki tane GMM yaratırız, bir tanesi
deri renk bölgeleri için, diğeri diğer bölgeler için. Eğitim sırasında her iki GMM’i
kendi bölgeleri üzerinde eğitiriz. Sonra, test zamanında, her yeni (bilinmeyen)
veri noktasını her iki GMM’e veririz, hangisinden daha yüksek olasılık değeri
geliyorsa, etiket değeri olarak o GMM’in değerini alırız.
GMM’leri, ve onların içindeki Gaussian’ların kovaryanslarını kullanmak faydalı,
kovaryans bildiğimiz gibi bir Gaussian’ın hangi yönde daha fazla ağırlığının olacağını
belirler, eğer kovaryans hesabı yapılmazsa, yani kovaryans matrisinin sadece
çaprazında değerler varsa, mesela üç boyutta Gaussian’ın konturu bir çember
olarak gözükür [1, sf 90]. Tabii her yönde aynı ağırlıkta olan bir Gaussian her
türlü veriyi temsil edemez, en esneği (ki grafiğe bakınca bu gerekliliği görüyoruz)
tam kovaryans kullanmaktır. Scikit Learn ile bu seçim GMM için full ile yapılır,
sadece çaprazı kullan anlamına gelen diag da olabilirdi.

import zipfile
from sklearn.cross_validation import train_test_split
from sklearn.metrics import roc_curve, auc
from sklearn.metrics import roc_auc_score
from sklearn.mixture import GMM
import pandas as pd

16
class GMMClassifier():
def __init__(self,k,var):
self.clfs = [GMM(n_components=k,
covariance_type=var,thresh=0.1,
min_covar=0.0001,n_iter=100) for i in range(2)]

def fit(self,X,y):
self.clfs[0].fit(X[y==0])
self.clfs[1].fit(X[y==1])

def predict(self,X):
res0 = self.clfs[0].score(X)
res1 = self.clfs[1].score(X)
res = (res1 > res0)
return res.astype(float)

if __name__ == "__main__":

with zipfile.ZipFile('skin.zip', 'r') as z:


df = pd.read_csv(z.open('skin.csv'),sep=',')
y = (df['skin'] == True).astype(float)
X = df[['h','s','v','r','g']]

res = []
for i in range(5):
clf = GMMClassifier(k=10,var='full')
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=2000)
clf.fit(x_train,y_train)
preds = clf.predict(x_test)

fpr, tpr, thresholds = roc_curve(y_test, preds)


roc_auc = auc(fpr, tpr)
res.append(roc_auc)

print 'deneyler'
print res
print 'nihai ortalama', np.array(res).mean()

deneyler
[0.99075081610446136, 0.98417442945172173, 0.98641291695170819,
0.98779826464208242, 0.99239130434782608]
nihai ortalama 0.9883055463

Başarı oranı yüzde 98.8! Bu problem üzerinde pek çok diğer yöntem denedik,
mesela KNN sınıflayıcı, Lojistik Regresyon, vs. gibi, bu yöntem tüm diğerlerini
geçti.
İlginç bir yan bir soru, “hangi kolonların kullanılacağı”. Bu bağlamda projede
arkadaşlardan “ama HSV değerleri RGB değerlerinden türetilebiliyor, ya birini
ya ötekini kullanmak yeterli olmaz mı?” yorumu yapanlar oldu. Evet, bu verinin
diğerinden “türetilmiş” olduğu doğru, ve beklenir ki ideal bir dünyada mükemmel
bir yapay öğrenim algoritmasının bu tür bir yardıma ihtiyacı olmaz, algoritma o
kadar iyidir ki ona sanki aynı veriyi tekrar vermiş gibi oluruz, en iyi ihtimalle ek
külfet yaratırız. Fakat pratikte bu ek veri algoritmaya ek bazı sinyaller verebilir.

17
Mesela eğer müşterilerin kilosu üzerinden bir öğrenim yapıyor olsaydık, 80 kilo-
dan daha az ya da daha fazla olmayı (problem alanına göre) ayrı bir kolon olarak
kodlamak avantaj getirebilirdi. Tabii ki kilo verisi sayısal değer olarak azıyla fa-
zlasıyla oradadır, fakat önem verdiğimiz noktaları türetilmiş veri olarak öğrenim
algoritmasına vermenin zararı yoktur. Üstteki örnekte GB değerlerinin HSV ile
beraber kullanılmasının başarı şansını biraz daha arttırdığını görebiliriz.
Kaynaklar
[1] Alpaydin, E., Introduction to Machine Learning
[2] Jebara, T., Columbia Machine Learning Course
[3] Aaron A. D’Souza, Using EM To Estimate A Probability Density With A Mixture
Of Gaussians, http://www-clmc.usc.edu/˜adsouza/notes/mix_gauss.
pdf
[4] Expectation-Maximization (Python Recipe), http://code.activestate.com/
recipes/577735-expectation-maximization
[5] Zaki, Data Mining and Analysis: Fundamental Concepts and Algorithms
[6] Bayramli, Istatistik, Çok Değişkenli Bernoulli Karışımı

18
Birden Fazla Düz Çizgi Regresyonu, Çizgi Karışım Modeli (Line Mixture Model
-LMM-)
Aynen veriye bir veya birden fazla boyutlu Gaussian karışımlarını uydurabildiğimiz
gibi birden fazla çizgilerin karışımını da veriye uydurabiliriz. Alttaki veriye bakalım,

#lines = [[1,4,10,50],[-1,30,5,50],[4,10,20,40],[0.4,0,80,100]]
lines = [[1,4,10,50],[-1,30,5,50],[4,10,20,40]]
xs = []; ys = []
for a,b,x1,x2 in lines:
x = np.linspace(x1,x2,100)
y = a*x + b
y += np.random.randn(100)*4
xs.append(x); ys.append(y)
xs = np.array(xs).T.flatten()
ys = np.array(ys).T.flatten()
plt.scatter(xs,ys)
plt.hold(True)
plt.savefig('stat_lmm_01.png')

Model olarak düz çizgi kullanmaya karar verdikten sonra önemli soru şu: çizgileri
nasıl modelleriz? Bize bir olasılıksal temsil yöntemi lazım ki böylece bir maksi-
mum olurluk denklemi türetebilelim ve bu denklemi Beklenti-Maksimizasyon
(Expectation-Maximization -EM-) ile çözelim.
Bir fikir: her nokta üzerinde sanki bir tek boyutlu Gaussian varmış gibi düşünebiliriz,
ve o noktada hatayı (negatif olurluk) ölçeriz, ki hata o noktada olduğu düşünülen
bir çizginin gerçek veri noktasına olan y eksenindeki uzaklığı olabilir. Böylece li-
neer regresyon tekniğini aslında çok çizgili olacak şekilde genişletmiş oluyoruz.
Bu karışım modelin formu şöyle,

Y
N X
K
L= πk N(yi ; fk (xi ), σ2k )
i=1 k=1

1
X
N X
K
1
log L = log πk p exp(−(yi − fk (xi ))2 /2σ2k )
i=1 k=1
2πσ2k

ki çizgi tanıdık gelecek formül,

fk (xi ) = ak xi + bk

Q fonksiyonu,

X
N X
K 
1 (yi − (ak xi + bk ))2

2
Q∝ log πk − log(σk ) − ηik
i=1 k=1
2 2σ2k

ηik , i noktasının k çizgisine ait olma olasılığıdır.


Türevleri alırsak,

∂Q X N
∝ (yi − ak xi − bk )xi ηik = 0
∂ak i=1

∂Q X N
∝ (yi − ak xi − bk )ηik = 0
∂bk i=1

PK
 

∂ Q+λ k=1 πk − 1 X
N X
K
ηik
∝ +λ=0 πk = 1
∂πk i=1
πk k=1

Tekrar düzenleyip parametreler için çözüm yaparsak,

PN
i=1 xi (yi − bk )ηik
âk = PN 2
i=1 xi ηik

PN
i=1 (yi − ak xi )ηik
b̂k = PN
i=1 ηik
PN
i=1 (yi − (ak xi + bk ))2 ηik
σ̂2k = PN
i=1 ηik

1 X
N
π̂k = ηik
N i=1

2
def em_line(x,y,n_components):
eta = np.random.rand(len(x),n_components)
a = np.random.rand(n_components) * 10
b = np.random.rand(n_components) * 10
sigma2 = np.random.rand(n_components) * 10
pi = np.random.rand(n_components)

for i in range(1000):
for k in range(n_components):
# hats
ahat = np.sum(x*(y-b[k])*eta[:,k]) / np.sum(x**2*eta[:,k])
etasum = np.sum(eta[:,k])
bhat = np.sum((y-a[k]*x)*eta[:,k]) / etasum
sigma2hat = np.sum( (y - (a[k]*x+b[k]))**2 * eta[:,k] ) / etasum
pihat = (1./len(x)) * etasum
#print ahat, bhat, sigma2hat, pihat
a[k] = ahat
b[k] = bhat
sigma2[k] = sigma2hat
pi[k] = pihat

for k in range(n_components):
tmp1 = 1. / np.sqrt(2*np.pi*sigma2[k])
tmp2 = (y-(a[k]*x+b[k]))**2
eta[:,k] = tmp1 * np.exp(-( tmp2 / (2*sigma2[k]) ) )

eta = eta / eta.sum(axis=1)[:,None]

return a,b,eta

a,b,eta = em_line(xs,ys,n_components=3)
print a
print b

plt.scatter(xs,ys)
plt.hold(True)
for k in range(3):
tmp = np.linspace(0,60,100)
plt.plot(tmp,tmp*a[k]+b[k])
plt.hold(True)
plt.savefig('stat_lmm_02.png')

[-1.02632885 3.9704963 0.96107527]


[ 30.43624091 11.21649921 5.18239643]

3
labels = np.argmax(eta, axis=1)
colors = ['r','b','g','c']
for k in range(3):
plt.plot(xs[labels==k],ys[labels==k],'.'+colors[k])
plt.hold(True)
plt.savefig('stat_lmm_03.png')

Çözüm hiç fena değil.


Yanlız bazı potansiyel eksiklerden bahsedelim; çizgiler tanım itibariyle sonsuz-
dan gelip sonsuza giden şeylerdir, yani uzunlukları temsil ettiği veri kümesini
aşabilir, bu sebeple eğer onlara yakın başka kopuk ama yakınca başka bir veri
kümesi var ise LMM o kümeyi de modellemeye uğraşacağı için temsiliyet bozu-
labilir. Eğer yanyana kopuk pek çok veri kümesi var ise belki Gaussian Karışım
Modeli (GMM) daha iyi bir çözüm olabilir. GMM’lerin kovaryansları bir kon-
tur bağlamda ince bir elips haline gelerek düz “çizgimsi” ama kopuk bir bölgeyi
rahatça temsil edebilir.
Kaynaklar
[1] Traa, Expectation Maximization - Math and Pictures, http://cal.cs.illinois.
edu/˜johannes/research/EM%20derivations.pdf

4
Regresyon, Ridge, Lasso, Çapraz Sağlama, Regülarize Etmek
Konumuz regresyon çeşitleri, ve örnek veri olarak diyabet hastalığı olan kişilerden
alınmış bazı temel verilerle hastalığın bir sene sonraki ilerleme miktarı kullanılacak.
Regresyon sayesinde temel veriler ile hastalığın ilerlemesi arasında bir bağlantı
bulunabilir, bu sayede hem veri açıklanır / daha iyi anlaşılır (hangi değişken
önemlidir, hangisi değildir), hem de başka bir hastanın temel verilerini kulla-
narak o hastanın diyabetinin bir sene sonra ne olacağını tahmin etmek mümkün
olur. Kullanılan temel veriler kişinin yaşı, cinsiyeti, vücut kütle endeksi (body
mass index) ortalama tansiyonu ve altı kere alınmış kan serum ölçümleridir.

from pandas import *


diabetes = read_csv("diabetes.csv",sep=';')
diabetes_y = diabetes['response']
diabetes_x = diabetes.drop("response",axis=1)
diabetes_x_train = diabetes_x[:-20]
diabetes_x_test = diabetes_x[-20:]
diabetes_y_train = diabetes_y[:-20]
diabetes_y_test = diabetes_y[-20:]

İlk önce basit regresyonu hatırlayalım. Bu tekniği daha önce pek çok yönden
gördük. Lineer Cebir, Çok Değişkenli Calculus ders notlarında bu tekniğin türetilmesi
mevcut. Formül

ŵ = (XT X)−1 XT y

Sayısal olarak hemen bu hesabı yapabiliriz. Bir hatırlatma: veri setine y ekseninin
nerede kesildiğinin bulunabilmesi için suni bir ekstra kesi, “intercept” adlı kolon
ekleyeceğiz, bu kolon iki boyutta y = ax + c formülündeki c’nin bulunabilmesi
içindir. Pandas ile bu ekstra kolonu eklemek çok basit, ismen mevcut olmayan
kolon erişildiği anda o kolon hemen yoktan yaratılır.

import numpy.linalg as la
x_tmp = diabetes_x_train.copy()
x_tmp['intercept'] = 1
xTx = np.dot(x_tmp.T,x_tmp )
ws = np.dot(la.inv(xTx),np.dot(x_tmp.T,diabetes_y_train))
print ws

[ 3.03499452e-01 -2.37639315e+02 5.10530605e+02 3.27736981e+02


-8.14131711e+02 4.92814589e+02 1.02848453e+02 1.84606489e+02
7.43519617e+02 7.60951724e+01 1.52764307e+02]

Aynı hesabı bir de scikit-learn paketini kullanarak yapalım. Bu paketin LinearRegression


çağrısı kesi ekleme işini otomatik olarak hallediyor, eğer kesi olmasın isteseydik,
fit_intercept=False diyecektik.

from sklearn import linear_model, cross_validation


lin = linear_model.LinearRegression()

1
lin.fit(diabetes_x_train, diabetes_y_train)
print lin.coef_
print "score", lin.score(diabetes_x_test, diabetes_y_test),

[ 3.03499452e-01 -2.37639315e+02 5.10530605e+02 3.27736981e+02


-8.14131711e+02 4.92814589e+02 1.02848453e+02 1.84606489e+02
7.43519617e+02 7.60951724e+01]
score 0.585075302278

Sonuçlar birbirine oldukça yakın. Şimdi diğer tekniklere gelelim.


Sırt Regresyonu (Ridge Regression)
Klasik regresyon ile

ŵ = arg min ||y − Xw||2


w

problemini çözdüğümüzü biliyoruz, ki ||·||2 Öklit normunun karesini temsil ediyor.


Fakat bazı durumlarda XT X’in eşsiz (singular) olması mümkün ki böyle bir du-
rumda (XT X)−1 ’in tersini almamız mümkün olmazdı. Eşsizlik ne zaman ortaya
çıkar? Eğer elimizde veri noktasından daha fazla boyut var ise mesela... Diyelim
ki veri olarak 10 tane kolon var, ama sadece 9 tane veri satırı. Sırt Regregyonunun
çıkış noktası budur.
Fakat ek olarak bu teknik kestirme hesaplarımıza (estimation) bir yanlılık (bias)
eklemek için de kullanılabilir ve bu meyil kestirme hesaplarının iyileşmesine fay-
dalı olabilir.
Meyili nasıl ekleriz? Diyelim ki bizim tanımlayacağımız bir λ ile tüm ws’lerin
toplamına bir üst sınır tanımlayabiliriz. Böylelikle regresyonun bulacağı kat-
sayıların çok fazla büyümesine bir ”ceza” getirmiş olacağız, ve bu cezayı içeren
regresyon hesabı o cezadan kaçınmak için mecburen bulacağı katsayıları ufak
tutacak, hatta bazılarını sıfıra indirebilecek. Bu azaltmaya istatistikte küçülme
(shrinkage) ismi veriliyor.
Sırt regresyonu için bu küçültme şöyle

ŵsirt = arg min(||y − Xw||2 + λ||w||2 )


w

Görüldüğü üzere w’nin büyüklüğünü, bir λ katsayısı üzerinden minimizasyon


problemine dahil ettik, böylece diğer parametreler ile büyüklük te minimize edile-
cek. Üstteki tanım sınırı tanımlanmamış (unconstrained) bir optimizasyon prob-
lemidir. Sınırlı olarak

min ||y − Xw||2


w

||w|| 6 τ koşuluna göre (subject to)


2

2
ki λ Lagrange çarpanıdır. Aslında şimdiye kadar üstteki çevrimin tersini gördük
çoğunlukla (yani sınırlı problemden sınırsıza gitmeyi), bu gidiş tarzını görmek te
iyi oldu.
Neyse baştaki sınırsız problemi çözmek için ifadenin gradyanını alalım,

∇ ||y − Xw||2 + λ||w||2




∇ (y − Xw)T (y − Xw) + λwT w




∇ (yT − wT XT )(y − Xw) + λwT w




∇(yT y − yT Xw − wT XT y + wT XT Xw + λwT w)

−yT X − XT y + 2XT Xw + 2λw

−2XT y + 2XT Xw + 2λw

2XT Xw + 2λw − 2XT y

2(XT X + λI)w − 2XT y

Minimizasyon için üstteki ifadeyi sıfıra eşitleyebiliriz

2(XT X + λI)w − 2XT y = 0

O zaman

(XT X + λI)w = XT y

ŵ = (XT X + λI)−1 XT y

Bu son ifade en az kareler (least squares) yani normal regresyon çözüm formülüne
çok benziyor, sadece ek olarak bir λI toplama işlemi var. Demek ki sırt regresy-
onunu kullanmak için zaten yaptığımız hesaba, zaten bizim kendimizin karar
verdiği bir λ üzerinden λI eklersek, geri kalan tüm işlemler aynı olacak.
Kontrol edelim

3
lam = 0.2
wridge = np.dot(la.inv(xTx+lam*np.eye(xTx.shape[0])),\
np.dot(x_tmp.T,diabetes_y_train))
print wridge

[ 16.70807829 -179.42288145 447.64999897 285.41866481 -51.7991733


-75.09876191 -192.46341288 123.61066573 387.91385823 105.53294479
152.7637018 ]

Şimdi scikit-learn ile aynı hesabı yapalım

ridge = linear_model.Ridge(alpha=0.2)
ridge.fit(diabetes_x_train, diabetes_y_train)
print ridge.score(diabetes_x_test, diabetes_y_test), ridge.coef_

0.553680030106 [ 16.69330211 -179.414259 447.63706059 285.40960442 -51.79094255


-75.08327488 -192.45037659 123.60400024 387.91106403 105.55514774]

Bir yöntem daha var, bu yönteme Lasso ismi veriliyor. Lasso’ya göre cezalandırma

X
n
w2k 6 λ
k=1

üzerinden olur. Bu yöntemin tüm detaylarına şimdilik inmeyeceğiz.


Örnek olarak bir λ ile onun bulduğu katsayılara bakalım.

lasso = linear_model.Lasso(alpha=0.3)
lasso.fit(diabetes_x_train, diabetes_y_train)
print lasso.coef_

[ 0. -0. 497.3407568 199.17441037 -0. -0.


-118.89291549 0. 430.93795945 0. ]

Lasso bazı katsayıları sıfıra indirdi! Bu katsayıların ağırlık verdiği değişkenleri,


eğer Lasso’ya inanırsak, modelden tamamen atmak mümkündür.
Bu arada Sırt ve Lasso yöntemlerinin metotlarına ”regülarize etmek (regulariza-
tion)” ismi de veriliyor.
k-Katlamalı Çapraz Sağlama (k-fold Cross-Validation)
Bir yapay öğrenim algoritmasını kullanmadan önce veriyi iki parçaya ayırmak ise
yarar; bu parçalar tipik olarak eğitim verisi (training set) diğeri ise test verisi (val-
idation set) olarak isimlendirilir. İsimlerden belli olacağı üzere, algoritma eğitim
seti üzerinde eğitilir; ve başarısı test verisi üzerinden rapor edilir. Bir bakıma
modelin oluşturulması bir set üzerindendir, sonra ”al şimdi hiç görmediğin bir
veri seti, bakalım ne yapacaksın” sorusunun cevabı, sağlaması bu şekilde yapılır.
Not: AIC istatistiği, standart şartlar altında, çapraz saglama ile eşdeğerdedir, ki
bu durumda iki farklı veri öbeğine gerek yok, eğitim verisi yeterli.

4
k-Katlamalı Çapraz Sağlama bu iki parçalı eğitim / test kavramını bir adım öteye
taşır. Ufak bir k seçeriz, ki bu genellikle 5 ila 10 arasında bir sayı olur, ve tüm ver-
imizi rasgele bir şekilde ama k tane ve eşit büyüklükte olacak şekilde parçalara
ayırırız. Bu parçalara ”katlar (folds)” ismi verilir bazen (ki isim buradan geliyor).
Sonra teker teker her parçayı test verisi yaparız ve geri kalan tüm parçaları eğitim
verisi olarak kullanırız. Bu işlemi tüm parçalar için tekrarlarız.
Bu yaklaşım niye faydalıdır? Çünkü veriyi rasgele şekillerde bölüp, pek çok
yönden eğitim / test için kullanınca verinin herhangi bir şekilde bizi yönlendirmesi
/ aldatması daha az mümkün hale gelir.
Ve işte bu özelliği, ek olarak, çapraz sağlamayı ”model seçmek” için vazgeçilmez
bir araç haline getirir.
Model seçmek nedir? Model seçimi üstteki bağlamda optimal bir λ bulmaktır
mesela, yani her modeli temsil eden bir λ var ise, en iyi λ’yi bulmak, en iyi modeli
bulmak anlamına geliyor, çapraz sağlama bunu sağlıyor. Çapraz sağlama için
scikit-learn’un sağladığı fonksiyonlar vardır, önce katları tanımlarız, sonra bu
değiştirilmiş regresyon fonksiyonlarına katlama usulünü geçeriz.

k_fold = cross_validation.KFold(n=420, n_folds=7)

Katları üstteki gibi tanımladık. 420 tane veri noktasını 7 kata bol dedik. Şimdi bu
katları kullanalım,

ridge_cv = linear_model.RidgeCV(cv=k_fold)
ridge_cv.fit(np.array(diabetes_x), np.array(diabetes_y))
print ridge_cv.alpha_

0.1

Üstteki sonuç λ = 0.1’i gösteriyor. Bu λ daha optimalmış demek ki. Lasso için
benzer şekilde

lasso_cv = linear_model.LassoCV(cv=k_fold)
print lasso_cv.fit(diabetes_x, diabetes_y)

LassoCV(alphas=None, copy_X=True,
cv=sklearn.cross_validation.KFold(n=420, n_folds=7), eps=0.001,
fit_intercept=True, max_iter=1000, n_alphas=100, normalize=False,
precompute=auto, tol=0.0001, verbose=False)

print lasso_cv.alpha_

0.00283958719118

print lasso_cv.score(diabetes_x_test, diabetes_y_test)

0.597090337358

Şimdi veri setinin bir kısmı üzerinde teker teker hangi algoritmanın daha başarılı
olduğunu görelim.

5
def predict(row):
j = row; i = row-1
new_data = diabetes_x[i:j]
print diabetes_y[i:j], "lasso",lasso_cv.predict(new_data), \
"ridge",ridge_cv.predict(new_data), \
"linear",lin.predict(new_data)

predict(-2) # sondan ikinci veri satiri


predict(-3)
predict(-4)
predict(-5)
predict(-8)

439 132
Name: response, dtype: int64 lasso [ 122.2361344] ridge [ 127.1821212] linear [ 123.56
438 104
Name: response, dtype: int64 lasso [ 101.85154189] ridge [ 108.89678818] linear [ 102.
437 178
Name: response, dtype: int64 lasso [ 192.95670241] ridge [ 189.58095011] linear [ 194.
436 48
Name: response, dtype: int64 lasso [ 52.8903924] ridge [ 57.66611598] linear [ 52.5445
433 72
Name: response, dtype: int64 lasso [ 60.42852107] ridge [ 66.3661042] linear [ 61.1983

Üstteki sonuçlara göre gerçek değeri 132 olan 439. satırda lasso 122.2, sırt (ridge)
127.1, basit regresyon ise 123.5 bulmuş. O veri noktası için sırt yöntemi daha
başarılı çıktı.
Sonuçlara bakınca bazen sırt, bazen normal regresyon başarılı çıkıyor. Hangi
yöntem kazanmış o zaman? Bir o, bir bu öndeyse, hangi yöntemi kullanacağımızı
nasıl bileceğiz?
Aslında her seferinde tek bir metotu kullanmak gerekmiyor. Bu metotları bir
takım (ensemble) halinde işletebiliriz. Her test noktasını, her seferinde tüm metot-
lara sorarız, gelen sonuçların mesela.. ortalamasını alırız. Bu şekilde tek başına
işleyen tüm metotlardan tutarlı olarak her seferinde daha iyi sonuca ulaşacak
bir sonuç elde edebiliriz. Zaten Kaggle gibi yarışmalarda çoğunlukla birinciliği
kazanan metotlar bu türden takım yöntemlerini kullanan metotlar, mesela Netflix
yarışmasını kNN ve SVD metotlarını takım halinde işleten bir grup kazandı.
Kaynaklar
[1] Figueiredo, Lecture Notes on Linear Regression, www.lx.it.pt/˜mtf/Figueiredo_
Linear_Regression.pdf
[3] Harrington, P., Machine Learning in Action
[4] Shalizi, Data Analysis from an Elementary Point of View

6
Özellik İşlemek (Feature Engineering)
Veri madenciliğinde ”veriden veri yaratma” tekniği çok kullanılıyor; mesela bir
sipariş veri satırında o siparişin hangi zamanda (timestamp) olduğunu belirten
bir kolon varsa (ki çoğu zaman vardır), bu kolonu ”parçalayarak” ek, daha genel,
özetsel bilgi kolonları yaratılabilir. Ya da kategoriksel verileri pek çok farklı şekilde
sayısal hale çevirebiliriz, mesela 1-hot kodlama ile N kategori N kolon haline
gelir, eldeki kategoriye tekabül eden öğe 1 diğerleri sıfır yapılır.
Özellik işlemenin önemi yapay öğrenme açısından önemi var, mesela bir SVM
sınıflayıcısını en basit haliyle siyah/beyaz görüntüden sayı tanıma probleminde
kullandık, ve diyelim yüzde 70 başarı elde ettik. Şimdi çok basit bir yeni özellik
yaratalım, görüntüyü dikey ikiye bölelim, ve üstteki ve alttaki siyah noktaları
toplayarak iki yeni kolon olarak görüntü matrisine ekleyelim. Bu yeni özellikleri
kullanınca basit sınıflayıcının yüzde 20 kadar tanıma başarısında ilerleme kay-
dettiğini göreceğiz!
Not: Derin yapay sınır ağları teknikleri ile özellik işlemeye artık gerek olmadığı
söylenir, bu büyük ölçüde doğru. Bir DYSA farklı seviyelerdeki pek çok farklı
nöronları üzerinden aslında üstte tarif edilen türden yeni özellikleri otomatik
olarak yaratır, ögrenir. Fakat yine de yeni özellikleri elle yaratma tekniklerini
bilmek iyi.
Şimdi farklı yöntemlere bakalım.
Zaman Kolonlarını Zenginleştirmek
Zaman kolonları çoğu zaman saniyeye kadar kaydedilir, bu bilgiyi alıp mesela
ay, mevsim, haftanın günü, saat, iş saati mi (9-5 arası), akşam mı, sabah mı, öğlen
mi, vs. gibi ek bilgiler çıkartılabilir. Tüm kolonlar veri madenciliği algoritmasına
verilir, ve algoritma belki öğlen saati ile sipariş verilmiş olması arasında genel bir
bağlantı bulacaktır.
Python + Pandas ile bir zaman kolonu şöyle parçalanabilir, örnek veri üzerinde
görelim, sadece iki kolon var, müşteri no, ve sipariş zamanı,

import pandas as pd
from StringIO import StringIO
s = """customer_id;order_date
299;2012-07-20 19:44:55.661000+01:00
421;2012-02-17 21:54:15.013000+01:00
437;2012-02-20 22:18:12.021000+01:00
463;2012-02-20 23:46:21.587000+01:00
482;2012-05-21 09:50:02.739000+01:00
607;2012-02-21 11:57:12.462000+01:00
641;2012-02-21 13:40:28.088000+01:00
674;2012-08-21 14:53:15.851000+01:00
780;2012-02-23 10:31:05.571000+01:00
"""
df = pd.read_csv(StringIO(s),sep=';', parse_dates=True)

def f(x):

1
tmp = pd.to_datetime(x['order_date'])
tpl = tmp.timetuple(); yymm = int(tmp.strftime('%m%d'))
spring = int(yymm >= 321 and yymm < 621)
summer = int(yymm >= 621 and yymm < 921)
fall = int(yymm >= 921 and yymm < 1221)
winter = int( spring==0 and summer==0 and fall==0 )
warm_season = float(tpl.tm_mon >= 4 and tpl.tm_mon <= 9)
work_hours = float(tpl.tm_hour > 9 and tpl.tm_hour < 17)
morning = float(tpl.tm_hour >= 7 and tpl.tm_hour <= 11)
noon = float(tpl.tm_hour >= 12 and tpl.tm_hour <= 14)
afternoon = float(tpl.tm_hour >= 15 and tpl.tm_hour <= 19)
night = int (morning==0 and noon==0 and afternoon==0)

return pd.Series([tpl.tm_hour, tpl.tm_mon,


tpl.tm_wday, warm_season,
work_hours, morning, noon, afternoon, night,
spring, summer, fall, winter])

cols = ['ts_hour','ts_mon','ts_wday','ts_warm_season',\
'ts_work_hours','ts_morning','ts_noon','ts_afternoon',\
'ts_night', 'ts_spring', 'ts_summer', 'ts_fall', 'ts_winter']

df[cols] = df.apply(f, axis=1)


print df[cols]

ts_hour ts_mon ts_wday ts_warm_season ts_work_hours ts_morning \


0 18.0 7.0 4.0 1.0 0.0 0.0
1 20.0 2.0 4.0 0.0 0.0 0.0
2 21.0 2.0 0.0 0.0 0.0 0.0
3 22.0 2.0 0.0 0.0 0.0 0.0
4 8.0 5.0 0.0 1.0 0.0 1.0
5 10.0 2.0 1.0 0.0 1.0 1.0
6 12.0 2.0 1.0 0.0 1.0 0.0
7 13.0 8.0 1.0 1.0 1.0 0.0
8 9.0 2.0 3.0 0.0 0.0 1.0

ts_noon ts_afternoon ts_night ts_spring ts_summer ts_fall ts_winter


0 0.0 1.0 0.0 0.0 1.0 0.0 0.0
1 0.0 0.0 1.0 0.0 0.0 0.0 1.0
2 0.0 0.0 1.0 0.0 0.0 0.0 1.0
3 0.0 0.0 1.0 0.0 0.0 0.0 1.0
4 0.0 0.0 0.0 1.0 0.0 0.0 0.0
5 0.0 0.0 0.0 0.0 0.0 0.0 1.0
6 1.0 0.0 0.0 0.0 0.0 0.0 1.0
7 1.0 0.0 0.0 0.0 1.0 0.0 0.0
8 0.0 0.0 0.0 0.0 0.0 0.0 1.0

Sıcak mevsim (warm season) Mart-Eylül aylarını kapsar, bu ikisel bir değişken
hale getirildi. Belki siparişin, ya da diğer başka bir verinin bununla bir alakası
vardır. Genel 4 sezon tek başına yeterli değil midir? Olabilir, fakat bazı kalıplar /
örüntüler (patterns) belki sıcak / soğuk mevsim bilgisiyle daha çok bağlantılıdır.
Aynı şekilde saat 1-24 arasında bir sayı olarak var, fakat ”iş saatini” ayrı bir ikisel
değişken olarak kodlamak yine bir ”kalıp yakalama” şansımızı arttırabilir. Bu
kolonun ayrı bir şekilde kodlanmış olması veri tasarımı açısından ona önem ver-

2
ildiğini gösterir, ve madencilik algoritmaları bu kolonu, eğer ona bağlı bir kalıp
var ise, yakalayabilirler.
Not: Burada ufak bir pürüz sabah, öğlen, akşamüstü gibi zamanları kodlarken
çıktı. Gece 19’dan sonra ve 7’den önce bir sayı olacaktı, fakat bu durumda x > 19
ve x < 7 hiçbir sonuç getirmeyecekti. Burada saatlerin 24 sonrası başa dönmesi
durumu problem çıkartıyordu, tabii ki karşılaştırma ifadelerini çetrefilleştirerek
bu iş çözülebilir, ama o zaman kod temiz olmaz (mesela (x > 19 ve x < 24)
ya da (x > 0 ve x < 7) yapabilirdik). Temiz kod için gece haricinde diğer tüm
seçenekleri kontrol ediyoruz, ve gece ”sabah, öğlen, akşamüstü olmayan şey”
haline geliyor. Aynı durum mevsimler için de geçerli. Onun için

night = int (morning==0 and noon==0 and afternoon==0)

kullanıldı.
Kategorileri İkileştirme
Yapay öğrenim algoritmalarının çoğu zaman hem kategorik hem sayısal değerleri
aynı anda bulunduran verilerle iş yapması gerekebiliyor. Ayrıca literatüre bakılınca
görülür ki çoğunlukla bir algoritma ya biri, ya diğeri ile çalışır, ikisi ile aynı anda
çalışmaz (çalışanlar var tabii, mesela karar ağaçları -decision tree-). Bu gibi du-
rumlarda iki seçenek var, ya numerik veri kategoriselleştirilir (ayrıksallaştırılır),
ya da kategorik veri numerik hale getirilir.
Bu durumda, kategorik bir kolon eyalet için, eyaletin Ohio olup olmaması başlı
başına ayrı bir kolon olarak gösteriliyor. Aynı şekilde Nevada. Bu kodlamaya lit-
eratürde 1-hot kodlaması adı veriliyor. KMeans, lojistik regresyon gibi metotlara
girdi vermek için bu transformasyon kullanılabilir.

import numpy as np
import pandas as pd, os
import scipy.sparse as sps
from sklearn.feature_extraction import DictVectorizer

def one_hot_dataframe(data, cols, replace=False):


vec = DictVectorizer()
mkdict = lambda row: dict((col, row[col]) for col in cols)
vecData = pd.DataFrame(vec.fit_transform(data[cols].apply(mkdict, axis=1)).toarray
vecData.columns = vec.get_feature_names()
vecData.index = data.index
if replace is True:
data = data.drop(cols, axis=1)
data = data.join(vecData)
return (data, vecData, vec)

data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],


'year': [2000, 2001, 2002, 2001, 2002],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9]}

df = pd.DataFrame(data)

3
df2, _, _ = one_hot_dataframe(df, ['state'], replace=True)
print df2

pop year state=Nevada state=Ohio


0 1.5 2000 0.0 1.0
1 1.7 2001 0.0 1.0
2 3.6 2002 0.0 1.0
3 2.4 2001 1.0 0.0
4 2.9 2002 1.0 0.0

Unutmayalım, kategorik değerler bazen binleri bulabilir (hatta sayfa tıklama tah-
mini durumunda mesela milyonlar, hatta milyarlar), bu da binlerce yeni kolon
demektir. Yani 1/0 kodlaması, yani 1-hot işleminden ele geçen yeni blok içinde
aslında oldukca çok sayıda sıfır değeri olacak (sonuçta her satırda binlerce ’şey’
içinde sadece bir tanesi 1 oluyor), yani bu bloğun bir seyrek matris olması iyi
olurdu. O zaman matrisin tamamını sps.csr_matrix ya da sps.lil_matrix ile
gerçekten seyrek formata çevirebiliriz, ve mesela scikit-learn paketi, numpy, scipy
işlemleri seyrek matrisler ile hesap yapabilme yeteneğine sahip. Seyrekselleştirince
ne elde ediyoruz? Sıfırları depolamadığımız için sadece sıfır olmayan değerler ile
işlem yapıyoruz, o ölçüde kod hızlanıyor, daha az yer tutuyor.
Dikkat etmek gerekir ki yeni kolonları üretince değerlerin yerleri sabitlenmiş
olur. Her satır bazında bazen state=Ohio, state=Nevada, bazen sadece state=Ohio
üretiyor olamayız. Üstteki örnekte her zaman 4 tane kolon elde edilmelidir.
Not: 1-hot yerine bir diğer seçenek kategoriyi bir indise çevirmek (tüm katego-
rileri sıralayıp kaçıncı olduğuna bakarak mesela) sonra bu sayıyı ikisel sistemde
belirtmek, eğer ’a’ sayısı 30 indisine tekabül ediyorsa, 30 ikisel sistemde 11110,
bu değer kullanılır (aslında bu son tarif edilen sistemin 1-hot sistemden daha iyi
işlediği rapor ediliyor).
Anahtarlama Numarası (1-Hot Encoding, Hashing Trick)
Fakat bir problem var, dokümanı temsil eden ve içinde 1 ya da 0 hücreli özellik
vektörünü (feature vector) oluşturmak için tüm kelimelerin ne olduğunu bilmeliyiz.
Yani veriyi bir kere baştan sonra tarayarak bir sözlük oluşturmalıyız (ki öyle yap-
maya mecbur kaldık) ve ancak ondan sonra her doküman için hangi kelimenin
olup olmadığını saptamaya ve onu kodlamaya başlayabiliriz. Halbuki belgelere
bakar bakmaz, teker teker giderken bile hemen bir özellik vektörü oluşturabilseydik
daha iyi olmaz mıydı?
Bunu başarmak için anahtarlama numarasını kullanmamız lazım. Bilindiği gibi
temel yazılım bilime göre bir kelimeyi temsil eden bir anahtar (hash) üretebiliriz,
ki bu hash değeri bir sayıdır. Bu sayının en fazla kaç olabileceğinden hareke-
tle (hatta bu sayıya bir limit koyarak) özellik vektörümüzün boyutunu önceden
saptamış oluruz. Sonra kelimeye bakarız, hash üretiriz, sonuç mesela 230 geldi,
o zaman özellik vektöründeki 230’uncu kolonun değerini 1 yaparız.

d_input = dict()

4
def add_word(word):
hashed_token = hash(word) % 127
d_input[hashed_token] = d_input.setdefault(hashed_token, 0) + 1

add_word("obama")
print d_input

{48: 1}

add_word("politics")
print d_input

{48: 1, 91: 1}

Üstteki kodda bunun örneğini görüyoruz. Hash sonrası mod uyguladık (yüzde
işareti ile) ve hash sonucunu en fazla 127 olacak şekilde sınırladık. Potansiyel
problemler ne olabilir? Hashing mükemmel değildir, çarpışma (collision) olması
mümkündür yani nadiren farklı kelimelerin aynı numaraya eşlenebilmesi du-
rumu. Bu problemleri iyi bir anahtarlama algoritması kullanarak, mod edilen
sayıyı büyük tutarak çözmek mümkündür, ya da bu tür nadir çarpışmalar ”kabul
edilir hata” olarak addedilebilir.
Pandas kullanarak bir Dataframe’i otomatik olarak anahtarlamak istersek,

import pandas as pd
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
'year': [2000, 2001, 2002, 2001, 2002],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9]}

data = pd.DataFrame(data)
print data

pop state year


0 1.5 Ohio 2000
1 1.7 Ohio 2001
2 3.6 Ohio 2002
3 2.4 Nevada 2001
4 2.9 Nevada 2002

Şimdi bu veri üzerinde sadece eyalet (state) için bir anahtarlama numarası ya-
palım

def hash_col(df,col,N):
for i in range(N): df[col + '_' + str(i)] = 0.0
df[col + '_hash'] = df.apply(lambda x: hash(x[col]) % N,axis=1)
for i in range(N):
idx = df[df[col + '_hash'] == i].index
df.ix[idx,'%s_%d' % (col,i)] = 1.0
df = df.drop([col, col + '_hash'], axis=1)
return df

print hash_col(data,'state',4)

pop year state_0 state_1 state_2 state_3

5
0 1.5 2000 0.0 0.0 0.0 0.0
1 1.7 2001 0.0 0.0 0.0 0.0
2 3.6 2002 0.0 0.0 0.0 0.0
3 2.4 2001 0.0 0.0 0.0 1.0
4 2.9 2002 0.0 0.0 0.0 1.0

Baştan Seyrek Matris ile Çalışmak


Büyük Veri ortamında, eğer kategorik değerler milyonları buluyorsa, o zaman
üstteki gibi normal Numpy matrisinden seyreğe geçiş yapmak bile külfetli ola-
bilir. Bu durumlarda daha en baştan seyrek matris üretiyor olmalıyız. Mevcut
tüm değerleri önceden bildiğimizi farz edersek,

import numpy as np
import pandas as pd, os
import scipy.sparse as sps
import itertools

def one_hot_column(df, cols, vocabs):


mats = []; df2 = df.drop(cols,axis=1)
mats.append(sps.lil_matrix(np.array(df2)))
for i,col in enumerate(cols):
mat = sps.lil_matrix((len(df), len(vocabs[i])))
for j,val in enumerate(np.array(df[col])):
mat[j,vocabs[i][val]] = 1.
mats.append(mat)

res = sps.hstack(mats)
return res

data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],


'year': ['2000', '2001', '2002', '2001', '2002'],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9]}

df = pd.DataFrame(data)
print df

vocabs = []
vals = ['Ohio','Nevada']
vocabs.append(dict(itertools.izip(vals,range(len(vals)))))
vals = ['2000','2001','2002']
vocabs.append(dict(itertools.izip(vals,range(len(vals)))))

print vocabs

print one_hot_column(df, ['state','year'], vocabs).todense()

pop state year


0 1.5 Ohio 2000
1 1.7 Ohio 2001
2 3.6 Ohio 2002
3 2.4 Nevada 2001
4 2.9 Nevada 2002
[{'Ohio': 0, 'Nevada': 1}, {'2002': 2, '2000': 0, '2001': 1}]
[[ 1.5 1. 0. 1. 0. 0. ]

6
[ 1.7 1. 0. 0. 1. 0. ]
[ 3.6 1. 0. 0. 0. 1. ]
[ 2.4 0. 1. 0. 1. 0. ]
[ 2.9 0. 1. 0. 0. 1. ]]

one_hot_column çağrısına bir ”sözlükler listesi” verdik, sözlük her kolon için o
kolonlardaki mümkün tüm değerleri bir sıra sayısı ile eşliyor. Sözlük listesinin
sırası kolon sırasına uyuyor olmalı.
Niye sözlük verdik? Bunun sebebi eğer azar azar (incremental) ortamda iş yapıyorsak,
ki Büyük Veri (Big Data) ortamında her zaman azar azar yapay öğrenim yap-
maya mecburuz, o zaman bir kategorik kolonun mevcut tüm değerlerine azar
azar ulaşamazdık (verinin başında isek, en sonundaki bir kategorik değeri nasıl
görelim ki?). Fakat önceden bu listeyi başka yollarla elde etmişsek, o zaman her
öne-hot işlemine onu parametre olarak geçiyoruz.
Sözlük niye one_hot_dataframe çağrısı dışında yaratıldı? Bu çağrı düz bir liste
alıp oradaki değerleri sırayla bir sayıyla eşleyerek her seferinde bir sözlük yarata-
bilirdi. Bunu yapmadık, çünkü sözlük yaratımının sadece bir kere, one_hot_dataframe
dışında olmasını istiyoruz. Yine Büyük Veri ortamını düşünenelim, eşleme (map)
için mesela bir script yazdık, bu script içinde (basında) hemen sözlükler yaratılırdı.
Daha sonra verinin tamamı için, azar azar sürekli one_hot_dataframe çağrısı yapılacaktır.
O zaman arka arkaya sürekli aynı veriyi (sözlükleri) sıfırdan tekrar yaratmamız
gerekirdi. Bu gereksiz performans kaybı demek olacaktı. Unutmayalım, Büyük
Veri ortamında tek bir kategorik kolonun milyonlarca değişik değeri olabilir!
Azar Azar İşlemek (Incremental, Minibatch Processing)
Çoğu zaman onlarca kategori, birkaç milyonluk satır içeren bir veriye bakmamız
gerekiyor; biliyoruz ki bu kadar veri için Büyük Veri teknolojilerine (mesela Spark,
Hadoop gibi) geçmek gereğinden fazla külfet getirecek, elimizdeki dizüstü, masaüstü
bilgisayarı bu işlemler için yeterli olmalı, fakat çoğu kütüphane tek makinada
azar azar işlem yapmak için yazılmamış. Mesela üstte görülen anahtarlama yöntemi
anahtarlama başlamadan önce tüm verinin hafızaya alınmasını gerektiriyor.
Bu durumda kendimiz çok basit Python kavramlarını, iyi bir anahtarlama ko-
dunu, ve lineer cebir hesaplarında seyreklik (sparsity) tekniklerini kullanarak
ufak veri parçaları işleyen bir ortamı yaratabiliriz.
Örnek veri olarak [4] yazısında görülen oy kalıpları verisini biraz değiştirerek
yeni bir analiz için kullanalım. Veri oy verenlerin ırk, cinsiyet, meslek, hangi
partiye oy verdikleri ve kazançlarını kaydetmiş, biz analizimizde bahsedilen kat-
egorilerin bu kişilerin kazancıyla bağlantılı olup olmadığına bakacağız. Veriyi
oluşturalım,

import pandas as pd
df = pd.read_csv('../stat_logit/nes.dat',sep=r'\s+')
df = df[['presvote','year','gender','income','race','occup1']]
df = df.dropna()
df.to_csv('nes2.csv',index=None)

7
Önce kategorilerden ne kadar var, sayalım. Basit toplam yani,

import pandas as pd
df = pd.read_csv('nes2.csv')
print u'tüm veri', len(df)
print 'cinsiyet', np.array(df['gender'].value_counts())
print u'ırk', np.array(df['race'].value_counts())
print 'parti', np.array(df['presvote'].value_counts())
print u'kazanç', df['income'].mean()

tüm veri 13804


cinsiyet [7461 6343]
ırk [12075 1148 299 180 85 17]
parti [6998 6535 271]
kazanç 3.07649956534

Mesela son sonuçtaki her hücre belli bir partiye verilen oyların sayısı; veriye göre
üç farklı kategori varmış demek ki, veri ABD için olduğuna göre bunlardan ilk
ikisi bilinen iki büyük parti, üçüncü hücre de herhalde bağımsız adaylar.
Kazanç 1 ile 5 arasında tam sayılar (1 az, 5 çok) bu sayıları kategorik olarak kabul
edip aslında çok çıktılı bir sınıflayıcı eğitmeyi de seçebilirdik, fakat bu örnek
için bu sayıları reel hedef olarak aldık: test verisinde tahminleri bakılırsa 2.5’lük
kazanç tahminleri görülebilir, bu yüzden.
Kategorik verileri ikileştirmeye gelelim. Burada üç nokta önemli, veriyi azar azar
işleyeceğiz demiştik, ve veriyi seyrek matris olarak almak istiyoruz, ve hangi kat-
egorik değerin hangi kolona eşleneceğini elle tanımlamak istemiyoruz (eşleme
otomatik olmalı). Seyreklik önemli çünkü eğer 1000 farklı kategorik değere sahip
olan 10 tane kolon varsa, bu 10000 tane yeni kolon yaratılması demektir - her
farklı kategori için o değere tekabül eden kolon 1 olacak gerisi 0 olacak. Bu
rakamlar orta ölçekte bile rahatlıkla milyonlara ulaşabilir. Eğer ikileştirme için
seyrek matris kullanırsak çoğu sıfır olan değerler hafızada bile tutulmaz. Eşleme
otomatik olmalı, zaten onun için anahtarlama yapacağız.
Anahtarlama icin sklearn.feature_extraction.text.HashingVectorizer var,

from sklearn.feature_extraction.text import HashingVectorizer


import numpy as np
vect = HashingVectorizer(n_features=20)
a = ['aa','bb','cc']
res = vect.transform(a)
print res

(0, 5) 1.0
(1, 19) 1.0
(2, 18) -1.0

Sonuçlar seyrek matris olarak, ve üç değer için üç ayrı satır olarak geldi. Anahtar-
lama niye bazen -1 bazen +1 veriyor? Aslında bu bizim için çok faydalı, çünkü
birazdan PCA işleteceğiz, ve PCA her veri kolonunun sıfırda ortalanmış olmasını
ister. Üstteki teknikte anahtar üreten fonksiyon -1,+1 arasında rasgele seçim yapıyor

8
gibi duruyor, bize göre bu üretilen anahtar kolonlarında -1, +1 değerlerinin doğal
olarak dengelenmesi için yapılmış, böylece otomatik olarak ortalamaları sıfıra in-
ecektir. Akıllıca bir teknik.
Devam edelim, sonucu tek satır olacak şekilde kendimiz tekrar düzenleyebiliriz.
O zaman Python yield kavramını [3] kullanarak (azar azar satır okumak için),
anahtarlama, ve seyrek matrisler ile şu şekilde bir kod olabilir,

from sklearn.feature_extraction.text import HashingVectorizer


import numpy as np
import pandas as pd, csv
import scipy.sparse as sps

HASH = 30
vect = HashingVectorizer(decode_error='ignore',n_features=HASH)

def get_row(cols):
with open("nes2.csv", 'r') as csvfile:
rd = csv.reader(csvfile)
headers = {k: v for v, k in enumerate(next(rd))}
for row in rd:
label = float(row[headers['income']])
rrow = [x + str(row[headers[x]]) for x in headers if x in cols]
X_train = vect.transform(rrow)
yield X_train.tocoo(), label

def get_minibatch(row_getter,size=10):
X_train = sps.lil_matrix((size,HASH))
y_train = []
for i in range(size):
cx,y = row_getter.next()
for dummy,j,val in zip(cx.row, cx.col, cx.data): X_train[i,j] = val
y_train.append(y)
return X_train, y_train

# tek bir satir goster


cols = ['gender','income','race','occup1']
row_getter = get_row(cols)
X,y = get_minibatch(row_getter,size=1)
print y, X.todense()

[4.0] [[ 0. 0. 0. -1. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 1. 0.]]

İlgilendiğimiz kolon listesini get_row’a verip bir gezici fonksiyon yarattık. Bu


geziciyi get_minibatch’e verdik, kaç tane satır istediğimizi ona söylüyoruz, o bize
istenen kadar satırı arka planda geziciye sorarak seyrek matris olarak veriyor. 10
tane daha isteyelim,

X,y = get_minibatch(row_getter,size=10)
print len(y), X.shape, type(X)

10 (10, 30) <class 'scipy.sparse.lil.lil_matrix'>

9
PCA
Lineer Cebir’in temel bileşen analizi (PCA) tekniğini kullanarak boyut azaltması
yapabiliriz. Veriyi yine satır satır işleyerek PCA hesabı yapan teknikler var, kod
veriyi seyrek formatta da alabiliyor. Bu kod lineer cebir PCA yazısında işlendi.

import sys; sys.path.append('../stat_170_pca')


import ccipca
cols = ['gender','income','race','occup1']
row_getter = get_row(cols)
pca = ccipca.CCIPCA(n_components=10,n_features=30)
for i in range(10000):
X,y = get_minibatch(row_getter,size=1)
pca.partial_fit(X)
pca.post_process()

print 'varyans orani'


print pca.explained_variance_ratio_

varyans orani
[ 0.36086926 0.16186391 0.13377998 0.09440711 0.0702763 0.05113956
0.04768294 0.0343724 0.02336052 0.02224802]

Her bileşenin verideki varyansın ne kadarını açıkladığı görülüyor.


Peki 30 kolonu 10 kolona indirdik, acaba veri temsilinde, tahmin etmek amacında
ilerleme elde ettik mi? Veriyi PCA’nın bulduğu uzaya yansıtıp bu boyutu azaltılmış
veriyi regresyonda kullansak ne olur acaba? Yansıtma ve regresyon,

from sklearn.linear_model import SGDRegressor


clf = SGDRegressor(random_state=1, n_iter=1)
row_getter = get_row(cols)
P = pca.components_.T
for i in range(10000):
X_train, y_train = get_minibatch(row_getter,1)
Xp = np.dot((X_train-pca.mean_),P)
clf.partial_fit(Xp, y_train)

Şimdi sonraki 1000 satırı test için kullanalım,

y_predict = []
y_real = []
for i in range(1000):
X_test,y_test = get_minibatch(row_getter,1)
Xp = np.dot((X_test-pca.mean_),P)
y_predict.append(clf.predict(Xp)[0])
y_real.append(y_test[0])
y_predict = np.array(y_predict)
y_real = np.array(y_real)

err = np.sqrt(((y_predict-y_real)**2).sum()) / len(y_predict)


print 'ortalama tahmin hatasi', err
print 'maksimum deger', np.max(y_real)

10
ortalama tahmin hatasi 0.0105872845541
maksimum deger 5.0

1 ile 5 arasında gidip gelen değerlerin tahmininde 0.01 civarı ortalama hata var.
Fena değil. Peki verinin kendisini olduğu gibi alıp regresyonda kullansaydık?
Hedef verisi kazanç, kaynak kolonları geri kalan kategoriler. Üstte olduğu gibi
veri parçaları 1000’er satır, 10 parça olarak alacağız, yani 10,000 satır modeli
eğitmek için kullanılacak. Geri kalanlar test verisi olacak.
sklearn.linear_model.SGDRegressor ufak seyrek matris parçaları ile eğitilebiliyor,

from sklearn.linear_model import SGDRegressor


clf = SGDRegressor(random_state=1, n_iter=1)
row_getter = get_row(cols)

y_predict = []; y_real = []

for i in range(10):
X_train, y_train = get_minibatch(row_getter,1000)
clf.partial_fit(X_train, y_train)

X_test,y_test = get_minibatch(row_getter,1000)
y_predict = clf.predict(X_test)

err = np.sqrt(((y_predict-y_test)**2).sum()) / len(y_predict)


print 'ortalama tahmin hatasi',

ortalama tahmin hatasi 0.0208096951078

Bu sonuç ta hiç fena değil. Sonuç olarak veri içinde bazı kalıplar olduğunu
gördük, tahmin yapabiliyoruz. Hangi kolonların daha önemli olduğunu bulmak
için her kolonu teker teker atıp hatanın yukarı mı aşağı mı indiğine bakabilirdik.
Tekrar vurgulamak gerekirse: üstteki analizde aslında çok fazla kategorik veri
yok, yani statsmodels.formula.api üzerinden güzel formüllerle, regresyon çıktısında
her kategorik değerin güzelce listelendiği türden bir kullanıma da gidebilirdik.
Bu yazıda göstermeye çalıştığımız çok fazla veri, çok fazla kolon / kategori olduğunda
ve tek makina ortamında takip edilebilecek çözümler.
Zaman Karşılaştırmak
Eğer 23:50 ile sabah 00:10 zamanını karşılaştırmak istersek ne yaparız? Eğer saat
ve dakika farkını direk hesaplasak bu iki zamanın çok uzak olduğunu düşünebilirdik.
Fakat aslında aralarında 20 dakika var, zaman dönüp başa gelen bir kavram.

11
Bu hesabı yapmak için bir yöntem çember, açılar kullanmak. Gün içindeki za-
manı 0 ile 1 arasında kodlarız, sonra bu büyüklüğü 2π ile çarparız, bu bize çember
üzerindeki bir noktayı verir, yani zamanı açıya çevirmiş oluruz. Sonra açının sin,
cos değerini hesaplayıp iki rakam elde ederiz, bu iki sayı bize gün içindeki za-
manı temsil eden bir büyüklük verir.
Bu büyüklükleri birbirleri ile karşılaştırmak daha kolay, üstteki şekilde θ2 ve θ3
birbirine yakın, karşılaştırma yaparken sin bize dikey eksendeki izdüşümü, cos
yatay eksendeki izdüşümünü verir, θ2 , θ3 için y eksenindeki yansıma birbirine
çok yakın. Eksen x üzerindeki yansıma farklı biri eksi biri artı yönde fakat yine
de mutlak değer bağlamında birbirlerine çok yakınlar. İstediğimiz de bu zaten.

import scipy.linalg as lin

t1 = 0.12 * 2*np.pi
t2 = 0.97 * 2*np.pi
t3 = 0.03 * 2*np.pi

d1 = (np.cos(t1), np.sin(t1))
d2 = (np.cos(t2), np.sin(t2))
d3 = (np.cos(t3), np.sin(t3))

print ("%f %f" % d1)


print ("%f %f" % d2)
print ("%f %f" % d3)

print u'uzaklık 1-2 =', lin.norm(np.array(d1)-np.array(d2))


print u'uzaklık 2-3 =', lin.norm(np.array(d2)-np.array(d3))

0.728969 0.684547
0.982287 -0.187381
0.982287 0.187381
uzaklık 1-2 = 0.907980999479

12
uzaklık 2-3 = 0.374762629171

Kaynaklar
[1] Teetor, R Cookbook
[2] Scikit-Learn Documentation, 4.2. Feature extraction, http://scikit-learn.
org/dev/modules/feature_extraction.html
[3] Bayramli, Fonksiyon Gezmek ve Yield, https://burakbayramli.github.
io/dersblog/sk/2011/02/fonksiyon-gezmek-ve-yield.html
[4] Bayramli, Istatistik, Lineer Regresyon

13
İlişkisel Madencilik (Association Mining)
İkisel Matris Ayrıştırması (Binary Matrix Factorization)
Veri madenciliği denince pek çok kişinin aklına gelen ilk örnek, aslında, sık bulu-
nan öğe kümeleri (frequent itemsets) örneğidir: ”filanca ülkeden sitemize gelen
müşterilerin aynı zamanda vs özelliklerinin olduğunu da keşfettik” gibi.
Benzer bir örnek, ki bu alan öğe kümelerinin aslında en önemli çıkış sebeplerinden
birisidir, alışveriş sepeti analizidir. Müşterinin her alışverişinde sepetinde belli
mallar vardır, ve bu malların hangilerinin aynı anda, aynı sepette olduğu analiz
edilmeye uğraşılır. Eğer sürekli ekmek ve reçel aynı anda alınıyorsa, bu bilgi kul-
lanılarak belki malların daha iyi konumlandırılması yapılacaktır, vs. Sık bulunan
öğe kümeleri teknikleri bazen değişik adlar altında da geçebiliyor, mesela ilişki
madenciliği (association mining) gibi. Algoritma olarak kullanılan pek çok teknik
var, APriori iyi bilinenlerden, FPGrowth ondan daha hızlı çalışan ve daha tercih
edilen bir teknik. İstatistiki bir teknik olan Çok Boyutlu Bernoulli Karışımları da
bu alanda kullanılan bir yaklaşım.
Bir diğer alternatif ikisel matris ayrıştırması (binary matrix factorızation -BMF-)
kullanmaktır [3]. Aynen SVD’de olduğu gibi BMF de bir matrisi ayrıştırır, fakat
üç matris yerine iki matrise ayrıştırır ve hem sonuç matrisi hem de ayrıştırılan
matrisler sadece 0 ya da 1 değerini taşıyabilirler. Yani bu ayrıştırma sonuç ma-
trislerinin ikisel olmasını mecbur tutar, negatif olmayan matris ayrıştırmasının
(non-negative matrix factorızation) sonuç matrisinin pozitif değerler taşımasını
mecbur kılması gibi. Bunlar birer kısıtlama (constraint) ve bu sonuç o kısıtlamalara
göre ortaya çıkıyor. Dikkat: BMF için toplama işlemi 1 + 0 = 1, 1 + 1 = 1, 0 + 0 = 0
olarak tekrar tanımlanır, yani mantıksal OR işlemi haline gelir.
Ayrıştırma öncesi hangi kerte (rank) k değerine geçmek istediğimizi biz belirti-
riz. BMF’nin öğe kümeleri madenciliği için faydası şurada: öğe kümeleri ararken
baktığımız öğeler kategorik şeylerdir, alışveriş sepeti örneğinde mesela ekmek,
reçel gibi. Kategorik öğeleri daha önce 1-hot kodlaması (encoding) ile 1/0 değerleri
taşıyan yeni kolonlara geçirebildiğimizi görmüştük. Yani tamamen kategorik
değerler taşıyan veriler tamamen 1/0 taşıyacak şekilde tekrar kodlanabilir, yani
ikisel matris haline getirilebilir. Bu ikisel matrisi ayrıştırdığımız zaman ve kendi-
leri de ikisel olan iki yeni matris elde ettiğimizde ise bir anlamda boyut indirgemesi
yapmış oluruz, yani sanki ana matrisi “özetleriz”. İşte bu özet, özellikle çarpılan
“baz” matris, öğe kümelerinin hangileri olduğu hakkında ipuçları içeriyor ola-
bilir.
Bir örnek üzerinde görelim, mesela altta Alice (A), Bob Marley (B) ve Prens Charles
(C) verileri var. Bu kişiler için saçı uzun mu (long-haired), ünlü mü (well-known)
ve bay mı (male) verileri var.

1
Bu matris üzerinde ikisel ayrıştırma yaparsak, k = 2

Eğer kontrol etmek istersek, matris çarpımı yapmamız gerekir, bunun için

a = np.array([[1, 0],
[1, 1],
[0, 1]], dtype=bool)
b = np.array([[1, 1, 0],
[0, 1, 1]], dtype=bool)

print np.dot(a,b)

[[ True True False]


[ True True True]
[False True True]]

0 ve 1 değerleri görmek için 1 ile çarpmak yeterli

print 1*np.dot(a,b)

[[1 1 0]
[1 1 1]
[0 1 1]]

Sonuç başlangıç matrisi ile aynı, demek ki bool tipi matris tanımlayınca Numpy
çarpımı dot, çarpım sırasındaki toplama işlemi için aritmetik toplama yerine VEYA
(OR) kullanması gerektiğini anladı.
Şimdi ayrıştırmayı analiz edelim, özellikle sol taraftaki çarpılan “baz” matrise
bakalım.. [6] yazısından hareketle, bu yazıdaki kolon kombinasyon bakışını kul-
lanalım (tabii toplamanın BMF için OR olduğunu unutmadan), o zaman soldaki
baz matrisin dikey, kolon bazlı olarak, bir özet olduğunu görebiliyoruz. Çünkü
çarpan sağ taraf bu kolonları alıp onları belli şekillerde “kombine ederek” nihai
(orijinal) matrisi ortaya çıkartabilmeli. Bu sebeple soldaki çarpılan matris bir özet
olmalı / baz oluşturmalı, ve bunun yan etkisi olarak kolonlardaki değerlerde belli

2
bir kalıp / örüntü (pattern) olmalı. O zaman her baz kolonunda birbiriyle alakalı
olan ögeler aynı anda 1 değeri taşıyor olacaktır.
Sonuca göre uzun saçlı ve ünlü olmak (1. kolon) arasında bağlantı varmış , ayrıca
erkek olmak ve ünlü olmak (2. kolon) arasında da bağlantı varmış :) Veriye göre
böyle en azından.. Bu sonucu orijinal matrise bakarak ta kontrol edebiliriz.
Ayrıştırma Kodlaması
BMF özel bir hesaptır ve Numpy / Scipy içinde mevcut değildir, ayrı bir kütüphane
kullanmak gereklidir, nimfa paketi içinde gerekli kodlar var. Kurduktan sonra
üstteki örneği şöyle çözebiliriz;

import nimfa
import pandas as pd
import scipy.sparse as sp

def __fact_factor(X):
return X.todense() if sp.isspmatrix(X) else X

A = np.array([[1., 1., 0],


[1., 1., 1.],
[0, 1., 1.]])

fctr = nimfa.mf(A,
seed = "nndsvd",
rank = 2,
method = "bmf",
max_iter = 40,
initialize_only = True,
lambda_w = 1.1,
lambda_h = 1.1)

res = nimfa.mf_run(fctr)

threshold = 0.2
res1 = __fact_factor(res.basis())
res2 = __fact_factor(res.coef())
res1 = np.abs(np.round(res1 - 0.5 + threshold))
res2 = np.abs(np.round(res2 - 0.5 + threshold))
res1 = pd.DataFrame(res1, index=['long-haired','well-known','male'])
res2 = pd.DataFrame(res2, columns=['A','B','C'])
print res1
print '\n'
print res2
0 1
long-haired 1 0
well-known 1 1
male 0 1

A B C
0 1 0 0
1 0 1 1

3
Sonuç neredeyse tıpatıp aynı; sadece çarpan matriste [0,B] kordinatı 1 değil, fakat
bize lazım olan baz matris aynı çıktı.
BMF hakkında bazı ek bilgiler: [2]’ye göre en az hatalı BMF hesaplamak NP-hard
zorluğunda, yani 3SAT gibi, ya da Seyahat Eden Satış Elemanı (Traveling Sales-
man) problemi gibi ki bu problemler kombinatoryel (combinatorial) optimiza-
syon problemleridir; çözüm için tüm olasılıklar denendiği ve kısayolun mevcut
olmadığı çeşitten problemler. Fakat yaklaşıksal BMF metotları oldukça hızlıdır,
ayrıca seyreklik çok fark yaratıyor (pozitif anlamda) ki kategorik veriler gerçek
dünyada çoğunlukla seyrek olarak görülüyor. Eldeki 2000 tane mal çeşidi içinden
bir sepette ancak 5-10 tane ürün oluyor mesela, tüm 2000 tane malı bir sepete koy-
mak mümkün değil.
FPGrowth
Öğe kümeleri bulmak için BMF haricinde bir yöntem FPGrowth yöntemidir [1,2].
Bu yöntem önce her ögeden (tek başına) kaç tane olduğunu sayar, belli bir eşik
değeri minsup altında olanları atar, sonucu sıralar. Bu liste bir yapısına işaret
eden bir başlık yapısı haline gelir. Ağacın kendisini oluşturmak için veri satırları
teker teker işlenir, her satırdaki her öge için başlık yapısındaki en fazla değeri
taşıyan öğe önce olmak üzere tepeden başlanıp alta doğru uzayan bir ağaç yapısı
oluşturulur. Ağaçtaki her düğüm altındaki düğümün sayısal toplamını taşır.
Madencilik için alttan başlanarak yukarı doğru çıkılır (amaç en üste ulaşmak) ve
bu sırada öğeler minsup altında ise, atılırlar. Sonuçta ulaşılan ve atılmayan yollar
bir öğe kümesini temsil ederler.
Örnek verisi olarak alttakini kullanalım,

data = [
['outlook=sunny', 'temparature=hot', 'humidity=high', 'windy=false', 'play=no'],
['outlook=sunny', 'temparature=hot', 'humidity=high', 'windy=true', 'play=no'],
['outlook=overcast', 'temparature=hot', 'humidity=high', 'windy=false', 'play=yes'],
['outlook=rainy', 'temparature=mild', 'humidity=high', 'windy=false', 'play=yes'],
['outlook=rainy', 'temparature=cool', 'humidity=normal', 'windy=false', 'play=yes'],
['outlook=rainy', 'temparature=cool', 'humidity=normal', 'windy=true', 'play=no'],
['outlook=overcast', 'temparature=cool', 'humidity=normal', 'windy=true', 'play=yes'],
['outlook=sunny', 'temparature=mild', 'humidity=high', 'windy=false', 'play=no'],
['outlook=sunny', 'temparature=cool', 'humidity=normal', 'windy=false', 'play=yes'],
['outlook=rainy', 'temparature=mild', 'humidity=normal', 'windy=false', 'play=yes'],
['outlook=sunny', 'temparature=mild', 'humidity=normal', 'windy=true', 'play=yes'],
['outlook=overcast', 'temparature=mild', 'humidity=high', 'windy=true', 'play=yes'],
['outlook=overcast', 'temparature=hot', 'humidity=normal', 'windy=false', 'play=yes'],
['outlook=rainy', 'temparature=mild', 'humidity=high', 'windy=true', 'play=no']
]

Hava ile alakalı bazı veriler [1] bunlar; bu veriler tahmin (outlook), sıcaklık (tem-
parature), nem (humidity), rüzgar (windy), dışarıda oyun oynayan var mı (play).
Mesela ilk satırda tahmin güneşli, ısı sıcak, nem yüksek, rüzgar yok ve oyun
oynayan yok. Bu şekilde bir sürü satır. Biz bu veride bir kalıp olup olmadığına
bakacağız. [2]’deki kodu [1]’den aldığımız üstteki veriye uygularsak, sonuç şöyle:

4
import fp
items = fp.fpgrowth(data, minsup=6)
for x in items:
if len(x) > 1: print x

<fp.node instance at 0x5017ef0>


Null Set 1
play=yes 9
humidity=high 1
windy=true 1
temparature=mild 1
windy=false 6
humidity=high 2
temparature=mild 1
humidity=normal 4
temparature=mild 1
humidity=normal 2
windy=true 2
temparature=mild 1
humidity=high 2
windy=true 2
temparature=mild 1
windy=false 2
humidity=high 2
temparature=mild 1
humidity=normal 1
windy=true 1
Null Set 1
play=yes 6
Null Set 1
play=yes 6
set(['play=yes', 'humidity=normal'])
set(['play=yes', 'windy=false'])

Bulunan sonuçlar iki tane (tek öğeli sonuçlar da var ama onları eledik). Bunlar
hakikaten veri içindeki kalıpları temsil ediyorlar. Fena değil.
Kıyas için BMF üzerinden madencilik yapalım. Önce 1-hot kodlaması yapalım,
ve örnek için bir veri satırını ekrana basalım,

from sklearn.feature_extraction import DictVectorizer


import pandas as pd, re

def one_hot_dataframe(data, cols, replace=False):


vec = DictVectorizer()
mkdict = lambda row: dict((col, row[col]) for col in cols)
tmp = data[cols].apply(mkdict, axis=1)
vecData = pd.DataFrame(vec.fit_transform(tmp).toarray())
vecData.columns = vec.get_feature_names()
vecData.index = data.index
if replace is True:
data = data.drop(cols, axis=1)
data = data.join(vecData)
return (data, vecData, vec)

5
cols = ['outlook','temparature','humidity','windy','play']
df = pd.DataFrame(data,columns=cols)
# kolon ismini veriden cikart, cunku tekrar geri koyulacak
# fpgrowth icin veri icinde olmasi lazim
df = df.applymap(lambda x: re.sub('.*?=','',x))
df2, _, _ = one_hot_dataframe(df, cols, replace=True)
# tek ornek ekrana bas
print df2.ix[0]

humidity=high 1
humidity=normal 0
outlook=overcast 0
outlook=rainy 0
outlook=sunny 1
play=no 1
play=yes 0
temparature=cool 0
temparature=hot 1
temparature=mild 0
windy=false 1
windy=true 0
Name: 0, dtype: float64

Şimdi BMF işletelim, k = 4

import nimfa
import scipy.sparse as sp

def __fact_factor(X):
return X.todense() if sp.isspmatrix(X) else X

fctr = nimfa.mf(np.array(df2).T, seed = "nndsvd",


rank = 4, method = "bmf",
max_iter = 40, initialize_only = True,
lambda_w = 1.1, lambda_h = 1.1)

res = nimfa.mf_run(fctr)

threshold = 0.2
res1 = __fact_factor(res.basis())
res2 = __fact_factor(res.coef())
res1 = np.abs(np.round(res1 - 0.5 + threshold))
res2= np.abs(np.round(res2 - 0.5 + threshold))
res1 = pd.DataFrame(res1,index=df2.columns)
print res1

0 1 2 3
humidity=high 1 0 0 1
humidity=normal 0 1 0 0
outlook=overcast 0 0 1 0
outlook=rainy 1 0 0 0
outlook=sunny 0 0 0 1
play=no 0 0 0 1
play=yes 0 1 1 0
temparature=cool 0 0 0 0
temparature=hot 0 0 0 0

6
temparature=mild 1 0 0 0
windy=false 0 0 1 0
windy=true 1 0 0 0

Bu sonuçları kategoriksel hale çevirip tekrar ekrana basalım,

for i in range(4):
print np.array(df2.columns)[res1.ix[:,i] == 1]
['humidity=high' 'outlook=rainy' 'temparature=mild' 'windy=true']
['humidity=normal' 'play=yes']
['outlook=overcast' 'play=yes' 'windy=false']
['humidity=high' 'outlook=sunny' 'play=no']

1. sonuç atlanabilir, buradaki “kalabalık” orada bir kalıp olmadığına dair bir
işaret. Ayrıştırma sonucu bu tür kolonlar ortaya çıkabilir, diğer kolonlardaki
kalıplar bütünü temsil etmeye tam yetmemişse, arta kalan her türlü gereklilik
bir yerlere tıkılabiliyor, bu normal. 2. sonuç FPGrowth sonucunda var, güzel. 3.
sonuç ta neredeyse aynı, sadece ek olarak outlook=overcast var. Fakat, 3. sonuç
aslında önemli bir kalıp içeriyor olabilir, yani kalması daha iyi olur.
4. sonuç ise çok önemli bir kalıp ve FPGrowth bunu tamamen kaçırmış!
Sebep FPGrowth’un çözüme lokal olarak erişmeye çalışıyor olması, kıyasla BMF
bütüne (global) bakıyor [3]. Bu ne demektir? Bir ayrıştırmanın ne olduğunu
düşünürsek, bir matrisi oluşturan çarpımı ayrıştırıyoruz ve bu ayrıştırma olduk-
tan sonra iki matris elde ediyoruz. Bu iki matris özgündür (unique). Yani belli bir
ikisel matrisi oluşturan çarpım sadece tek bir şekilde olabilir. Buradan hareketle
diyebiliriz ki bu ayrıştırma bütünü göze alarak yapılmalıdır, sağı, solu tutan ama
köşesi tutmayan bir ayrıştırma olmaz. Bu sebeptendir ki ayrıştırma çözümünden
belli bir kapsayıcılık bekleyebiliriz.
FPGrowth ise olaya yerel bakıyor; ağaç oluştururken değişik bir sıra takip edilirse
mesela değişik ağaçlar ortaya çıkabilir. Ayrıca her önemli ilişki muhakkak özgün
bir dal yapısında olmayabilir. Madencilik algoritması alt dallardan başlar ve
yukarıya doğru çıkar, fakat bu her zaman iyi bir yöntem midir?
Kodlama Notları
Şu kod np.round(num - 0.5 + threshold) kullanımı yuvarlama (rounding) yapıyor,
çünkü Nimfa 1 değeri yerine 0.9, 0.8 gibi değerler üretebiliyor, ayrıca 0.1 gibi
değerler de oluyor. Biz bildiğimiz yuvarlama .5 sonrası üzerini 1 yapmak yerine
belli bir eşik değeri (threshold) üzerinden yuvarlama yaptık. Yani eşik=0.2 ise 0.7
alta yuvarlanır ve 0 olur, 0.9 eşik üstünde olduğu için üste yuvarlanır 1 olur.
BMF için kerte k kullanıcı tarafından seçilmeli, ama bu durum SVD, ya da GMM
ile kümeleme gibi diğer yapay öğrenim metotlarından farklı değildir. Bu oynan-
ması gereken, keşfedilmesi gereken bir değer.
Çok Değişkenli Bernoulli Karışımı Kümelemesi ile İlişkisel Madencilik
Bir diger yaklasim kümeleme üzerinden kural çıkartmak. Örnek veri olarak [7]
yazısındanki Movielens 1M verisini kullanacağız. Ayrıca bu verideki posta kodu

7
(zip) ve meslek (occupation) verisine README’ye ve bir Internet sitesine [4]
danışarak sözel açıklamalarını koyduk. Böylece sonuçları yorumlamak çok daha
kolay olacak.
İlişkilerin keşfi için çok değişkenli Bernoulli modelini kullanacağız, ki [8] yazısında
bu kümeleme yöntemi işlendi. CDBK kullanmak için veriyi 0/1 bazına indirgeyeceğiz
(ki verinin büyük bir kısmı zaten bu durumda) ardından CDBK’yı veriye uydu-
racağız, ve karışım öğeleri θk ’lerin bir nevi “şablon” oluşturması sebebiyle ilişki
keşfini bu şablonlar üzerinden yapmaya uğraşacağız.

import pandas as pd, zipfile


import sys; sys.path.append('../stat_mixbern')
import mixbern

unames = ['user_id', 'gender', 'age', 'occupation', 'zip']


rnames = ['user_id', 'movie_id', 'rating', 'timestamp']
mnames = ['movie_id', 'title', 'genres']
with zipfile.ZipFile('../stat_ratings/ml1m.zip', 'r') as z:
users = pd.read_table(z.open('users.dat'), sep='::', header=None,names=unames)
ratings = pd.read_table(z.open('ratings.dat'), sep='::', header=None,names=rnames)
movies = pd.read_table(z.open('movies.dat'), sep='::', header=None,names=mnames)

occup_map = \
{ 0: "other" or not specified,1: "academic/educator",
2: "artist",3: "clerical/admin",
4: "college/grad student",5: "customer service",
6: "doctor/health care",7: "executive/managerial",
8: "farmer",9: "homemaker",
10: "K-12 student", 11: "lawyer",
12: "programmer",13: "retired",
14: "sales/marketing",15: "scientist",
16: "self-employed",17: "technician/engineer",
18: "tradesman/craftsman",19: "unemployed",
20: "writer"}

zip_map = \
{ 0: 'Northeast', 1: 'NY Area', 2: 'DC', 3: 'Florida', 4: 'Michigan/Ohio',
5: 'North', 6: 'Illinois', 7: 'Texas / Arkansas', 8: 'Nevada / Utah',
9: 'California / Alaska'}

from sklearn.feature_extraction import DictVectorizer


def one_hot_dataframe(data, cols):
vec = DictVectorizer()
mkdict = lambda row: dict((col, row[col]) for col in cols)
tmp = vec.fit_transform(data[cols].to_dict(outtype='records')).toarray()
vecData = pd.DataFrame(tmp)
vecData.columns = vec.get_feature_names()
vecData.index = data.index
data = data.drop(cols, axis=1)
data = data.join(vecData)
return data

df = users.copy()
df['occupation'] = df.apply(lambda x: occup_map[x['occupation']], axis=1)

8
df['zip2'] = users['zip'].map(lambda x: int(str(x)[0]))
df['zip2'] = df.apply(lambda x: zip_map[x['zip2']], axis=1)
df['age2'] = pd.qcut(df['age'],5)
df = one_hot_dataframe(df,['occupation','gender','zip2','age2'])
df = df.drop(['zip','age'],axis=1)
df = df.set_index('user_id')

ZIP kodları altta gösteriliyor

Şimdi hangi film genre’sinin (türünün) kullanıcı tarafından kaç kez alınmış olduğunu
özetleyip kullanıcı verisine bitişik olarak ekleyeceğiz.

genre_iter = (set(x.split('|')) for x in movies.genres)


genres = sorted(set.union(*genre_iter))
dummies = pd.DataFrame(np.zeros((len(movies), len(genres))), columns=genres)
for i, gen in enumerate(movies.genres):
dummies.ix[i, gen.split('|')] = 1
movies_windic = movies.join(dummies.add_prefix('Genre_'))
movies_windic = movies_windic.drop(['title','genres'],axis=1)
joined = ratings.merge(movies_windic, left_on='movie_id',right_on='movie_id')
genres = joined.groupby('user_id').sum()
genres = genres.drop(['movie_id','rating','timestamp'],axis=1)
X = pd.merge(df, genres, left_index=True, right_index=True,how='left')
print X.shape

(6040, 56)

En iyi küme sayısı nedir? Bunun için mümkün tüm küme sayılarını deneriz, AIC
sonuçlarına bakarız, sonuçlar arasından düşüş ardından ilk çıkış olduğu anı en
iyi küme sayısı olarak kullanırız.

iter=40; eps=1e-15; attempts=5


for K in range(5,16):
lR,lPi,lP,lbest,aic = mixbern.EMmixtureBernoulli(X,K,iter,eps,attempts)
print K,aic

5,173126.633281

9
6,172007.606772
7,170285.383519
8,169043.301004
9,168457.12051
10,167463.532805
11,167253.486012
12,166290.598818
13,165764.506989
14,164964.964083
15,164989.85056
16,164321.25051

Sonuçlara göre K = 14 bu çıkış anını yakalar. Bu sayıyla tekrar kümelemeyi


işletelim,

iter=40; eps=1e-15; attempts=5; K=14


lR,lPi,lP,lbest,aic = mixbern.EMmixtureBernoulli(X,K,iter,eps,attempts)
rules = np.exp(lP)

def print_rule(j):
for i,r in enumerate(rules[j]):
if r > 0.5: print X.columns[i], r

Şimdi bazı kuralları ekrana basalım,

print_rule(0)

age2=(25, 35] 1.0


gender=M 1.0
Genre_Action 0.997646429789
Genre_Adventure 0.976908591072
Genre_Animation 0.73312197406
Genre_Children's 0.815806962254
Genre_Comedy 1.0
Genre_Crime 0.888200034236
Genre_Drama 1.0
Genre_Fantasy 0.759168898223
Genre_Film-Noir 0.535819148049
Genre_Horror 0.859145011653
Genre_Musical 0.704293299334
Genre_Mystery 0.735085517947
Genre_Romance 0.999999999621
Genre_Sci-Fi 0.98865549819
Genre_Thriller 1.0
Genre_War 0.948000910806
Genre_Western 0.590038323721

25 ila 35 yaş arasındaki erkekler komedi ve aksiyon çok seviyorlar, en çok beğendiklerinin
arasında en alt sırada Western var. İlginç.

print_rule(1)

age2=(18, 25] 1.0

10
gender=M 1.0
Genre_Action 0.999999916342
Genre_Adventure 0.968035357641
Genre_Animation 0.618607301467
Genre_Children's 0.733114850427
Genre_Comedy 1.0
Genre_Crime 0.895303009556
Genre_Drama 1.0
Genre_Fantasy 0.621607330213
Genre_Horror 0.826409070694
Genre_Mystery 0.667105230382
Genre_Romance 0.962487486107
Genre_Sci-Fi 0.981703990034
Genre_Thriller 0.999998477836
Genre_War 0.884260074733

Daha dar bir yaş aralığı 18-25 yaş grubu, komedi, dram, aksiyon, gerilim var, en
az sevilen filmler bu sefer animasyon.

print_rule(2)

gender=F 1.0
Genre_Action 1.0
Genre_Adventure 0.997753376918
Genre_Animation 0.925605697933
Genre_Children's 0.989223061984
Genre_Comedy 0.999411653044
Genre_Crime 0.978893423529
Genre_Drama 1.0
Genre_Fantasy 0.890898944372
Genre_Film-Noir 0.810452619282
Genre_Horror 0.901607018088
Genre_Musical 0.93690169152
Genre_Mystery 0.949990841295
Genre_Romance 1.0
Genre_Sci-Fi 0.999467975234
Genre_Thriller 0.997148167548
Genre_War 0.987837234705
Genre_Western 0.801075654907

Bayanlar için (yaş grubu yok dikkat), üstte aksiyon var, ama romantik filmler de
en üstte.
Şu da ilginç bir bulgu; meslek kolları ve adres verilerini analize dahil etmiş ol-
mamıza rağmen kümelerin şablonu içinde hiçbiri yok! Demek ki meslekler, adresler
film beğenisinde fark yaratmıyor.
Üstteki analiz müşteri bilgisine müşteri seviyesinde baktı. Eğer işlemsel (trans-
actional) bir analiz yapıyor olsaydık, yaklaşım benzer olacaktı, sadece veri odağı
biraz farklı olurdu; müşterilerin her alışveriş sepetlerine bakılacaktı mesela, bir
sepete koyulan mesela ekmek, çikolata, su, bir diğerine koyulan ekmek, su, biberon
gibi alımlar bir satırda 1 ile işaretli, diğerleri 0 ile işaretli olacaktı, ve kümeleme
algoritması bu çok boyutlu Bernoulli veriye bir uyum yapıp şablonları raporlay-
acaktı.

11
İlginçlik - İstatistiki Ölçüt
Kümeleri uydurduktan sonra bile bu kümelerin içinde hangisinin “daha iyi” olduğunu
bulmak için istatistiki ölçüt kullanmak faydalı olabilir. Hatta birazdan bahsedeceğimiz
teknik aslında her türlü ilişki madenciliği yaklaşımı için faydalı, çünkü hangi
teknik olursa olsun bize verinin belli bir grubunu “önemli” olarak gösterecek.
Ardından biz bu grubu alıp onun ne kadar önemli olduğunun ölçütünü hesaplaya-
bileceğiz.
Teknik şöyle: İstatistiki testlerden [9] yazı bölümünü hatırlarsak, bir ideal dağılım
vardı, ve eldeki verinin bu ideale olan yakınlığını ölçüyorduk. Chi Kare testi
ayrıksal bazda işliyordu, eğer eldeki sürekli fonksiyon bazlı bir dağılım ise onun
ideal hesaplarını kutucuklara bölüştürüyorduk.
İlişkisel madencilikte elde ettiğimiz kural bir vektör içinde 0/1 değerleri olacak.
Yaklaşım şöyle; önce verideki her kolonun tek başına oranını buluruz. Bu oran-
lar her kolon “dağılımının” birbirinden bağımsız farz edildiği “idealize” ortamın
ölçütleri olacaklar. Veri mesela şöyle,

data = [[1,1,0,0,1],
[1,0,0,0,0],
[1,0,0,1,1],
[1,1,0,1,1],
[1,1,1,0,1],
[0,0,1,1,0],
[0,1,1,0,0]
]
data = np.array(data)
sums = data.sum(axis=0)
means = data.mean(axis=0)
print 'toplam', sums
print 'ortalama', means

toplam [5 4 3 3 4]
ortalama [ 0.71428571 0.57142857 0.42857143 0.42857143 0.57142857]

Şimdi bulunan kurallardan birini, diyelim [1,1,0,0,1], ana veride en fazla 1


sayısına tekabül eden kolonunu seçeriz, ve bu kolonun 1 olduğu tüm satırları
bir alt küme olarak toparlarız. Bu alt kümede diyelim 5 tane satır var, ve ku-
ralın diğer ögeleri 1. haricinde 2. ve 5. kolonun da ’1’ değerinde olması. O
zaman, toplam 5 satır için 2. ve sonuncu satırda 5*0.57 ve 5*0.57 tane satır ol-
malı. Sıfır hipotezi bağımsızlık olduğu için bu “beklenen (expected)” sayı. Diğer
yandan gerçek rakamlar var, bu rakamlar alt kümedeki ’1’ değerlerinin toplamı,
ki bu da “görünen (observed)” sayı. Bu iki vektör üzerinden chi kare değerini
hesaplıyoruz [5, sf. 391],

X (Oi − Ei )2
χ2 =
i
Ei

χ2 ’nin serbestlik derecesi 3-1=2 (çünkü kuralda 3 tane kolon var, 1. kolonu alt

12
kümeyi bulmak için kullandık). p-değeri ne kadar yüksek ise kural o kadar ilginç
diyebiliriz.

from scipy.stats.distributions import chi2

def interesting(rule):
idx = (sums*rule).argmax()
subset = data[data[:,idx] == 1]
print subset
print subset[:,rule==1]
obs = subset[:,rule==1].sum(axis=0)
exp = len(subset)*means[rule==1]
print 'gorunen (observed)', obs
print 'beklenen (expected)', exp
chi = np.sum((obs-exp)**2 / exp)
dof = rule.sum()-1
print 1-chi2.cdf(chi,dof)

rule = np.array([1,1,0,0,1])
interesting(rule)
[[1 1 0 0 1]
[1 0 0 0 0]
[1 0 0 1 1]
[1 1 0 1 1]
[1 1 1 0 1]]
[[1 1 1]
[1 0 0]
[1 0 1]
[1 1 1]
[1 1 1]]
gorunen (observed) [5 3 4]
beklenen (expected) [ 3.57142857 2.85714286 2.85714286]
0.595795886519

Bir başka kural deneyelim,

rule = np.array([1,0,0,0,1])
interesting(rule)
[[1 1 0 0 1]
[1 0 0 0 0]
[1 0 0 1 1]
[1 1 0 1 1]
[1 1 1 0 1]]
[[1 1]
[1 0]
[1 1]
[1 1]
[1 1]]
gorunen (observed) [5 4]
beklenen (expected) [ 3.57142857 2.85714286]
0.310494434317

Bu daha az ilginçmiş. Hakikaten de ilk kuralın veriye bakarak daha ilginç olduğunu
söyleyebiliriz.

13
Gösterdiğimiz tekniği film sonuçlarında kullanmadık, bunu ödev olarak okuyu-
cuya bırakıyoruz.
Kaynaklar
[1] Ian H. Witten, Eibe Frank, Mark A. Hall, Data Mining Practical Machine Learn-
ing Tools and Techniques
[2] Harrington, P., Machine Learning in Action
[3] Miettinen, Boolean Matrix Factorizations, http://www.mpi-inf.mpg.de/
˜pmiettin/slides/BooleanMatrixFactorizationsForDataMining_Antwerp_
slides.pdf
[4] Zip boundary, ZIP Code FAQs, http://www.zipboundary.com/zipcode_
faqs.html
[5] Rao, Linear Statistical Inference and Its Applications
[6] Bayramli, Lineer Cebir, Matris Çarpımı, Ders 1
[7] Bayramli, Istatistik, Pivotlama
[8] Bayramli, Istatistik, Çok Değişkenli Bernoulli Karışımı
[9] Bayramli, Istatistik, Pearson Chi Kare Uyum Derecesi Testi

14
Toplu Tavsiye (Collaborative Filtering), Filmler, SVD ile Boyut İndirgeme
Film tavsiye verilerine kullanarak bazı analizler ve tavsiye yaklaşımlarına bakacağız.
Diyelim ki Star Trek (ST) dizisini ne kadar beğendiğini 4 tane kullanıcı sezonlara
göre işaretlemiş. Bu örnek veriyi alttaki gibi gösterelim.

from pandas import *

d = np.array(
[[5, 5, 0, 5],
[5, 0, 3, 4],
[3, 4, 0, 3],
[0, 0, 5, 3],
[5, 4, 4, 5],
[5, 4, 5, 5]])

data = DataFrame (d.T,


columns=['S1','S2','S3','S4','S5','S6'],
index=['Ben','Tom','John','Fred'])
print data
S1 S2 S3 S4 S5 S6
Ben 5 5 3 0 5 5
Tom 5 0 4 0 4 4
John 0 3 0 5 4 5
Fred 5 4 3 3 5 5

Veriye göre Tom, ST dizisinin 3. sezonunu 4 seviyesinde sevmiş. 0 değeri o sezo-


nun seyredilmediğini gösteriyor.
Toplu Tavsiye algoritmaları verideki diğer kişilerin bir ürünü, diziyi, vs. ne kadar
beğendiğinin verisinin diğer ”benzer” kişilere tavsiye olarak sunabilir, ya da on-
dan önce, bir kişinin daha almadığı ürünü, seyretmediği sezonu, dinlemediği
müziği ne kadar beğeneceğini tahmin eder. 2006 yılında yapılan ünlü Netflix
yarışmasının amacı buydu mesela.
Peki benzerliğin kriteri nedir, ve benzerlik nelerin arasında ölçülür?
Benzerlik, ürün seviyesinde, ya da kişi seviyesinde yapılabilir. Eğer ürün se-
viyesinde ise, tek bir ürün için tüm kullanıcıların verdiği nota bakılır. Eğer kul-
lanıcı seviyesinde ise, tek kullanıcının tüm ürünlere verdiği beğeni notları vektörü
kullanılır. 1. sezonu örnek kullanalım,o sezonu beğenen kişilere o sezona benzer
diğer sezonlar tavsiye edilebilir. Kişiden hareketle, mesela John’a benzeyen diğer
kişiler bulunarak onların beğendiği ürünler John’a tavsiye edilebilir.
Ürün ya da kişi bazında olsun, benzerliği hesaplamak için bir benzerlik ölçütü
oluşturmalıyız. Genel olarak bu benzerlik ölçütünün 0 ile 1 arasında değişen bir
sayı olmasını tercih edilir ve tavsiye mantığının geri kalanı bu ölçütü baz ala-
caktır. Elimizde beğeni notlarını taşıyan A, B vektörleri olabilir, ve bu vektörlerin
içinde beğeni notları olacaktır. Vektör içindeki sayıları baz alan benzerlik çeşitleri
şöyledir:
Öklit Benzerliği (Euclidian Similarity)

1
Bu benzerlik 1/(1 + mesafe) olarak hesaplanır. Mesafe karelerin toplamının
karekökü (yani Öklitsel mesafe, ki isim buradan geliyor). Bu yüzden mesafe 0
ise (yani iki ”şey” arasında hiç mesafe yok, birbirlerine çok yakınlar), o zaman
hesap 1 döndürür (mükemmel benzerlik). Mesafe arttıkça bölen büyüdüğü için
benzerlik sıfıra yaklaşır.
Pearson Benzerliği
Bu benzerliğin Öklit’ten farklılığı, sayı büyüklüğüne hassas olmamasıdır. Diye-
lim ki birisi her sezonu 1 ile beğenmiş, diğeri 5 ile beğenmiş, bu iki vektörün
Pearson benzerliğine göre birbirine eşit çıkar. Pearson -1 ile +1 arasında bir değer
döndürür, alttaki hesap onu normalize ederek 0 ile 1 arasına çeker.
Kosinüs Benzerliği (Cosine Similarity)
İki vektörü geometrik vektör olarak görür ve bu vektörlerin arasında oluşan açıyı
(daha doğrusu onun kosinüsünü) farklılık ölçütü olarak kullanır.

A·B
cos θ =
||A||||B||

from numpy import linalg as la


def euclid(inA,inB):
return 1.0/(1.0 + la.norm(inA - inB))

def pearson(inA,inB):
if len(inA) < 3 : return 1.0
return 0.5+0.5*np.corrcoef(inA, inB, rowvar = 0)[0][1]

def cos_sim(inA,inB):
num = float(np.dot(inA.T,inB))
denom = la.norm(inA)*la.norm(inB)
return 0.5+0.5*(num/denom)

print np.array(data.ix['Fred'])
print np.array(data.ix['John'])
print np.array(data.ix['Ben'])
print pearson(data.ix['Fred'],data.ix['John'])
print pearson(data.ix['Fred'],data.ix['Ben'])

[5 4 3 3 5 5]
[0 3 0 5 4 5]
[5 5 3 0 5 5]
0.551221949943
0.906922851283

print cos_sim(data.ix['Fred'],data.ix['John'])
print cos_sim(data.ix['Fred'],data.ix['Ben'])

0.898160909799
0.977064220183

2
Şimdi tavsiye mekaniğine gelelim. En basit tavsiye yöntemi, mesela kişi bazlı
olarak, bir kişiye en yakın diğer kişileri bulmak (matrisin tamamına bakarak) ve
onların beğendikleri ürünü istenilen kişiye tavsiye etmek. Benzerlik için üstteki
ölçütlerden birini kullanmak.
Kosinüs Benzerliği ile Tavsiye Örneği
Büyük ölçekte basit kosinüs benzerliği üzerinden tavsiyeleri alttaki gibi hesaplaya-
biliriz. Önce [8]’den en son tam dosyayı indirelim, ve zip dosyasını açalım, base_dir
içinde açılmış olsun. Veride kaç kullanıcı, kaç film olduğu altta raporlandı,

import pandas as pd
base_dir = "/tmp/ml-latest"
ratings = pd.read_csv(base_dir + "/ratings.csv")
print (ratings.userId.nunique(), ratings.movieId.nunique())

283228 53889

Büyük bir veri dosyası bu. Şimdi beğenilerden kullanıcı-film şeklinde olacak
şekilde bir matris yaratacağız. Çoğu kişi çoğu filmi seyretmediği için matris
seyrek olacak, bu sebeple seyrek matris kodu csr_matrix kullanılacak,

from scipy.sparse import csr_matrix


sps = csr_matrix((ratings.rating, (ratings.userId , ratings.movieId)))

Artık sps içinde kullanıcı-film kordinatlarından oluşan bilgiler var. Mesela 1’inci
kullanıcının 307’üncü film beğenisi için

print (sps[1,307])

3.5

Şimdi kendi beğenilerimi bir vektör üzerine kodlamanın zamanı geldi, böylece
bu vektör ile tüm kullanıcı-film matrisi üzerinde bir kosinüs benzerliği hesaplayınca
bizim beğenilere en yakın olan diğer kullanıcıların mesafesini bir diğer vektör
içinde edebiliriz.

mov = pd.read_csv(base_dir + "/movies.csv",index_col="title")['movieId'].to_dict()


picks = {"Swordfish (2001)": 5.0, "Every Which Way But Loose (1978)": 5.0,
"Sideways (2004)": 5.0}
tst = np.zeros((1,sps.shape[1]))
for p in picks: tst[0,mov[p]] = picks[p]

Benzerlik hesabını işletelim,

from sklearn.metrics.pairwise import cosine_similarity


similarities = cosine_similarity(sps, tst)
print (similarities.shape)

(283229, 1)

3
Bu vektörün büyüklüğü verideki kullanıcı sayısı kadar, bu mantıklı.
Artık tavsiye vermek için bu kullanıcılara olan uzaklığa göre yakından-uzağa
şekilde vektörü sıralayacağız, argsort ile sıralama yapınca bize sonuçlar indis
vektörü olarak verilecek (yani en yakın öğenin indisi, indis vektöründe en sonda)
böylece bu vektörü gezip en yakın kullanıcıları bulabiliriz, ve eğer istersek, on-
ların en çok beğendiği filmleri toplayıp bir tavsiye listesi oluşturabiliriz.

m = np.argsort(similarities[:,0])
print (sps[m[-10],:])

(0, 145) 3.5


(0, 805) 4.0
(0, 1061) 4.0
(0, 2013) 3.0
(0, 3173) 4.0
(0, 4344) 4.0

Üstte en yakın 10’uncu kullanıcının beğenilerini görüyoruz. Kodları film ismine


çevirmek için alttakini işletelim, ve filmlerden birine bakalım,

movi = pd.read_csv(base_dir + "/movies.csv",index_col="movieId")['title'].to_dict()


print (movi[145])

Bad Boys (1995)

Bu iyi bir tavsiye; ben beğeni listeme koymamıştım ama filmi biliyorum, ve ak-
siyon filmi olarak güzeldi.
Nihai listeyi oluşturma, tekrarlananları, zaten seyredilmiş olanları filtreleme kod-
larını okuyuculara ödev olsun. Bazı tiyolar seyrek matris, ya da vektör üzerinde
nonzero çağrısı içi dolu öğelerin indisini ve değerini döndürür, bunları kulla-
narak bir nihai tavsiye sonucu oluşturabiliriz.
Not: Üstte hazır cosine_similarity çağrısı kullanıldı, bu kod bazı ek servisler
sunuyor bize, mesela normalize etmek, seyrek matrislerle iş yapabilmek gibi.
Fakat o fonksiyonun kodlamasının detayına baksak daha önce gösterdiğimiz cos_sim
çağrısı ile benzer olduğunu görürdük.
SVD
Eğer boyut azaltma tekniği kullanmak istiyorsak SVD yöntemi burada da işimize
yarar.

A = USV

elde edeceğimiz için, ve S içindeki en büyük değerlere tekabül eden U, V değerleri


sıralanmış olarak geldiği için U, V’nin en baştaki değerlerini almak bize ”en önemli”
blokları verir. Bu en önemli kolon ya da satırları alarak azaltılmış bir boyut
içinde benzerlik hesabı yapmak işlemlerimizi hızlandırır. Bu azaltılmış boyutta
kümeleme algoritmalarını devreye sokabiliriz; U’nun mesela en önemli iki kolonu

4
bize iki boyuttaki sezon kümelerini verebilir, V’nin en önemli iki (en üst) satırı
bize iki boyutta bir kişi kümesi verebilir.
O zaman beğeni matrisi üzerinde SVD uygulayalım,

from numpy.linalg import linalg as la


U,Sigma,V=la.svd(data, full_matrices=False)
print data.shape
print U.shape, Sigma.shape, V.shape
u = U[:,:2]
vt=V[:2,:].T
print 'u', u
print 'vt', vt
print u.shape, vt.shape

(4, 6)
(4, 4) (4,) (4, 6)
u [[-0.57098887 -0.22279713]
[-0.4274751 -0.51723555]
[-0.38459931 0.82462029]
[-0.58593526 0.05319973]]
vt [[-0.44721867 -0.53728743]
[-0.35861531 0.24605053]
[-0.29246336 -0.40329582]
[-0.20779151 0.67004393]
[-0.50993331 0.05969518]
[-0.53164501 0.18870999]]
(4, 2) (6, 2)

degerleri elimize gecer. U ve VT matrisleri

def label_points(d,xx,yy,style):
for label, x, y in zip(d, xx, yy):
plt.annotate(
label,
xy = (x, y), xytext = style,
textcoords = 'offset points', ha = 'right', va = 'bottom',
bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5),
arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))

plt.plot(u[:,0],u[:,1],'r.')
label_points(data.index, u[:, 0], u[:, 1],style=(-10, 30))
plt.plot(vt[:,0],vt[:,1],'b.')
label_points(data.columns, vt[:, 0], vt[:, 1],style=(20, 20))
plt.savefig('svdrecom_1.png')

5
Çok güzel! SVD bize ürün bazında sezon 5 ve 6’nin bir küme oluşturduğunu,
Ben ve Fred’in de kişi bazında ayrı bir küme olduğunu gösterdi.
Azaltılmış boyutları nasıl kullanırız? Yeni bir kişiyi (mesela Bob) ele alınca, bu
kişinin verisini öncelikle aynen diğer verilerin indirgendiği gibi azaltılmış boyuta
”indirgememiz” gerekiyor. Çünkü artık işlem yaptığımız boyut orası. Peki bu
indirgemeyi nasıl yaparız? SVD genel formülünü hatırlarsak,

A = USV

Azaltılmış ortamda

A = Uk Sk Vk

Diyelim ki gitmek istediğimiz nokta azaltılmış U, o zaman Uk ’yi tek başına bırakalım
(dikkat, mesela V’nin tersini aldık, fakat bir matrisin tersini almak için o matrisin
kare matris olması gerekir, eğer kare değilse, ters alma işlemi taklit ters alma
işlemi -pseudoinverse- ile gerçekleştirilir, daha fazla detay için [6])

AVk−1 = Uk SVk Vk−1

Uk , Vk matrisleri birimdik (orthonormal), o zaman Vk−1 Vk = I olacak, yani yoko-


lacak

AVk−1 = Uk S

Benzer şekilde

AVk−1 S−1 = Uk

Çok fazla ters alma işlemi var, her iki tarafın devriğini alalım

6
(S−1 )T (Vk−1 )T AT = UTk

Vk−1 = VkT olduğunu biliyoruz. Nasıl? Çünkü VkT Vk = I, aynı şekilde Vk−1 Vk = I.
Ters alma işleminin özgünlüğü (üniqueness) sebebiyle Vk−1 = VkT olmak zorun-
dadır 2
Demek ki üstteki formül devriğin devriğini almak demektir, yani tekrar başa
dönmüş oluyoruz, demek ki Vk değişmeden kalıyor

(S−1 )T Vk AT = UTk

S ise köşegen matris, onun tersi yine köşegen, köşegen matrisin devriği yine ken-
disi

S−1 Vk AT = UTk

Bazı kod ispatları, u’nun birimdik olması:

print np.dot(u.T,u)

[[ 1.00000000e+00 4.83147593e-18]
[ 4.83147593e-18 1.00000000e+00]]

Doğal olarak 1e-17 gibi bir sayı sıfıra çok yakın, yani sıfır kabul edilebilir. Devrik
ve tersin aynı olduğunu gösterelim: İki matrisi birbirinden çıkartıp, çok küçük
bir sayıdan büyüklüğe göre filtreleme yapalım, ve sonuç içinde bir tane bile True
olup olmadığını kontrol edelim,

print not any(U.T-la.inv(U) > 1e-15)

True

Yeni Bob verisi

bob = np.array([5,5,0,0,0,5])

O zaman

print bob.T.shape
print u.shape
S_k = np.eye(2)*Sigma[:2]
bob_2d = np.dot(np.dot(la.inv(S_k),vt.T),bob.T)
print bob_2d

(6,)
(4, 2)
[-0.37752201 -0.08020351]

7
Not: bob.T üstteki formüldeki AT yerine geçecek; formülü tekrar düzenlerken
A üzerinden işlem yaptık, fakat formülü “A’ya eklenen herhangi bir yeni satır”
olarak ta görebiliriz, ki bu örneğimizde Bob’un verisi olurdu.
Üstte eye ve Sigma ile ufak bir takla attık, bunun sebebi svd çağrısından gelen
Sigma sonucunun bir vektör olması ama üstteki işlem için köşegen bir ”matrise”
ihtiyacımız olması. Eğer birim (identity) matrisini alıp onu Sigma ile çarparsak,
bu köşegen matrisi elde ederiz.
Şimdi mesela kosinüs benzerliği kullanarak bu izdüşümlenmiş yeni vektörün
hangi diğer vektörlere benzediğini bulalım.

for i,user in enumerate(u):


print data.index[i],cos_sim(user,bob_2d)

Ben 0.993397525045
Tom 0.891664622942
John 0.612561691287
Fred 0.977685793579

Sonuca göre yeni kullanıcı Bob, en çok Ben ve Fred’e benziyor. Sonuca eriştik!
Artık bu iki kullanıcının yüksek not verdiği ama Bob’un hiç not vermediği se-
zonları alıp Bob’a tavsiye olarak sunabiliriz.
SVD ile Veriyi Oluşturmak

import pandas as pd
import numpy.linalg as lin
import numpy as np
import scipy.sparse.linalg as lin
import scipy.sparse as sps

d = np.array(
[[ 5., 5., 3., np.nan, 5., 5.],
[ 5., np.nan, 4., np.nan, 4., 4.],
[ np.nan, 3., np.nan, 5., 4., 5.],
[ 5., 4., 3., 3., 5., 5.],
[ 5., 5., np.nan, np.nan, np.nan, 5.]
])
users = ['Ben','Tom','John','Fred','Bob']
seasons = ['0','1','2','3','4','5']
data = pd.DataFrame (d, columns=seasons,index=users)
print data
avg_movies_data = data.mean(axis=0)
print avg_movies_data
data_user_offset = data.apply(lambda x: x-avg_movies_data, axis=1)
A = sps.coo_matrix(np.nan_to_num(np.array(data_user_offset)))
U,S,VT = lin.svds(A,k=3)
def predict(u,i):
offset = np.dot(U[u,:],VT[:,i])
r_ui_hat = offset + avg_movies_data.ix[i]
return r_ui_hat, offset

8
print 'Bob', predict(users.index('Bob'),2)
print 'Tom', predict(users.index('Tom'),1)

0 1 2 3 4 5
Ben 5 5 3 NaN 5 5
Tom 5 NaN 4 NaN 4 4
John NaN 3 NaN 5 4 5
Fred 5 4 3 3 5 5
Bob 5 5 NaN NaN NaN 5
0 5.000000
1 4.250000
2 3.333333
3 4.000000
4 4.500000
5 4.800000
dtype: float64
Bob (3.3115641365499888, -0.021769196783344661)
Tom (4.295419370813935, 0.045419370813934629)

Alternatif Yöntem
Bir diğer yöntem [1] yeni Bob verisi y’yi alıp

z = VV T y

olarak z’ye çevirmek. Bu durumda aslında cebirsel olarak hiçbir şey yapmamış
oluyoruz,

z = VV T y = Iy = y

ve iteratif sayısal çoğu algoritmanın temelini de bu oluşturuyor. Kavramsal olarak


y’yi alıp V uzayına “yansıtıyoruz”. Daha kavramsal olarak kullanıcı seçimlerini
temsil eden veri için V bir “kordinat sistemi” oluşturmuştur (SVD’nin doğal sonucu
olarak) ve her veri noktası bu kordinat sistemi, bu bazın vektörlerinin bir kombi-
nasyonu olarak temsil edilebilir durumdadır (SVD için kullanılan veriden bahsediy-
oruz). Bu durumda yeni veriyi oraya yansıtmak doğal bir işlemdir. Tabii yansıtıp
sonra geri geliyoruz, yani başlangıçtaki boyutlara / hale dönüyoruz, bu olurken
aynı zamanda Bob verisinin boş noktaları en makul tahminlerle “doldurulmuş”
oluyor.

from numpy.linalg import linalg as la


U,Sigma,V=la.svd(data, full_matrices=False)
print data.shape
print U.shape, Sigma.shape, V.shape
u = U[:,:2]
vt=V[:2,:].T
print data
print 'bob', bob
y = bob
for i in range(3):
z = np.dot(vt,np.dot(vt.T,y))

9
print z
z[y>0] = y[y>0]
print z

(4, 6)
(4, 4) (4,) (4, 6)
S1 S2 S3 S4 S5 S6
Ben 5 5 3 0 5 5
Tom 5 0 4 0 4 4
John 0 3 0 5 4 5
Fred 5 4 3 3 5 5
bob [5 5 0 0 0 5]
[ 3.26615993 2.27206826 2.16256132 1.04609626 3.37952362 3.45858088]
[ 3.26615993 2.27206826 2.16256132 1.04609626 3.37952362 3.45858088]
[ 3.26615993 2.27206826 2.16256132 1.04609626 3.37952362 3.45858088]
[ 5. 5. 2.16256132 1.04609626 3.37952362 5. ]

Sonuca göre Bob büyük ihtimalle S5’i sevecektir, not tahminleri arasında en yüksek
puan orada tahmin edilmiş, ki bu daha önceki Ben ve Fred benzerlik tahminleri
ile uyumlu.
Not: Döngüde z’nin hep aynı satır olması kafa karışıklığı yaratmasın, bu çok ufak
bir veri seti, daha büyük veri setlerdinde bu değişim görülecektir.
İteratif işlem sözde kod (pseudocode) olarak,
Algoritma imputed_svd

1. while z’deki değişim azalıncaya kadar (convergence)

2. z = VV T y

3. y’nin ilk halindeki bilinen noktaları alıp z’ye kopyala

En son projemizde üstteki işlemin en iyi sonuçlar verdiğini gözlemledik.


Movielens 1M Verisi
Bu veri seti 6000 kullanıcı tarafından yaklaşık 4000 tane filme verilen not / derece
(rating) verisini içeriyor, 1 milyon tane not verilmiş, yani 4000 * 6000 = 24 milyon
olasılık içinde sadece 1 milyon veri noktası dolu. Bu oldukça seyrek bir matris
demektir.
Verinin ham hali diğer ders notlarımızı içeren üst dizinlerde var, veriyi SVD ile
kullanılır hale getirmek için bu dizindeki movielens_prep.py adlı script kullanılır.
İşlem bitince movielens.csv adlı bir dosya script’te görülen yere yazılacak. Bu
dosyada olmayan derecelendirmeler, verilmemiş notlar boş olacaktır. Bu boşlukları
sıfırlarsak, seyrek matrisi o noktaları atlar. Ardından bu seyrek matris üzerinde
seyrek SVD işletilebilir. Bu normal SVD’den daha hızlı işleyecektir.
Tavsiye kodlamamız için yazının başında anlatılan tekniği kullanacağız, film verisi
üzerinde boyut azaltılması yapılacak, benzer kullanıcı bulunacak, ve herhangi

10
bir yeni kullanıcı / film kombinasyonu için bu diğer benzer kullanıcının o filme
verdiği not baz alınacak.
Veriyi eğitim ve test olarak iki parçaya böleceğiz. SVD eğitim bölümü üzerinde
işletilecek.
Bu bağlamda, önemli bir diğer konu eksik veri noktalarının SVD sonuçlarını nasıl
etkileyeceği. Sonuçta eksik yerler nan, oradan sıfır yapılıp ardından seyrek matris
kodlaması üzerinden ”atlanıyor” olabilir, fakat bu değerler atlanıyor (yani hızlı
işleniyor, depolanıyor) olsa bile, onların sıfır olmasının bir anlamı yok mudur?
Evet vardır. Not bakımından sıfır da bir not’tur, ve bu sebeple sonuçları isten-
meyen biçimde etkileyebilir.
O zaman mevcut veriyi öyle bir değiştirelim ki verilmemiş notlar, yani sıfır değerleri
sonucu fazla değiştirmesin.
Bunu yapmanın yollarından biri her film için bir ortalama not değeri hesaplamak,
ve bu ortalama değeri o filme verilen tüm not değerlerinden çıkartmaktır. Bu
işleme ”sıfır çevresinde merkezlemek” ismi de verilir, hakikaten mesela film j için
ortalama 3 ise, 5 değeri 2, 3 değeri sıfır, 2 değeri -1 haline gelecektir. Bu bir iler-
lemedir çünkü ortalama 3 değeri zaten bizim için ”önemsiz” bir değerdir, tavsiye
problemi bağlamında bizim en çok ilgilendiğimiz sevilen filmler, ve sevilmeyen
filmler. Bu değerler sırasıyla artı ve eksi değerlere dönüşecekler, ve SVD bu
farklılığı matematiksel olarak kullanabilme yeteneğine sahip.
Altta Pandas mean çağrısı ile bu işlemin yapıldığını görüyoruz, dikkat, Pandas
dataframe içinde nan değerleri olacaktır, ve Pandas bu değerleri atlaması gerektiğini
bilir, yani bu değerler ortalamaya etki etmez. Ardından merkezleme işlemi eğitim
verisi üzerinde uygulanıyor.

import pandas as pd, os


import scipy.sparse as sps
df = pd.read_csv("%s/Downloads/movielens.csv" % os.environ['HOME'] ,sep=';')
print df.shape
df = df.ix[:,1:] # id kolonunu atla
df = df.ix[:,:3700] # sadece filmleri al
df_train = df.copy().ix[:5000,:]
df_test = df.copy().ix[5001:,:]
df_train[np.isnan(df_train)] = 0.0
movie_avg_rating = np.array(df_train.mean(axis=0))
df_train = df_train - movie_avg_rating
dfs_train = sps.coo_matrix(df_train)

df_train = np.array(df_train)
df_test = np.array(df_test)

print df_train.shape
print df_test.shape

__top_k__ = 10
import scipy.sparse.linalg as slin
import scipy.linalg as la

11
U,Sigma,V=slin.svds(dfs_train,k=__top_k__)
print U.shape, Sigma.shape, V.shape
Sigma = np.diag(Sigma)
(6040, 3731)
(5001, 3700)
(1039, 3700)
(5001, 10) (10,) (10, 3700)

Altta test verisi üzerinde satır satır ilerliyoruz, ve her satır (test kullanıcısı) içinde
film film ilerliyoruz. ”Verilmiş bir not” arıyoruz (çoğunlukla not verilmemiş
oluyor çünkü), ve bulduğumuz zaman artık elimizde test edebileceğimiz bir şey
var, o notu ”sıfırlayıp” vektörün geri kalanını azaltılmış boyuta yansıtıyoruz,
ve sonra o boyuttaki tüm diğer U vektörleri içinde arama yapıyoruz, en yakın
diğer kullanıcıyı buluyoruz ve onun bu filme verdiği notu tahminimiz olarak
kullanıyoruz.
Altta eğer bulunan diğer kullanıcı o filme not vermemişse, basitleştirme amaçlı
olarak, o filmi atladık. Gerçek dünya şartlarında filme not vermiş ve yakın olan
(en yakın olmasa da) ikinci, üçüncü kullanıcılar bulunup onların notu kullanılabilir.
Hatta en yakın k tane kullanıcının ortalaması alınabilir (o kullanıcılar kNN gibi
bir metotla bulunur belki), vs.

def euclid(inA,inB):
return 1.0/(1.0 + la.norm(inA - inB))

rmse = 0; n = 0
for i,test_row in enumerate(df_test):
for j, test_val in enumerate(test_row):
# nan olmayan bir not buluncaya kadar ara
if np.isnan(test_val): continue
# bulduk, test satirini tamamen kopyala ve bulunan notu silerek
# onu nan / sifir haline getir cunku yansitma (projection) oncesi
# o notu 'bilmiyormus gibi' yapmamiz lazim.
curr = test_row.copy()
curr[j] = np.nan
curr[np.isnan(curr)] = 0.

proj_row = np.dot(np.dot(la.inv(Sigma),V),curr)

sims = np.array(map(lambda x: euclid(x, proj_row), U[:,:__top_k__]))


isim = np.argmax(sims)

# eger bulunan kullanici o filme not vermemisse atla


if np.isnan(df.ix[isim, j]): continue

# egitim verisinde notlar sifir etrafinda ortalanmis, tekrar


# normal haline dondur
est = df_train[isim, j]+movie_avg_rating[j]

# gercek not
real = df_test[i, j]

print i, 'icin en yakin', isim, 'urun',j, 'icin oy', est, 'gercek', real

12
rmse += (real-est)**2
n += 1
break # her kullanici icin tek film test et
if i == 20: break # 20 kullanici test et

print "rmse", np.sqrt(rmse / n)

0 icin en yakin 1903 urun 144 icin oy 5.0 gercek 5.0


1 icin en yakin 239 urun 144 icin oy 5.0 gercek 5.0
2 icin en yakin 2045 urun 844 icin oy 4.0 gercek 4.0
3 icin en yakin 4636 urun 0 icin oy 3.0 gercek 4.0
4 icin en yakin 139 urun 845 icin oy 4.0 gercek 5.0
5 icin en yakin 427 urun 1107 icin oy 4.0 gercek 5.0
6 icin en yakin 3620 urun 31 icin oy 4.0 gercek 4.0
7 icin en yakin 1870 urun 0 icin oy 4.0 gercek 3.0
8 icin en yakin 4816 urun 106 icin oy 5.0 gercek 5.0
9 icin en yakin 3511 urun 0 icin oy 3.0 gercek 4.0
10 icin en yakin 3973 urun 1212 icin oy 5.0 gercek 4.0
11 icin en yakin 2554 urun 287 icin oy 4.0 gercek 5.0
12 icin en yakin 4733 urun 31 icin oy 4.0 gercek 3.0
13 icin en yakin 2339 urun 9 icin oy 4.0 gercek 3.0
14 icin en yakin 3036 urun 10 icin oy 4.0 gercek 3.0
15 icin en yakin 2748 urun 253 icin oy 5.0 gercek 5.0
16 icin en yakin 450 urun 16 icin oy 4.0 gercek 4.0
17 icin en yakin 1133 urun 9 icin oy 5.0 gercek 2.0
18 icin en yakin 3037 urun 253 icin oy 5.0 gercek 4.0
19 icin en yakin 1266 urun 107 icin oy 3.0 gercek 3.0
20 icin en yakin 537 urun 253 icin oy 5.0 gercek 5.0
rmse 0.975900072949

Sonuç fena değil. Tavsiye programlarında RMSE 0.9 civarı iyi olarak bilinir, Net-
flix yarışmasında [3] mesela kazanan algoritma RMSE 0.85’e erişmiştir.
Kaynaklar
[1] Grigorik, SVD Recommendation System in Ruby, http://www.igvita.com/
2007/01/15/svd-recommendation-system-in-ruby
[2] Harrington, P., Machine Learning in Action
[3] Wikipedia, Netflix Prize, http://en.wikipedia.org/wiki/Netflix_Prize
[4] Stack Exchange, How do I use the SVD in collaborative filtering?, http://stats.
stackexchange.com/questions/31096/how-do-i-use-the-svd-in-collaborative
filtering
[5] Anand, MORE ON LINEAR STRUCTURE IN DATA, AND SINGULAR VALUE
DECOMPOSITION, https://anandoka.wordpress.com/tag/imputed-svd
[6] Bayramli, Lineer Cebir, Ders 33
[8] Bayramli, Netflix / Movielens Film Verisi, https://burakbayramli.github.
io/dersblog/sk/2015/04/pandas-movielens-netflix-ratings.html

13
Naive Bayes
Reel sayılar arasında bağlantı kurmak için istatistikte regresyon kullanılır. Eğer
reel değerleri, (mesela) iki kategorik grup arasında seçmek için kullanmak is-
tenirse, bunun için lojistik regresyon gibi teknikler de vardır.
Fakat kategoriler / gruplar ile başka kategorik gruplar arasında bağlantılar ku-
rulmak istenirse, standart istatistik yöntemleri faydalı olamıyor. Bu gibi ihtiyaçlar
için yapay öğrenim (machine learning) dünyasından Naive Bayes gibi tekniklere
bakmamız lazım.
Not: Daha ilerlemeden belirtelim, bu tekniğin ismi Naive Bayes ama bu tanım
tam doğru değil, çünkü NB Olasılık Teorisi’nden bilinen Bayes Teorisini kul-
lanmıyor.
Öncelikle kategorik değerler ile ne demek istediğimizi belirtelim. Reel sayılar
0.3423, 2.4334 gibi değerlerdir, kategorik değerler ile ise mesela bir belge içinde
’a’,’x’ gibi harflerin mevcut olmasıdır. Ya da, bir evin ’beyaz’, ’gri’ renkli olması..
Burada öyle kategorilerden bahsediyoruz ki istesek te onları sayısal bir değere
çeviremiyoruz; kıyasla mesela bir günün ’az sıcak’, ’orta’, ’çok sıcak’ olduğu
verisini kategorik bile olsa regresyon amacıyla sayıya çevirip kullanabilirdik. Az
sıcak = 0, orta = 1, çok sıcak = 2 değerlerini kullanabilirdik, regresyon hala anlamlı
olurdu (çünkü arka planda bu kategoriler aslında sayısal sıcaklık değerlerine
tekabül ediyor olurlardı). Fakat ’beyaz’, ’gri’ değerlere sayı atamanın regresyon
açısından bir anlamı olmazdı, hatta bunu yapmak yanlış olurdu. Eğer elim-
izde fazla sayıda ’gri’ ev verisi olsa, bu durum regresyon sırasında beyaz evlerin
beyazlığını mı azaltacaktır?
İşte bu gibi durumlarda kategorileri olduğu gibi işleyebilen bir teknik gerekiyor.
Bu yazıda kullanacağımız örnek, bir belgenin içindeki kelimelere göre katego-
rize edilmesi. Elimizde iki türlü doküman olacak. Bir tanesi Stephen Hawking
adlı bilim adamının bir kitabından 3 sayfa, diğeri başkan Barack Obama’nın bir
kitabından 3 sayfa. Bu sayfalar ve içindeki kelimeler NB yöntemini ”eğitmek”
için kullanılacak, sonra NB tarafından hiç görülmemiş yeni sayfaları yöntemimize
kategorize ettireceğiz.
Çok Boyutlu Bernoulli ve Kelimeler

Bir doküman ile içindeki kelimeler arasında nasıl bağlantı kuracağız? Burada
olasılık teorisinden Çok Boyutlu Bernoulli (Multivariate Bernoulli) dağılımını kul-
lanacağız. Üstteki resimde görüldüğü gibi her doküman bir xi rasgele değişkeniyle
temsil edilecek. Tek boyutlu Bernoulli değişkeni ’1’ ya da ’0’ değerine sahip ola-
bilir, çok boyutlu olanı ise bir vektör içinde ’1’ ve ’0’ değerlerini taşıyabilir. İşte

1
bu vektörün her hücresi, önceden tanımlı bir kelimeye tekabül edecek, ve bu ke-
limeden bir doküman içinde en az bir tane var ise, o hücre ’1’ değerini taşıyacak,
yoksa ’0’ değerini taşıyacak. Üstteki örnekte 2. kelime ”hello” ve 4. doküman
içinde bu kelimeden en az bir tane var, o zaman x42 = 1. Tek bir dokümanı temsil
eden dağılımı matematiksel olarak şöyle yazabiliriz:

Y
D Y
D
p(x1 , ..., xD ) = p(xd ) = αxdd (1 − αd )1−xd
d=1 d=1

Bu formülde her d boyutu bir tek boyutlu Bernoulli, ve bir doküman için tüm bu
boyutların ortak (joint) dağılımı gerekiyor, çarpımın sebebi bu. Formüldeki αd
bir dağılımı ”tanımlayan” değer, α bir vektör, ve unutmayalım, her ”sınıf” için
NB ayrı ayrı eğitilecek, ve her sınıf için farklı α vektörü olacak. Yani Obama’nın
kitapları için α2 = 0.8 olabilir, Hawking kitabı için α2 = 0.3 olabilir. Birinin
kitabında ”hello” kelimesi olma şansı fazla, diğerinde pek yok. O zaman NB’yi
”eğitmek” ne demektir? Eğitmek her sınıf için yukarıdaki α değerlerini bulmak
demektir.
Bunun için istatistikteki ”olurluk (likelihood)” kavramını kullanmak yeterli. Olurluk,
bir dağılımdan geldiği farzedilen bir veri setini alır, tüm veri noktalarını teker
teker olasılığa geçerek olasılık değerlerini birbirine çarpar. Sonuç ne kadar yüksek
çıkarsa, bu verinin o dağılımdan gelme olasılığı o kadar yüksek demektir. Bizim
problemimiz için tek bir sınıfın olurluğu, o sınıf içindeki tüm (N tane) belgeyi
kapsamalıdır, tek bir ”veri noktası” tek bir belgedir, o zaman:

Y
N Y
D Y
N Y
D
xi i
L(θ) = p(xid ) = αdd (1 − αd )1−xd
i=1 d=1 i=1 d=1

θ bir dağılımı tanımlayan her türlü değişken anlamında kullanıldı, bu örnekte


içinde sadece α var.
Devam edelim: Eğer α’nin ne olduğunu bilmiyorsak (ki bilmiyoruz -eğitmek za-
ten bu demek-) o zaman maksimum olurluk (maximum likelihood) kavramını
resme dahil etmek gerekli. Bunun için üstteki olurluk formülünün α’ya göre
türevini alıp sıfıra eşitlersek, bu formülden bir maksimum noktasındaki α elim-
ize geçecektir. İşte bu α bizim aradığımız değer. Veriyi en iyi temsil eden α değeri
bu demektir. Onu bulunca eğitim tamamlanır.
Türev almadan önce iki tarafın log’unu alalım, böylece çarpımlar toplamlara dönüşecek
ve türevin formülün içine nüfuz etmesi daha kolay olacak.

X
N X
D
log(L) = xid log(αd ) + (1 − xid ) log(1 − αd )
i=1 d=1

Türevi alalım:

2
dlog(L) X
N
xid 1 − xid
 
= − =0
dαd i=1
αd 1 − αd

1- αd ’ye göre türev alırken xid ’ler sabit sayı gibi muamele görürler. 2- log’un
türevi alırken log içindeki değerlerin türev alınmış hali bölümün üstüne, ken-
disini olduğu gibi bölüm altına alınır, örnek dlog(−x)/dx = −1/x olur üstteki
eksi işaretinin sebebi bu.
P
Peki D d=1 nereye gitti? Türevi αd ’ye göre alıyoruz ve o türevi alırken tek bir αd
ile ilgileniyoruz, mesela α22 , bunun haricindeki diğer tüm α? değerleri türev alma
P
işlemi sırasında sabit kabul edilirler, türev sırasında sıfırlanırlar. Bu sebeple D d=1
içinde sadece bizim ilgilendiğimiz αd geriye kalır. Tabii ki bu aynı zamanda her
d = 1, 2, ..D, αd için ayrı bir türev var demektir, ama bu türevlerin hepsi birbirine
benzerler, yani tek bir αd ’yi çözmek, hepsini çözmek anlamına gelir.
Devam edelim:

X
N  i
x 1 − xid

Nd N − N d
d
− = − =0
i=1
αd 1 − αd αd 1 − αd

PN
i=1 xid = Nd olarak kabul ediyoruz, Nd tüm veri içinde d boyutu (kelimesi)
’1’ kaç tane hücre olduğunu bize söyler. xid ya ’1’ ya ’0’ olabildiğine göre bir d
için, tüm N hücrenin toplamı otomatik olarak bize kaç tane ’1’ olduğunu söyler.
Sonra:

Nd N − Nd
− =0
αd 1 − αd

1 − αd N − Nd
=
αd Nd

1 N
−1= −1
αd Nd

1 N
=
αd Nd

Nd
αd =
N
Python Kodu
αd ’nin formülünü buldumuza göre artık kodu yazabiliriz. İlk önce bir dokümanı
temsil eden çok boyutlu Bernoulli vektörünü ortaya çıkartmamız lazım. Bu vektörün
her hücresi belli bir kelime olacak, ve o kelimelerin ne olduğunu önceden kararlaştırmamız

3
lazım. Bunun için her sınıftaki tüm dokümanlardaki tüm kelimeleri içeren bir
sözlük yaratırız:

import re
import math

words = {}

# find all words in all files, creating a


# global dictionary.
base = './data/'
for file in ['a1.txt','a2.txt','a3.txt',
'b1.txt','b2.txt','b3.txt']:
f = open (base + file)
s = f.read()
tokens = re.split('\W+', s)
for x in tokens: words[x] = 0.

hawking_alphas = words.copy()
for file in ['a1.txt','a2.txt','a3.txt']:
words_hawking = set()
f = open (base + file)
s = f.read()
tokens = re.split('\W+', s)
for x in tokens:
words_hawking.add(x)
for x in words_hawking:
hawking_alphas[x] += 1.

obama_alphas = words.copy()
for file in ['b1.txt','b2.txt','b3.txt']:
words_obama = set()
f = open (base + file)
s = f.read()
tokens = re.split('\W+', s)
for x in tokens:
words_obama.add(x)
for x in words_obama:
obama_alphas[x] += 1.

for x in hawking_alphas.keys():
hawking_alphas[x] = hawking_alphas[x] / 3.
for x in obama_alphas.keys():
obama_alphas[x] = obama_alphas[x] / 3.

def prob(xd, alpha):


return math.log(alpha*xd + 1e-10) + \
math.log((1.-alpha)*(1.-xd) + 1e-10)

def test(file):
test_vector = words.copy()
words_test = set()
f = open (base + file)
s = f.read()
tokens = re.split('\W+', s)

4
for x in tokens:
words_test.add(x)
for x in words_test:
test_vector[x] = 1.
ob = 0.
ha = 0.
for x in test_vector.keys():
if x in obama_alphas:
ob += prob(test_vector[x], obama_alphas[x])
if x in hawking_alphas:
ha += prob(test_vector[x], hawking_alphas[x])

print "obama", ob, "hawking", ha, \


"obama", ob > ha, "hawking", ha > ob

print "hawking test"


test('a4.txt')
print "hawking test"
test('a5.txt')
print "obama test"
test('b4.txt')
print "obama test"
test('b5.txt')

hawking test
obama -34048.7734496 hawking -32192.3692113 obama False hawking True
hawking test
obama -33027.3182425 hawking -32295.7149639 obama False hawking True
obama test
obama -32531.9918709 hawking -32925.037558 obama True hawking False
obama test
obama -32205.4710748 hawking -32549.6924713 obama True hawking False

Test için yeni dokümanı kelimelerine ayırıyoruz, ve her kelimeye tekabül eden
alpha vektörlerini kullanarak bir yazar için toplam olasılığı hesaplıyoruz. Nasıl?
Her kelimeyi αxdd (1 − αd )1−xd formülüne soruyoruz, yeni dokümanı temsilen
elimizde bir [1, 0, 0, 1, 0, 0, ..., 1] şeklinde bir vektör olduğunu farz ediyoruz, buna
göre mesela x1 = 1, x2 = 0. Eğer bir d kelimesi yeni belgede ”var” ise o kelime
için xd = 1 ve bu durumda αxdd = α1d = αd haline gelir, ama formülün öteki tarafı
yokolur, (1 − αd )1−xd = (1 − αd )0 = 1, o zaman αd · 1 = αd .
Çarpım diyoruz ama biz aslında sınıflama sırasında αxdd (1 − αd )1−xd çarpımı yer-
ine yine log() numarasını kullandık; çünkü olasılık değerleri hep 1’e eşit ya da
ondan küçük sayılardır, ve bu küçük değerlerin birbiriyle sürekli çarpımı nihai
sonucu aşırı fazla küçültür. Aşırı ufak değerlerle uğraşmamak için olasılıkların
log’unu alıp birbirleri ile toplamayı seçtik, yani hesapladığımız değer xd ·log(αd )+
(1 − xd ) · log(1 − αd )
Fonksiyon prob içindeki 1e-7 kullanımı neden? Bu kullanım log numarasını ya-
pabilmek için – sıfır değerinin log değeri tanımsızdır, bir kelime olmadığı za-
man log’a sıfır geleceği için hata olmaması için log içindeki değerlere her se-
ferinde yeterince küçük bir sayı ekliyoruz, böylece pür sıfırla uğraşmak zorunda

5
kalmıyoruz. Sıfır olmadığı zamanlarda çok eklenen çok küçük bir sayı sonuçta
büyük farklar (hatalar) yaratmıyor.
Toparlarsak, yeni belge a4.txt için iki tür alpha değerleri kullanarak iki farklı
log toplamını hesaplatıyoruz. Bu iki toplamı birbiri ile karşılaştırıyoruz, hangi
toplam daha büyükse, dokümanın o yazardan gelmesi daha olasıdır, ve o seçimimiz
o yazar olur.
Kaynaklar
[1] Jebara, T., Columbia U. COMS 4771 Machine Learning Lecture Notes, Lecture 7

6
Kalıcı CD (Persistent Contrastive Divergence -PCD-)
Kısıtlı Boltzman Makinaları (RBM) yazısında gösterilen eğitim CD (contrastive
divergence) üzerinden idi. Amaç alttaki formülde, özellikle eksiden sonraki ter-
imi yaklaşıksal olarak hesaplamaktır.

X
N
< yi yj >P(h|xn ;W) − < yi yj >P(x,h;W)
n=1

Bu terime basında eksi olduğu için negatif parçacıklar (negatıve partıcles) ismi
de veriliyor.
Şimdi RBM’de gördüğümüz CD’yi hatırlayalım, CD bir tür “tek adımlık Gibbs
örneklemesi” yapıyordu; bu tek adım örnekleme sonrasında bir sonraki adım
öncesi, veri, tekrar başlangıç noktası olarak zincire veriliyordu. Yani her CD
adımının başlangıcı illa ki verinin kendisi olacaktır. Bu usul Gibbs’in veriden
uzaklaşma şansı çok azdır. Fakat çoğu ilginç yapay öğrenim verisi çok doruk-
ludur (multimodal), optimizasyon bağlamında düşünülürse birden fazla tepe (ya
da çukur) noktası içerir. Eğer eldeki veri, eğitimi bu noktalara yeterince kanal-
ize edemiyorsa o noktalar öğrenilmemiş olur. Bazen verinin (bile) söylediğinden
değişik yönleri gezebilen bir prosedür bu çokdoruklu alanı gezmesi açısından
daha başarılı olabilecektir.
PCD bu eksikleri düzeltmeye çabalar. PCD’ye göre modelden gelen “negatif
parçacıkların” örneklemesi arka planda, kendi başlarına ilerler, ve bu zincir hiçbir
zaman veriye, ya da başka bir şeye set edilmez (hatta zincirin başlangıç nok-
tası bile veriden alakasız olarak, rasgele seçilir). Bu yönteme göre h0 , x0 , h1 , x1 , ...
üretimi neredeyse tamamen “kapalı devre” kendi kendine ilerleyen bir süreç ola-
caktır. Diğer yanda pozitif parçacıklar veriden geliyor (ve tabii ki her gradyan
adımı sonrası değişen W hem pozitif hem negatif parçacıkları etkiler), ve bu
al/ver ilişkisi, hatta bir bakıma model ile verinin kapışmasının PCD’yi daha avan-
tajlı hale getirdiği iddia edilir, ki PCD, CD’den genellikle daha iyi öğrenim sağlar
[5].
CD’ye kıyasla PCD’nin Gibbs ya da genel olarak MCMC örneklemesinin pren-
sibine daha yakın durduğu iddia edilebilir, çünkü PCD ile bir örneklem zinciri
kesintisiz olarak devam ettirilir.

from sklearn.utils import gen_even_slices


import numpy as np
import itertools

class RBM:
def __init__(self, num_hidden, num_visible, learning_rate,max_epochs=10,
batch_size=10):
self.num_hidden = num_hidden
self.num_visible = num_visible
self.learning_rate = learning_rate
self.weights = 0.1 * np.random.randn(self.num_visible, self.num_hidden)

1
self.weights = np.insert(self.weights, 0, 0, axis = 0)
self.weights = np.insert(self.weights, 0, 0, axis = 1)
self.max_epochs = max_epochs
self.batch_size = batch_size

def run_visible(self, data):


num_examples = data.shape[0]

hidden_states = np.ones((num_examples, self.num_hidden + 1))

data = np.insert(data, 0, 1, axis = 1)

hidden_activations = np.dot(data, self.weights)


hidden_probs = self._logistic(hidden_activations)
hidden_states[:,:] = hidden_probs > \
np.random.rand(num_examples, self.num_hidden + 1)
hidden_states = hidden_states[:,1:]
return hidden_states

def run_hidden(self, data):


num_examples = data.shape[0]

visible_states = np.ones((num_examples, self.num_visible + 1))

data = np.insert(data, 0, 1, axis = 1)

visible_activations = np.dot(data, self.weights.T)


visible_probs = self._logistic(visible_activations)
visible_states[:,:] = visible_probs > \
np.random.rand(num_examples, self.num_visible + 1)

visible_states = visible_states[:,1:]
return visible_states

def _logistic(self, x):


return 1.0 / (1 + np.exp(-x))

def _fit(self, v_pos):


h_pos = self.run_visible(v_pos)
v_neg = self.run_hidden(self.h_samples_)
h_neg = self.run_visible(v_neg)
lr = float(self.learning_rate) / v_pos.shape[0]
v_pos = np.insert(v_pos, 0, 1, axis = 1)
h_pos = np.insert(h_pos, 0, 1, axis = 1)
v_neg = np.insert(v_neg, 0, 1, axis = 1)
h_neg = np.insert(h_neg, 0, 1, axis = 1)
update = np.dot(v_pos.T, h_pos).T
update -= np.dot(h_neg.T, v_neg)
self.weights += lr * update.T
h_neg[np.random.rand(h_neg.shape[0], h_neg.shape[1]) < h_neg] = 1.0
self.h_samples_ = np.floor(h_neg, h_neg)[:,1:]

def fit(self, data):


num_examples = data.shape[0]

2
self.h_samples_ = np.zeros((self.batch_size, self.num_hidden))
n_batches = int(np.ceil(float(num_examples) / self.batch_size))
batch_slices = list(gen_even_slices(n_batches * self.batch_size,
n_batches, num_examples))

for iteration in xrange(1, self.max_epochs + 1):


for batch_slice in batch_slices:
self._fit(data[batch_slice])

if __name__ == "__main__":
import numpy as np
X = np.array([[0, 0, 0], [0, 1, 1], [1, 0, 1], [1, 1, 1]])
model = RBM(num_hidden=2, num_visible=3, learning_rate=0.1,batch_size=2)
model.fit(X)
print model.weights

Üstte görülen kod daha önce RBM için kullanılan kodla benzeşiyor, sadece fit
değişik, ve _fit eklendi. Bu kodda miniparça (minibatch) kavramı da var, her
gradyan adımı ufak verinin mini parçaları üzerinden atılır. Bu parçalar hakikaten
ufak, mesela 10 ila 100 satırlık veri arasındadırlar ve bu ilginç bir durumu ortaya
çıkartır, özellikle negatif parçacıklar için, ki bu parçacıklar W bağlantısı haricinde
kendi başlarına ilerler, çok az veri noktası ile işlem yapabilmektedirler.
Metot fit içinde self.h_samples_ değişkenine dikkat, bu değişken PCD’nin “kalıcı”
olmasını sağlar, her _fit çağrı sonrası negatif parçacık örneklemesi self.h_samples_
’in bıraktığı yerden başlar.
RBM için kullandığımız aynı veri seti üzerine k-katlama ile test edelim,

from sklearn.linear_model import LogisticRegression


from sklearn.cross_validation import KFold
import numpy as np, rbmp, sys

X = np.loadtxt('../../stat/stat_mixbern/binarydigits.txt')
Y = np.ravel(np.loadtxt('../../stat/stat_mixbern/bindigitlabels.txt'))

np.random.seed(0)

scores = []
cv = KFold(n=len(X),n_folds=3)
for train, test in cv:
X_train, Y_train = X[train], Y[train]
X_test, Y_test = X[test], Y[test]
r = rbmp.RBM(num_hidden=40, learning_rate=0.1, max_epochs=100,
num_visible=64, batch_size=10)
r.fit(X_train)
clf = LogisticRegression(C=1000)
clf.fit(r.run_visible(X_train), Y_train)
res3 = clf.predict(r.run_visible(X_test))
scores.append(np.sum(res3==Y_test) / float(len(Y_test)))

print np.mean(scores)

! python test_rbmkfold.py

3
0.989898989899

Daha çetrefil bir veri seti MNIST veri setine [2] bakalım. Veri 28x28 boyutunda
ikisel veri olarak kodlanmış rakamların el yazısından alınmış resimlerini içerir.
Veri seti ünlü çünkü Derin Öğrenim’in ilk büyük başarıları bu veri seti üzerinde
paylaşıldı. MNIST’i aldıktan sonra eğitim / test kısımlarının ilk 1000 tanesi üzerinde
algoritmamızı kullanırsak, tek komşulu KNN (yani 1-NN) yüzde 85.4 başarı sonu-
cunu verir. Alttaki parametreler üzerinden PCD ile RBM’in başarısı yüzde 86
olacaktır.

import numpy as np, gzip, sys


from sklearn import neighbors
from sklearn.cross_validation import train_test_split
from sklearn.linear_model import LogisticRegression

np.random.seed(0)
S = 1000

f = gzip.open('/tmp/mnist.pkl.gz', 'rb')
train_set, valid_set, test_set = cPickle.load(f)
f.close()

X_train,y_train = train_set
X_test,y_test = valid_set
X_train = X_train[:S]; y_train = y_train[:S]
X_test = X_test[:S]; y_test = y_test[:S]
print X_train.shape

clf = neighbors.KNeighborsClassifier(n_neighbors=1)
clf.fit(X_train, y_train)
print 'KNN', clf.score(X_test, y_test)

import rbmp
r = rbmp.RBM(num_hidden=500, learning_rate=0.1, max_epochs=200,
num_visible=784,batch_size=20)
r.fit(X_train)
clf = LogisticRegression(C=1000)
clf.fit(r.run_visible(X_train), y_train)
res3 = clf.predict(r.run_visible(X_test))
print 'RBM', np.sum(res3==y_test) / float(len(y_test))

Kaynaklar
[1] Tieleman, Using Fast Weights to Improve Persistent Contrastive Divergence,http:
//videolectures.net/icml09_tieleman_ufw/
[2] Montreal Institute for Learning Algorithms, MNIST Data, http://www.iro.
umontreal.ca/˜lisa/deep/data/mnist/mnist.pkl.gz
[3] Bengio, Y., Learning Deep Architectures for AI
[4] Larochelle, H., Neural networks [5.6] : Restricted Boltzmann machine - persistent
CD, https://www.youtube.com/watch?v=S0kFFiHzR8M

4
[5] Murphy, K. Machine Learning A Probabilistic Perspective

5
Boltzman Makinaları (Rasgele Hopfield Ağları)
Alttaki ifade bir Boltmann dağılımını gösterir,
 
1 1 T
P(x; W) = exp x Wx (3)
Z(W) 2

ki x çok boyutlu ve -1,+1 değerleri içeren bir vektör, W simetrik ve çaprazında


(diagonal) sıfır içeren bir matristir, n × d boyutlarındaki bir veri için d × d boyut-
larında olacaktır. Boltzmann Makinaları (BM), Kısıtlı Boltzmann Makinaları (Re-
stricted Boltzmann Machines) kavramına geçiş yapmadan önce iyi bir durak nok-
tası.
BM W içinde aslında tüm değişkenlerin ikisel ilişkisini içerir. W çok değişkenli
Gaussian dağılımındaki Σ’da olduğu gibi ikisel bağlantıları saptar. Veriden W’yu
öğrenmek için olurluğu hesaplamak lazım. Olurluk (likelihood)

Y
N
1

1 (n)T

(n) (n)
P(x ; W) = exp x Wx
n=1
Z(W) 2

Log olurluk

Y
N X
N 
1

(n)T
L = ln (n) (n)

P(x ; W) = x Wx − ln Z(W) (1)
n=1 n=1
2

∂L
Birazdan ∂w ij
türevini alacağız, o sırada ln Z(W)’nin türevi lazım, daha doğrusu
Z(W)’yi nasıl türevi alınır hale getiririz?
Z(W) normalizasyon sabiti olduğuna göre, dağılımın geri kalanının sonsuzlar
üzerinden entegrali (ya da toplamı) normalizasyon sabitine eşittir,

X 1
 
Z(W) = exp xT Wx
x
2
X 
1 T 
ln Z(W) = ln exp x Wx
x
2

Log bazlı türev alınca log içindeki herşey olduğu gibi bölüme gider, ve log içindekinin
türevi alınırak bölüme koyulur. Fakat log içine dikkatli bakarsak bu zaten Z(W)’nin
tanımıdır, böylece denklemi temizleme şansı doğdu, bölüme hemen Z(W) deriz,
ve türevi log’un içine uygularız,
X 
∂ 1 ∂ 1 T 
ln Z(W) = exp x Wx
∂wij Z(W) x ∂wij 2

1
∂ 1  1 1  ∂ T
exp xT Wx = exp xT Wx x Wx (2)
∂wij 2 2 2 ∂wij

(2)’in içindeki bölümü açalım,

∂ T
x Wx = xi xj
∂wij

Şimdi (2)’ye geri koyalım,

1 1
exp xT Wx xi xj

=
2 2
X 
∂ 1 1 1 T 
ln Z(W) = exp x Wx xi xj
∂wij Z(W) x 2 2

1X 1 1
exp xT Wx xi xj

=
2 x Z(W) 2

1X
= P(x; W)xi xj
2 x

Üstteki son ifadede bir kısaltma kullanalım,

X
P(x; W)xi xj =< xi , xj >P(x;W) (4)
x

Artık ln Z(W)’nin türevini biliyoruz. O zaman tüm log olurluğun türevine (1)
dönebiliriz,

∂L X
N 
∂ 1 (n)T ∂

(n)
= x Wx − ln Z(W)
∂wij n=1 ∂wij 2 ∂wij

X
N 
1 (n)T (n) ∂

= xi xj − ln Z(W)
n=1
2 ∂wij

X
N 
1 (n)T (n) 1

= xi xj − < xi xj >P(x;W)
n=1
2 2

1/2 sabitlerini atalım,

2
X
N 
(n)T (n)

= xi xj − < xi xj >P(x;W)
n=1

Eğer

1 X (n)T (n)
N
< xi xj >Data = x xj
N n=1 i

olarak alırsak, eşitliğin sağ tarafı verisel kovaryansı (empirical covariance) temsil
eder. Düzenleyince,

X
N
(n)T (n)
N· < xi xj >Data = xi xj
n=1

şimdi eşitliğin sağ tarafı üç üstteki formüle geri koyulabilir,

∂L  
= N < xi xj >Data − < xi xj >P(x;W)
∂wij

Her ne kadar N veri noktası sayısını gösteriyor olsa da, üstteki ifade bir gradyan
güncelleme formülü olarak ta görülebilir, ve N yerine bir güncelleme sabiti alınabilir.
Gradyan güncelleme olarak görülebilir çünkü wij ’ye göre türev aldık, o zaman
bizi L’in minimumuna götürecek w adımları üstte görüldüğü gibidir.
(4)’te görülen < xi xj >P(x;W) ’in anlamı nedir? Bu ifade mümkün tüm x değerleri
üzerinden alınıyor ve ikisel ilişkilerin olasılığını “mevcut modele” göre hesaplıyor.
Yani bu ifade de bir korelasyon hesabıdır, sadece veriye göre değil, tüm mümkün
değerler ve model üzerinden alınır. Bu hesabı yapmak oldukça zordur, fakat
yaklaşıksal olarak Monte Carlo yöntemi ile hesaplanabilir. Nihayet MC ve MCMC
metotlarının kullanılma sebebini görmeye başlıyoruz; bu metotlar zaten aşırı yüksek
boyutlu, analitik çözümü olmayan, hesaplanamaz (intractable) entegraller (ya da
toplamlar) için keşfedilmiştir.
Yani bu ifadeyi hesaplamak için Monte Carlo simulasyonu kullanacağız. Tüm
değerleri teker teker ziyaret etmek yerine (ki bu çok uzun zaman alırdı) mev-
cut modele en olası x değerleri “ürettireceğiz”, ve bu değerleri alıp sanki gerçek
veriymiş gibi sayısal korelasyonlarını hesaplayacağız. Eğer veriler dağılımın en
olası noktalarından geliyorlarsa, elimizde veri dağılımı “iyi” temsil eden bir veri
setidir. Daha sonra bu korelasyon hesabını değeri gerçek veri korelasyonunun-
dan çıkartıp bir sabit üzerinden gradyan adımı atmamız mümkün olacak.
Gibbs Örneklemesi (Sampling)
Gibbs örneklemesinin detayları için [5]. Bolzmann dağılımından örneklem al-
mak için bize tek bir değişken (hücre) haricinde diğer hepsinin bilindiği durumun

3
olasılık hesabı lazım, yani koşulsal olasılık P(xi = 1|xj , j 6= i). Yani x üzerinde, biri
hariç tüm öğelerin bilindiği durumda bilinmeyen tek hücre i’nin 1 olma olasılık
değeri,

1
P(xi = 1|xj , j 6= i) =
1 + e−ai
ve,

X
ai = wij xj
j

Bu koşulsal olasılığın temiz / basit bir formül olması önemli, üstteki görülen
bir sigmoid fonksiyonu bu türden bir fonksiyondur... Bu fonksiyonlar hakkında
daha fazla bilgi [6] yazısında bulunabilir.
Ama, ana formül (3)’ten bu noktaya nasıl eriştik? Bu noktada biraz türetme yap-
mak lazım. x vektörü içinde sadece xi öğesinin b olmasını xb olarak alalım. Önce
koşulsal dağılımda “verili” olan kısmı elde etmek lazım. O uzaman

P(xj , j 6= i) = P(x0 ) + P(x1 )

Bu bir marjinalizasyon ifadesi, tüm olası i değerleri üzerinde bir toplam alınca
geri kalan j değerlerinin dağılımını elde etmiş oluruz.

P(x1 )
P(xi = 1|xj , j 6= i) =
P(x0 ) + P(x1 )

çünkü P(A|B) = P(A, B)/P(B) bilindiği gibi, ve P(x1 ) içinde x1 = 1 setini içeren
tüm veriler üzerinden.
Eşitliğin sağ tarafında P(x1 )’i bölen olarak görmek daha iyi, ayrıca ulaşmak istediğimiz
1/1 + e−ai ifadesinde +1’den kurtulmak iyi olur, böylece sadece e−ai olan eşitliği
ispatlarız. Bunun her iki denklemde ters çevirip 1 çıkartabiliriz,

P(x0 ) + P(x1 )
1/P(xi = 1|xj , j 6= i) =
P(x1 )

P(x0 )
=1+
P(x1 )

P(x0 )
Bir çıkartırsak, P(x1 )
kalır. Bu bize ulaşmak istediğimiz denklemde e−ai ibaresini
P(x0 )
bırakır. Artık sadece P(x1 )
’in e−ai ’e eşit olduğunu göstermek yeterli.

4
P(x0 ) T T

1
= exp(x0 Wx0 − x1 Wx1 )
P(x )

Şimdi xT Wx gibi bir ifadeyi indisler bazında açmak için şunları yapalım,

X
xT Wx = xk xj wkj
k,j

Üstteki çok iyi bilinen bir açılım. Eğer

X X
x xj wij = Ykj
| k {z }
k,j Ykj k,j

alırsak birazdan yapacağımız işlemler daha iyi görülebilir. Mesela k = i olan


durumu dış toplamdan dışarı çekebiliriz

XX X
= Ykj + Yij
k6=i j j

Daha sonra j = i olan durumu iç toplamdan dışarı çekebiliriz,

XX X
= ( Ykj + Yki ) + Yij
k6=i j6=i j

İç dış toplamları birleştirelim,

X X X
= Ykj + Yki + Yij
k6=i,j6=i k6=i j

X X X
= Ykj + Yki + Yij + Yii
k6=i,j6=i k j

T T
Üstteki ifadeyi exp(x0 Wx0 − x1 Wx1 ) için kullanırsak,

X X X X
0 0 0 1 1 1

exp Yki + Yij + Yii −( Yki + Yij + Yii )
k j k j

P
Ykj teriminin nereye gittiği merak edilirse, bu ifade i’ye dayanmadığı
k6=i,j6=i
için bir eksi bir artı olarak iki defa dahil edilip iptal olacaktı.

X X
1 1 1

= exp 0 − ( Yki + Yij + Yii )
k j

5
P 1
P 1
W’nin simetrik matris olduğunu düşünürsek, k Yki ile j Yij aynı ifadedir,

X
1 1

= exp − (2 Yij + Yii )
j

1
W sıfır çaprazlı bir matristir, o zaman Yii = 0,

X
1

= exp 2 Yij = exp(−2ai )
j

Orijinal dağılım denkleminde 1/2 ifadesi vardı, onu başta işlemlere dahil etmemiştik,
edilseydi sonuç exp(−ai ) olacaktı.

import numpy as np

class Boltzmann:

def __init__(self,n_iter=100,eta=0.1,sample_size=100,init_sample_size=10):
self.n_iter = n_iter
self.eta = eta
self.sample_size = sample_size
self.init_sample_size = init_sample_size

def sigmoid(self, u):


return 1./(1.+np.exp(-u));

def draw(self, Sin,T):


"""
Bir Gibbs gecisi yaparak dagilimdan bir orneklem al
"""
D=Sin.shape[0]
S=Sin.copy()
rand = np.random.rand(D,1)
for i in xrange(D):
h=np.dot(T[i,:],S)
S[i]=rand[i]<self.sigmoid(h);
return S

def sample(self, T):


N=T.shape[0]
# sigmoid(0) her zaman 0.5 olacak
s=np.random.rand(N)<self.sigmoid(0)
# alttaki dongu atlama / gozonune alinmayacak degerler icin
for k in xrange(self.init_sample_size):
s=self.draw(s,T)
S=np.zeros((N,self.sample_size))
S[:,0]=s
# simdi degerleri toplamaya basla
for i in xrange(1,self.sample_size):
S[:,i]=self.draw(S[:,i-1],T)
return S.T

6
def normc(self, X):
"""
normalizasyon sabitini dondur
"""
def f(x): return np.exp(0.5 * np.dot(np.dot(x,self.W), x))
S = 2*self.sample(self.W)-1
# sozluk icinde anahtar tek x degeri boylece bir
# olasilik degeri sadece bir kere toplanir
res = dict((tuple(s),f(s)) for s in S)
return np.sum(res.values())

def fit(self, X):


W=np.zeros((X.shape[1],X.shape[1]))
W_data=np.dot(X.T,X)/X.shape[1];
for i in range(self.n_iter):
if i % 10 == 0: print 'Iteration', i
S = self.sample(W)
S = (S*2)-1
W_guess=np.dot(S.T,S)/S.shape[1];
W += self.eta * (W_data - W_guess)
np.fill_diagonal(W, 0)
self.W = W
self.C = self.normc(X)

def predict_proba(self, X):


return np.diag(np.exp(0.5 * np.dot(np.dot(X, self.W), X.T))) / self.C

Fonksiyon draw içinde, tek bir veri satırı için ve sırayla her değişken (hücre)
için, diğer değişkenleri baz alıp diğerinin koşulsal olasılığını hesaplıyoruz, ve
sonra bu olasılığı kullanarak bir sayı üretimi yapıyoruz. Üretimin yapılması için
np.random.rand’dan gelen 0 ve 1 arasındaki birörnek (uniform) dağılımdan bir
rasgele sayıyı geçip geçmeme irdelemesi yeterli. Bir Bernoulli olasılık hesabını
üretilen bir rasgele değişkene bu şekilde çevirebilirsiniz. Bu niye işler? Üstte be-
lirttiğimiz irdelemeyi rasgele değişken olarak kodlarsak (ki bu da bir Bernoulli
rasgele değişkeni olur), ve birörnek rasgele değişken U olsun,


1 U<p
Y=
0 U>p

Bu durumda P(X = 1) = P(U < p) = p olurdu. Neden? Çünkü üstte bir sürekli
(continuous) bir birörnek değişken yarattık, ve P(U < p) = Fu (p) = p.
Devam edelim; Çağrı sample ise draw’u kullanarak pek çok veri satırını içeren
ve dağılımı temsil eden bir örneklem yaratmakla sorumlu. Bunu her örneklem
satırını baz alarak bir sonrakini ürettirerek yapıyor, böylelikle MCMC’nin dağılımı
“gezmesi” sağlanmış oluyor.
Normalizasyon Sabiti
Birazdan göreceğimiz örnek için normalizasyon sabitini de hesaplamamız gereke-
cek. Niye? Mesela iki farklı BM dağılımını farklı etiketli verilerden öğreniyoruz,

7
sonra test veri noktasını her iki ayrı dağılıma “soruyoruz”? Olasılığı nedir? Bu
noktada kesin bir olasılık hesabı istediğimiz için artık Z bilinmek zorunda. Bu
sabitin hesaplanması için ise < xi xj >P(x;W) P için olduğu gibi, tüm mümkün x’ler
T
üzerinden bir toplam gerekir, bu toplam x exp 1/2x Wx toplamı. Bu toplamın
hesaplanması çok zor olduğu için, yine MCMC’ye başvuracağız. Tek fark alınan
örneklemi (3) formülüne geceğiz, ve bir olasılık hesabı yapacağız, ve bu olasılıkları
toplayacağız. Tabii aynı x’i (eğer tekrar tekrar üretilirse -ufak bir ihtimal ama
mümkün-) tekrar tekrar toplamamak için hangi x’lerin üretildiğini bir sözlük
içinde hatırlayacağız, yani bir x olasılığı sadece bir kere toplanacak.
Şimdi ufak bir örnek üzerinde BM’i işletelim.

import boltz
A = np.array([\
[0.,1.,1.,1],
[1.,0.,0,0],
[1.,1.,1.,0],
[0, 1.,1.,1.],
[1, 0, 1.,0]
])
A[A==0]=-1

clf = boltz.Boltzmann(n_iter=50,eta=0.01,sample_size=200,init_sample_size=50)
clf.fit(A)
print 'W'
print clf.W
print 'normalizasyon sabiti', clf.C

Iteration 0
Iteration 10
Iteration 20
Iteration 30
Iteration 40
W
[[ 0. -0.065 -0.06 -0.055]
[-0.065 0. 0.17 0.105]
[-0.06 0.17 0. -0.09 ]
[-0.055 0.105 -0.09 0. ]]
normalizasyon sabiti 16.4620358997

Sonuç W üstte görüldüğü gibi. Örnek veriye bakarsak 2. satır 3. kolonda artı bir
değer var, 1. satır 4. kolonda eksi değer var. Bu beklediğimiz bir şey çünkü 2. ve
3. değişkenlerin arasında bir korelasyon var, x2 ne zaman 1/0 ise x3 te 1/0. Fakat
x1 ile x4 ters bir korelasyon var, birbirlerinin zıttı değerlere sahipler.
Şimdi yeni test verisini dağılıma “soralım”,

test = np.array([\
[0.,1.,1.,1],
[1.,1.,0,0],
[0.,1.,1.,1]
])
print clf.predict_proba(test)

8
[ 0.0730905 0.05692294 0.0730905 ]

Görüntü Tanıma
Elimizde el yazısı tanıma algoritmaları için kullanılan bir veri seti var. Veride
0,5,7 harflerinin görüntüleri var. Mesela 5 için bazı örnek görüntüler,

Y = np.loadtxt('../../stat/stat_mixbern/binarydigits.txt')
label = np.ravel(np.loadtxt('../../stat/stat_mixbern/bindigitlabels.txt'))
Y5 = Y[label==5]
plt.imshow(Y5[0,:].reshape((8,8),order='C'), cmap=plt.cm.gray)
plt.savefig('boltzmann_01.png')

plt.imshow(Y5[1,:].reshape((8,8),order='C'), cmap=plt.cm.gray)
plt.savefig('boltzmann_02.png')

plt.imshow(Y5[2,:].reshape((8,8),order='C'), cmap=plt.cm.gray)
plt.savefig('boltzmann_03.png')

Bu görüntüleri tanımak için BM kullanalım. Eğitim ve test olarak veriyi ikiye


ayıracağız, ve eğitim seti her etiketin W’sini öğrenmek için kullanılacak. Daha
sonra test setinde her veri noktalarını her üç BM’ye ayrı ayrı “sorup” o test verisinin
o BM’e göre olasılığını alacağız, ve hangi BM daha yüksek olasılık döndürüyorsa
etiket olarak onu kabul edeceğiz. Hangi BM daha yüksek olasılık döndürüyorsa,
o BM “bu verinin benden gelme olasılığı yüksek” diyor demektir, ve etiket o ol-
malıdır.

from sklearn import neighbors


import numpy as np, boltz
from sklearn.cross_validation import train_test_split

Y = np.loadtxt('../../stat/stat_mixbern/binarydigits.txt')
labels = np.ravel(np.loadtxt('../../stat/stat_mixbern/bindigitlabels.txt'))
X_train, X_test, y_train, y_test = train_test_split(Y, labels, test_size=0.4,random_st
X_train[X_train==0]=-1
X_test[X_test==0]=-1

clfs = {}
for label in [0,5,7]:
x = X_train[y_train==label]
clf = boltz.Boltzmann(n_iter=30,eta=0.05,sample_size=500,init_sample_size=100)
clf.fit(x)
clfs[label] = clf

res = []

9
for label in [0,5,7]:
res.append(clfs[label].predict_proba(X_test))

res3 = np.argmax(np.array(res).T,axis=1)
res3[res3==1] = 5
res3[res3==2] = 7
print 'Boltzmann Makinasi', np.sum(res3==y_test) / float(len(y_test))

clf = neighbors.KNeighborsClassifier()
clf.fit(X_train,y_train)
res3 = clf.predict(X_test)
print 'KNN', np.sum(res3==y_test) / float(len(y_test))

!python testbm.py

Iteration 0
Iteration 10
Iteration 20
Iteration 0
Iteration 10
Iteration 20
Iteration 0
Iteration 10
Iteration 20
Boltzmann Makinasi 0.975
KNN 0.975

Sonuç yüzde 97.5, oldukça yüksek, ve KNN metotu ile aynı sonucu aldık, ki bu
aslında oldukça temiz / basit bir veri seti için fena değil.
Biraz Hikaye
Boltzman Makinalarıyla ilgilenmemizin ilginç bir hikayesi var. Aslında bu metot-
tan haberimiz yoktu, ayrıca mevcut işimizde 0/1 içeren ikisel verilerle çok hasır
neşirdik, ve bu tür verilerde ikisel ilişkiler (coöccürence) hesabı iyi sonuçlar verir,
ki bu hesap basit bir matris çarpımı ile elde edilir.

import numpy as np
A = np.array([\
[0.,1.,1.,0],
[1.,1.,0, 0],
[1.,1.,1.,0],
[0, 1.,1.,1.],
[0, 0, 1.,0]
])
c = A.T.dot(A).astype(float)
print c

[[ 2. 2. 1. 0.]
[ 2. 4. 3. 1.]
[ 1. 3. 4. 1.]
[ 0. 1. 1. 1.]]

Burada bakılırsa 2. satır 3. kolon 3 değerini taşıyor çünkü 2. ve 3. değişkenlerin


aynı anda 1 olma sayısı tam olarak 3. Sonra acaba bu bilgiyi veri üzerinde hesaplayıp

10
bir kenara koysak bir dağılım gibi kullanamaz mıyız, sonra yeni veri noktasını bu
“dağılıma sorabiliriz” diye düşündük. Biraz matris çarpım cambazlığı sonrası,
yeni veri noktası için

x = np.array([0,1,1,0])
print np.dot(np.dot(x.T,c), x) / 2

7.0

gibi sonuçlar alabildiğimizi gördük; Bu değerin ilişki matrisinin tam ortasındaki


4,3,3,4 sayılarının toplamının yarısı olduğuna dikkat edelim. Yani x çarpımı ilişki
matrisinin sadece kendini ilgilendiren kısmını çekip çıkarttı, yani 2. ve 3. değişenleri
arasındaki ilişkiyi toplayıp aldı.
Buradan sonra, “acaba bu bir dağılım olsa normalizasyon sabiti ne olurdu?” sorusuna
geldik, ki [4] sorusu buradan çıktı ve bu soruya bomba bir cevap geldi. Sonra
diğer okumalarımız sırasında Boltzmann Dağılımına ulaştık, bu dağılımın ek
olarak bir exp tanımı var (ki türev alımı sırasında bu faydalı), ve tabii öğrenim
için daha net bir matematiği var. Biz de maksimum olurluk ile [4]’teki fikrin
sayısal kovaryansa ulaştırıp ulaştırmayacağını merak ediyorduk, BM formunda
verisel kovaryans direk elde ediliyor. Böylece BM konusuna girmiş olduk.
Bitirmeden önce ufak not, BM’ler Kısıtlı BM (RBM) için bir zıplama tahtası, ve
RBM’ler Derin Öğrenimin (Deep Learning) bir türü için kullanılabilir, bu yapay
sinir ağlarını birden fazla RBM’leri üst üste koyarak elde etmek mümkün (gerçi
son zamanlarda moda yaklaşım evrişimsel ağ -convolutional network- kullan-
mak).
[1] D. MacKay, Information Theory, Inference and Learning Algorithms, sf. 523
[2] Flaxman, Notebook, http://nbviewer.ipython.org/gist/aflaxman/
7d946762ee99daf739f1
1
exp 12 xT Wx to Sigmoid, http://math.
 
[3] Stack Exchange, From P(x; W) = Z(W)
stackexchange.com/questions/1095491/from-pxw-frac1zw-exp-bigl-
frac12-xt-w-x-bigr-to-sigmoid/
P
[4] Stack Exchange, Calculating the sum 21 xT Σx for all x ∈ {0, 1}n , http://
math.stackexchange.com/questions/1080504/calculating-the-sum-
frac12-sum-xt-sigma-x-for-all-x-in-0-1-n
[5] Bayramli, Istatistik, Monte Carlo, Entegraller, MCMC
[6] Bayramli, Istatistik, Lojistik Regresyon

11
Kısıtlı Boltzmann Makinaları (Restricted Boltzmann Machines -RBM-)
RBM aynen Boltzman Makinalarında (BM) örneğinde olduğu gibi bir dağılımdır.
Verilen x, h için bir olasılık değeri geri döndürebilir.

p(x, h; W) = exp(−E(x, h))/Z

Standart RBM için h, x ikiseldir (binary). Gizli (hidden) tabaka h, ve “görünen


(visible)” tabaka x vardır. Z aynen önce gördüğümüz BM’de olduğu gibi nor-
malizasyon sabitidir. Spesifik bir RBM’i tanımlayan şey onun W matrisidir. Gizli
değişkenler bazen karışıklık yaratabiliyor, bu değişkenler aynen görünen değişkenler
gibi değişkendirler. Yani belli h’lerin “olasılığı” sorulabilir, ya da onlar üretilebilir.
Fakat RBM’i eğitirken sadece görünen kısmı tarafından eğitiriz. Gizli tabaka bu
sırada örneklem ile arada sırada içi doldurulur, bu tabii ki W’ye bağlı olarak
yapılacaktır. Gizli tabaka daha düşük boyutlu olduğu, ve 0/1 değerlerine sahip
olması mecbur olduğu için bu git/gel bir tür özetleme yapar ki öğrenim bu sırada
ortaya çıkar.
Devam edelim, E tanımına “enerji” olarak ta atıf yapılabiliyor.

E(x, h) = −hT Wx − cT x − bT h

BM’lerden farklı olarak RBM’de c, b değişkenleri var. Bu değişkenler yanlılık


(bias) için, yani veri içindeki genel eğilimi saptamaları için modele konulmuştur.
Ayrıca hT Wx terimi var, bu BM’deki xT Wx’den biraz farklı, daha önce belirttiğimiz
gibi, h üzerinden x’ler arasında bağlantı yapıyor. BM ile tüm x öğeleri birbirine
bağlanabiliyordu, RBM ile h katmanında bağlantılar paylaşılıyor. Bu h üzerinden
bağlantı zorunluluğu RBM’in özetleme alanını azaltarak genelleme oluşturmasını
sağlıyor. Bu yüzden onlara “kısıtlı” Boltzmann makinaları adı veriliyor. Gizli
değişkenlerin kendi aralarında, ve görünen değişkenlerin kendi aralarında direk
bağlantıya izin verilmemiştir, ki bu daha önce bahsedilen kısıtlamanın bir diğer
yönü. Bağlantılara, W üzerinden sadece gizli ve görünen değişkenler (tabakalar)
arasında izin verilmiştir. Bu ayrıca matematiksel olarak bazı kolaylıklar sağlıyor,
bu konuyu birazdan işleyeceğiz.
Formül alttaki gibi de açılabilir,

XX X X
=− Wj,k hj xk − ck xk − b j hj
j k k j

1
Tekrar vurgulayalım, h, x değişkenleri olasılık teorisinden bilinen rasgele değişkenlerdir,
yani hem x’e hem de h’e “zar attırabiliriz” / bu değişkenler üzerinden örneklem
toplayabiliriz.
Ayrıca, RBM’ler aynen BM’ler gibi bir olasılık yoğunluk fonksiyonu üzerinden
tanımlanırlar, önceki formülde gördüğümüz gibi, tüm mümkün değerleri üzerinden
entegralleri (ya da toplamları) alınınca sonuç 1 olur, vs.
Devam edelim, ana formülden hareketle cebirsel olarak şunlar da doğrudur,

p(x, h; W) = exp(−E(x, h))/Z

= exp(hT Wx + cT x + bT h)/Z (2)

= exp(hT Wx) exp(cT x) exp(bT h)/Z

çünkü bir toplam üzerindeki exp, ayrı ayrı exp’lerin çarpımı olur. Aynı mantıkla,
eğer ana formülü matris / vektör yerine ayrı değişkenler olarak görmek istersek,

1 YY Y Y
p(x, h; W) = exp(Wjk hj xk ) exp(ck xk ) exp(bj hj )
Z j k k j

Notasyonu kolaylaştırmak amacıyla b, c terimlerini W içine absorbe edebiliriz,


x0 = 1 ve h0 = 1 değerlerini mecbur tutarsak ve w0,: = c ve w:,0 = b dersek, yani
W’nin sıfırıncı satırının tamamının c olduğunu, sıfırıncı kolonunun tamamının
b olduğunu kabul edersek RBM ana formülünü tekrar elde etmiş oluruz, fakat
artık

E(x, h) = −hT Wx

XX
=− Wj,k hj xk
j k

ve

2
p(x, h; W) = exp(hT Wx)/Z

yeterli olacaktır. Bir diğer kolaylık x, h yerine tek değişken kullanmak,


Eğer y ≡ (x, h) olarak alırsak (≡ tabiri “tanım” anlamına gelir),
 
1 1 T
P(x, h; W) = exp y Wy
Z(W) 2

Aslında açık konuşmak gerekirse “enerji” gibi kavramlarla uğraşmak, ya da içinde


eksi terimler içeren bir grup değişkenin tekrar eksisini almak ve eksilerin etk-
isini nötralize etmiş olmaya gerek yok, bunun yerine baştan (2)’deki ifadeyle
yola çıkmak daha kısa olur. İçinde enerji olan açıklamaları biraz da literatürde
görülebilecek anlatımlara açıklık getirmek için yaptık.
Şimdi h üzerinden marjinalize edersek,

X 1

1 T

P(x; W) = exp y Wy
h
Z(W) 2

1 X
 
1 T
P(x; W) = exp y Wy (1)
Z(W) h 2

Ve Z(W)

X 
1

Z(W) = exp yT Wy
h,x
2

(1) denkleminde bölümünden sonraki kısma Zx (W) dersek, sanki aynı exp den-
kleminin x’ler üzerinden marjinalize edilmiş hali olarak gösterebiliriz onu, ve
böylece daha kısa bir formül kullanabiliriz,

1 X
 
1 T
P(x; W) = exp y Wy
Z(W) h 2
| {z }
Zx (W)

O zaman

Zx (W)
P(x; W) =
Z(W)

elde ederiz. Veri üzerinden maksimum olurluk için, yine log üzerinden bir hesap
yaparız, BM için yapmıştık bunu,

3
Y
N X
N
L = ln n
ln P(xn ; W)

P(x ; W) =
n=1 n=1

X
N
Zx(n) (W) X
N

= ln = ln Zx(n) − ln Z
n=1
Z(W) n=1

∂L X ∂ ln Z (n) ∂ ln Z 
N
x
= − (3)
∂wij n=1 ∂wij ∂wij

Parantez içindeki 1. türevi alalım,


X 
∂ ln Zx(n) ∂ 1 nT n

= ln exp y Wy
∂wij ∂wij h
2
X 
1 ∂ 1 nT n

= exp y Wy
Zx(n) h
∂wij 2
X 
1 1 T  ∂ nT
= exp yn Wyn y Wyn
Zx(n) h
2 ∂wij

1 X 1 nT
y Wyn yi yj

= exp
Zx(n) h
2

X 1 1 nT
y Wyn yi yj

= exp
h
Zx(n) 2

Zx(n) ’nin ne olduğunu hatırlarsak, exp ifadesinin h üzerinden marjinalize edilmiş


hali,

X exp 1 ynT Wyn



= P 2
1 T
 yi y j
h h exp 2
y Wy

Eğer bölümün üstünü ve altını Z ile bolşek,

X exp 1 ynT Wyn /Z



= P 2
1 T
 y i yj
h h exp 2
y Wy /Z

Üst kısım P(y; W) yani P(x, h; W) alt kısım P(x; W) olmaz mı? Evet! Ve,

P(xn , h; W)
P(h|xn ; W) =
P(xn ; W)

4
olduğuna göre,

X
= P(h|xn ; W)yi yj
h

elde ederiz. Bunu da < yi yj >P(h|xn ;W) olarak yazabiliriz.


∂ ln Z
Şimdi parantez içindeki 2. türevi alalım, yani ∂wij
,

∂ ln Z X 1 1 X
exp yT Wy yi yj =

= P(y; W)yi yj
∂wij h,x
Z 2 h,x

ki bu son ifadeyi de < yi yj >P(y;W) olarak yazabiliriz. Tamamını, yani (3) ifadesini,
artık şöyle yazabiliriz,

XN
∂ ln Zx(n) ∂ ln Z  X
N
− = < yi yj >P(h|xn ;W) − < yi yj >P(y;W) (4)
n=1
∂w ij ∂w ij
n=1

Bu formülü de BM için yaptığımız gibi bir gradyan güncelleme formülüne dönüştürebiliriz.


Güncelleme formülünün hangi hesapları gerektirdiğine gelince; İlk terim tüm
h’ler üzerinden ki hesabı basit, ikincisi ise tüm mümkün x, h’ler üzerinden bir
olasılık hesabı ve örnekleme gerektirecek. Bu durum çetin hesap (intractable)
denen bir durum, özellikle x, h şartı için; daha önce BM için bu problemi Gibbs
örneklemesi ile çözmüştük. Aynı çözümü burada da uygulayabiliriz, fakat belki
daha iyi bir yaklaşım şu olacak.
CD Yöntemi (Contrastive Divergence)
RBM’leri eğitmek için kullanılan en popüler yöntem CD yöntemidir. Bu tekniği
anlatmadan önce bazı matematiksel kolaylıkları bilmek gerekli.
RBM grafiğine bakarsak, eğer x biliniyor ise bu h değişkenlerini bağımsız hale
getirir (koşullu olasılık kuralı), ve aynı şekilde h biliniyor ise x bağımsız hale
gelir. Bunu görsel olarak bile anlamak çok kolay, elimizle tüm x’leri kapatalım
mesela ve h düğümlerine bakalım, aralarında hiçbir bağlantı yoktur değil mi?
Aynı şekilde h kapatınca x’ler “bağlantısız” hale gelir.
Bu bağımsızlıktan yola çıkarak, daha önce BM için yaptığımız gibi, olasılıklar şu
basit formüllere dönüşür,

X
m 
P(hi = 1|x) = σ wij xj
j=1

X
n 
P(xi = 1|h) = σ wij hi
i=1

5
ve tabii ki σ(x) = 1/(1 + e−x ). Daha önce 1 olma olasılığını nasıl örnekleme
çevireceğimizi de görmüştük zaten.
Şimdi CD’nin ne olduğuna gelelim. Eğer RBM için gereken örneklemeyi klasik
Gibbs ile yaparsak örnekleme zincirini “yeterince uzun süre” işletmek gerekir
ki dağılımın olası noktaları gezilmiş olsun. Fakat, özellikle yüksek boyutlu du-
rumlarda, tüm x, h kombinasyonlarını düşünürsek bu çok büyük bir alandır ve
gezme işlemi çok, çok uzun zaman alabilir. Bunun yerine, ve üstteki bağımsızlık
formüllerinden hareketle CD yöntemi bulunmuştur, bu yönteme göre örnekleme
verinin kendisinden başlatılır (kıyasla pür Gibbs rasgele bir noktadan), döngünün
mesela ilk adımında x0 (ki bu tüm verinin tamamı), baz alınarak p(h0 |v0 ) hesa-
planır (üstteki sigmoid), onun üzerinden h0 örneklemi alınır, sonra h0 baz alınır
ve x1 üretilir, bu böyle devam eder. Böylece mümkün h ve x’ler gezilmiş olur.
Not: Sürekli verinin kendisine dönmenin de bazı dezavantajları var, ki bunu yap-
madan pür Gibbs örneklemesine daha yakın bir yaklaşım Kalıcı (Persistent) CD
adlı yöntemdir (tabii başka yaklaşıksal numaralar kullanarak).
Literatürde şu şekildeki resim bolca görülebilir,

Bu yöntem pür Gibbs örneklemesine kıyasla çok daha hızlı işler ve iyi sonuçlar
verir. Teorik olarak niye işlediği [1,2,4] makalelerinde bulunabilir. CD aslında
(4) hedef formülünü değil başka bir hedefi optimize ediyor, fakat sonuç orijinal
gradyan adımlarının yapmak istediğine yakın. [3] baz alınarak, şu şekilde kod-
lanabilir,

import numpy as np
import itertools

class RBM:

def __init__(self, num_hidden, learning_rate,max_epochs, num_visible=10):


self.num_hidden = num_hidden
self.num_visible = num_visible
self.learning_rate = learning_rate
# Agirlik matrisi W'yi yarat (buyukluk num_visible x num_hidden),
# bunun icin Gaussian dagilimi kullan, ortalama=0, standart sapma 1.
self.weights = 0.1 * np.random.randn(self.num_visible, self.num_hidden)
# Egilim (bias) icin ilk satir ve ilk kolona 1 degeri koy
self.weights = np.insert(self.weights, 0, 0, axis = 0)

6
self.weights = np.insert(self.weights, 0, 0, axis = 1)
self.max_epochs = max_epochs

def fit(self, data):


"""
Makinayi egit

Parametreler
----------
data: Her satirin "gorunen" veri oldugu bir matris
"""

num_examples = data.shape[0]

# Ilk kolona egilim / meyil (bias) olarak 1 ekle


data = np.insert(data, 0, 1, axis = 1)

for epoch in range(self.max_epochs):


# Veriyi baz alarak gizli veriyi uret.
pos_hidden_activations = np.dot(data, self.weights)
pos_hidden_probs = self._logistic(pos_hidden_activations)
pos_hidden_states = pos_hidden_probs > \
np.random.rand(num_examples, self.num_hidden + 1)

tmp = np.array(pos_hidden_states).astype(float)
pos_visible_states = self.run_hidden(tmp[:,1:])

# Dikkat, baglantilari hesaplarken h tabakasinin aktivasyon


# olasiliklarini kullaniyoruz h'nin kendi degerlerini (0/1)
# kullanmiyoruz. Bunu da yapabilirdik, daha fazla detay icin
# Hinton'un "A Practical Guide to Training Restricted Boltzmann
# Machines" makalesine bakilabilir
pos_associations = np.dot(data.T, pos_hidden_probs)

# Simdi gorunen veriyi gizli veriyi baz alip tekrar uret


neg_visible_activations = np.dot(pos_hidden_states, self.weights.T)
neg_visible_probs = self._logistic(neg_visible_activations)
neg_visible_probs[:,0] = 1 # Fix the bias unit.
neg_hidden_activations = np.dot(neg_visible_probs, self.weights)
neg_hidden_probs = self._logistic(neg_hidden_activations)

# Yine ayni durum, aktivasyon olasiliklari kullaniliyor


neg_associations = np.dot(neg_visible_probs.T, neg_hidden_probs)

# Agirliklari guncelle
self.weights += self.learning_rate * \
((pos_associations - neg_associations) / num_examples)

error = np.sum((data - neg_visible_probs) ** 2)

def run_visible(self, data):


"""
RBM'in egitilmis olduguna farz ederek, gorunen veri uzerinde
RBM'i islet, ve h icin bir orneklem al

7
Parametreler
----------
data: Her satirin gorunen veri oldugu bir matris

Returns
-------
hidden_states: data icindeki her satira tekabul eden gizli h verisi
"""
num_examples = data.shape[0]

hidden_states = np.ones((num_examples, self.num_hidden + 1))

data = np.insert(data, 0, 1, axis = 1)

hidden_activations = np.dot(data, self.weights)


hidden_probs = self._logistic(hidden_activations)
hidden_states[:,:] = hidden_probs > \
np.random.rand(num_examples, self.num_hidden + 1)
hidden_states = hidden_states[:,1:]
return hidden_states

def run_hidden(self, data):


"""
run_visible'a benzer, sadece gizli veri icin gorunen veri uret
"""

num_examples = data.shape[0]

visible_states = np.ones((num_examples, self.num_visible + 1))

data = np.insert(data, 0, 1, axis = 1)

visible_activations = np.dot(data, self.weights.T)


visible_probs = self._logistic(visible_activations)
visible_states[:,:] = visible_probs > \
np.random.rand(num_examples, self.num_visible + 1)

visible_states = visible_states[:,1:]
return visible_states

def _logistic(self, x):


return 1.0 / (1 + np.exp(-x))

if __name__ == "__main__":
import numpy as np
X = np.array([[0, 0, 0], [0, 1, 1], [1, 0, 1], [1, 1, 1]])
model = RBM(num_hidden=2,learning_rate=0.1,max_epochs=10,num_visible=3)
model.fit(X)
print model.weights

RBM ve Sınıflama
Sınıflama (classification) işlemi yapmak için BM örneğinde bir normalizasyon

8
sabiti hesaplamıştık. Burada değişik bir yoldan gideceğiz; ki bu yol ileride Derin
Öğrenim için faydalı olacak.
Eğittikten sonra bir RBM, içindeki W’ye göre, herhangi bir “görünür” veri nok-
tası x için bir gizli bir h üretebilir. Bunu üstteki formülasyondan zaten biliy-
oruz. Ayrıca, h genellikle daha az boyutta olduğuna göre (hatta olmasa bile)
bu h üretiminin bir tür transformasyon olduğu, veri üzerinde bir “özetleme”
yaptığı iddia edilebilir. O zaman teorik olarak, görünür veri yerine, görünür
veriden üretilen gizli veriyi kullanırsak ve bu veriyi alıp başka bir sınıflayıcıya
verirsek, mesela lojistik regresyon gibi, bu h’ler ve etiketler üzerinden denetimli
(supervised) bir eğitim yapabiliriz. Yani, önce RBM eğitiyoruz, tüm verinin h
karşılığını alıyoruz, sonra bunları lojistik regresyona veriyoruz. Alttaki kodda
bunun örneğinin görebiliriz.
Bu kod, ayrıca, k-Katlama (k-fold) tekniğini uyguluyor, veriyi 3 parçaya bölüp
sırasıyla tüm parçaları birer kez test, diğerlerini eğitim verisi yapıyor, böylece
verinin tamamı üzerinden eğitim/test yapmış olunuyor. Sonuç,

from sklearn.linear_model import LogisticRegression


from sklearn.cross_validation import KFold
import numpy as np, rbm

X = np.loadtxt('../../stat/stat_mixbern/binarydigits.txt')
Y = np.ravel(np.loadtxt('../../stat/stat_mixbern/bindigitlabels.txt'))
print X.shape, Y.shape

np.random.seed(0)

scores = []
cv = KFold(n=len(X),n_folds=3)
for train, test in cv:
X_train, Y_train = X[train], Y[train]
X_test, Y_test = X[test], Y[test]
r = rbm.RBM(num_hidden=40, learning_rate=0.3,max_epochs=500, num_visible=64)
r.fit(X_train)
clf = LogisticRegression(C=1000)
clf.fit(r.run_visible(X_train), Y_train)
res3 = clf.predict(r.run_visible(X_test))
scores.append(np.sum(res3==Y_test) / float(len(Y_test)))

print np.mean(scores)

! python test_rbmkfold.py

1.0

Başarı yüzde 100! Altta karşılaştırma için KNN tekniği kullandık,

from sklearn import neighbors


from sklearn.linear_model import LogisticRegression
import numpy as np

9
X = np.loadtxt('../../stat/stat_mixbern/binarydigits.txt')
Y = np.ravel(np.loadtxt('../../stat/stat_mixbern/bindigitlabels.txt'))

from sklearn.cross_validation import KFold


scores = []
cv = KFold(n=len(X),n_folds=3)
for train, test in cv:
X_train, Y_train = X[train], Y[train]
X_test, Y_test = X[test], Y[test]
clf = neighbors.KNeighborsClassifier(n_neighbors=1)
clf.fit(X_train, Y_train)
scores.append(clf.score(X_test, Y_test))

print np.mean(scores)

! python test_knnkfold.py

0.98009506833

Kaynaklar
[1] Hinton, G., Training Products of Experts by Minimizing Contrastive Divergence
[2] Louppe, G., Collaborative filtering, Scalable approaches using restricted Boltzmann
machines, Master Tezi, 2010
[3] https://github.com/echen/restricted-boltzmann-machines
[4] Tieleman, Hinton, Using Fast Weights to Improve Persistent Contrastive Diver-
gence
[5] Larochelle, H., Neural networks [5.1] : Restricted Boltzmann machine - definition,
https://www.youtube.com/watch?v=p4Vh_zMw-HQ

10
Asal Bileşen Analizi (Principal Component Analysis -PCA-)
PCA yöntemi boyut azaltan yöntemlerden biri, denetimsiz (unsupervised) işleyebilir.
Ana fikir veri noktalarının izdüşümünün yapılacağı yönler bulmaktır ki bu yönler
bağlamında (izdüşüm sonrası) noktaların arasındaki sayısal varyans (empirical
variance) en fazla olsun, yani noktalar grafik bağlamında düşünürsek en ”yayılmış”
şekilde bulunsunlar. Böylece birbirinden daha uzaklaşan noktaların mesela daha
rahat kümelenebileceğini umabiliriz. Bir diğer amaç, hangi değişkenlerin varyansının
daha fazla olduğunun görülmesi üzerine, o değişkenlerin daha önemli olabileceğinin
anlaşılması. Örnek olarak alttaki grafiğe bakalım,

from pandas import *


data = read_csv("testSet.txt",sep="\t",header=None)
print (data[:10])
0 1
0 10.235186 11.321997
1 10.122339 11.810993
2 9.190236 8.904943
3 9.306371 9.847394
4 8.330131 8.340352
5 10.152785 10.123532
6 10.408540 10.821986
7 9.003615 10.039206
8 9.534872 10.096991
9 9.498181 10.825446

plt.scatter(data.ix[:,0],data.ix[:,1])
plt.plot(data.ix[1,0],data.ix[1,1],'rd')
plt.plot(data.ix[4,0],data.ix[4,1],'rd')
plt.savefig('pca_1.png')

PCA ile yapmaya çalıştığımız öyle bir yön bulmak ki, x veri noktalarının tamamının
o yöne izdüşümü yapılınca sonuç olacak, ”izdüşümü yapılmış” z’nin varyansı en
büyük olsun. Bu bir maksimizasyon problemidir. Fakat ondan önce x nedir, z
nedir bunlara yakından bakalım.
Veri x ile tüm veri noktaları kastedilir, fakat PCA probleminde genellikle bir
”vektörün diğeri üzerine” yapılan izdüşümü, ”daha optimal bir w yönü bulma”,
ve ”o yöne doğru izdüşüm yapmak” kelimeleri kullanılır. Demek ki veri nokta-
larını bir vektör olarak görmeliyiz. Eğer üstte kırmızı ile işaretlenen iki noktayı
alırsak (bu noktalar verideki 1. ve 4. sıradaki noktalar),

1
gibi bir görüntüden bahsediyoruz. Hayali bir w kullandık, ve noktalardan biri
veri noktası, w üzerine izdüşüm yapılarak yeni bir vektörü / noktayı ortaya
çıkartılıyor. Genel olarak ifade edersek, bir nokta için

zi = xTi w = xi · w

Yapmaya çalıştığımız sayısal varyansı maksimize etmek demiştik. Bu arada verinin


hangi dağılımdan geldiğini söylemedik, “her veri noktası birbirinden ayrı, bağımsız
ama aynı bir dağılımdandır” bile demedik, x bir rasgele değişkendir beyanı yap-
madık (x veri noktalarını tutan bir şey sadece). Sadece sayısal varyans ile iş ya-
pacağız. Sayısal varyans,

1X
(xi · w)2
n i

Toplama işlemi yerine şöyle düşünelim, tüm xi noktalarını istifleyip bir x matrisi
haline getirelim, o zaman xw ile bir yansıtma yapabiliriz, bu yansıtma sonucu bir
vektördür. Bu tek vektörün karesini almak demek onun devriğini alıp kendisi ile
çarpmak demektir, yani

1 1
= (xw)T (xw) = wT xT xw
n n

xT x
= wT w
n

xT x/n sayısal kovaryanstır (empirical covariance). Ona Σ diyelim.

= wT Σw

Üstteki sonuçların boyutları 1×N·N×N·N×1 = 1×1. Tek boyutlu skalar degerler


elde ettik. Yani w yönündeki izdüşüm bize tek boyutlu bir çizgi verecektir. Bu
sonuç aslında çok şaşırtıcı olmasa gerek, tüm veri noktalarını alıp, başlangıcı
başnokta 0,0 (origin) noktasında olan vektörlere çevirip aynı yöne işaret edecek
şekilde düzenliyoruz, bu vektörleri tekrar nokta olarak düşünürsek, tabii ki aynı

2
yönü gösteriyorlar, bilahere aynı çizgi üzerindeki noktalara dönüşüyorlar. Aynı
çizgi üzerinde olmak ne demek? Tek boyuta inmiş olmak demek.
Ufak bir sorun wT Σw’i sürekli daha büyük w’lerle sonsuz kadar büyütebilirsiniz.
Bize ek bir kısıtlama şartı daha lazım, bu şart ||w|| = 1 olabilir, yani w’nin norm’u
1’den daha büyük olmasın. Böylece optimizasyon w’yi sürekli büyüte büyüte
maksimizasyon yapmayacak, sadece yön bulmak ile ilgilenecek, iyi, zaten biz
w’nin yönü ile ilgileniyoruz. Aradığımız ifadeyi yazalım, ve ek sınırı Lagrange
ifadesi olarak ekleyelim, ve yeni bir L ortaya çıkartalım,

L(w, λ) = wT Σw − λ(wT w − 1)

Niye eksiden sonraki terim o şekilde eklendi? O terim öyle şekilde seçildi ki,
∂L/∂λ = 0 alınınca wT w = 1 geri gelsin / ortaya çıksın [2, sf 340]. Bu Lagrange’in
dahice buluşu. Bu kontrol edilebilir, λ ’ya göre türev alırken w1 sabit olarak
yokolur, parantez içindeki ifadeler kalır ve sıfıra eşitlenince orijinal kısıtlama
ifadesi geri gelir. Şimdi

max L(w, λ)
w

için türevi w’e göre alırsak, ve sıfıra eşitlersek,

∂L
= 2wΣ − 2λw = 0
∂w

2wΣ = 2λw

Σw = λw

Üstteki ifade özdeğer, özvektör ana formülüne benzemiyor mu? Evet. Eğer w,
Σ’nin özvektörü ise ve eşitliğin sağındaki λ ona tekabül eden özdeğer ise, bu
eşitlik doğru olacaktır.
Peki hangi özdeğer / özvektör maksimal değeri verir? Unutmayalım, maksimize
etmeye çalıştığımız şey wT Σw idi
Eger Σw = λw yerine koyarsak

wT λw = λwT w = λ

Çünkü wT1 w’nin 1 olacağı şartını koymuştuk. Neyse, maksimize etmeye çalıştığımız
değer λ çıktı, o zaman en büyük λ kullanırsak, en maksimal varyansı elde ederiz,
bu da en büyük özdeğerin ta kendisidir. Demek ki izdüşüm yapılacak ”yön” ko-
varyans Σ’nin en büyük özdeğerine tekabül eden özvektör olarak seçilirse, temel

3
bileşenlerden en önemlisini hemen bulmuş olacağız. İkinci, üçüncü en büyük
özdeğerin özvektörleri ise diğer daha az önemli yönleri bulacaklar.
Σ matrisi n×n boyutunda bir matris, bu sebeple n tane özvektörü olacak. Her ko-
varyans matrisi simetriktir, o zaman lineer cebir bize der ki özvektörler birbirine
dikgen (orthogonal) olmalı. Yıne Σ bir kovaryans matrisi olduğu için pozitif bir
matris olmalı, yani herhangi bir x için xΣx > 0. Bu bize tüm özvektörlerin > 0
olması gerektiğini söylüyor.
Kovaryansın özvektörleri verinin asal bileşenleridir (principal components), ki
metotun ismi burada geliyor.
Örnek
Şimdi tüm bunları bir örnek üzerinde görelim. İki boyutlu örnek veriyi üstte
yüklemiştik. Şimdi veriyi ”sıfırda ortalayacağız” yani her kolon için o kolo-
nun ortalama değerini tüm kolondan çıkartacağız. PCA ile işlem yaparken tüm
değerlerin sıfır merkezli olması gerekiyor, çünkü bu sayısal kovaryans için gerekli.
Daha sonra özdeğer / vektör hesabı için kovaryansı bulacağız.

import numpy.linalg as lin


from pandas import *
data = read_csv("testSet.txt",sep="\t",header=None)
print (data.shape)
print (data[:10])

means = data.mean()
meanless_data = data - means
cov_mat = np.cov(meanless_data, rowvar=0)
print (cov_mat.shape)
eigs,eigv = lin.eig(cov_mat)
eig_ind = np.argsort(eigs)
print (eig_ind)
(1000, 2)
0 1
0 10.235186 11.321997
1 10.122339 11.810993
2 9.190236 8.904943
3 9.306371 9.847394
4 8.330131 8.340352
5 10.152785 10.123532
6 10.408540 10.821986
7 9.003615 10.039206
8 9.534872 10.096991
9 9.498181 10.825446
(2, 2)
[0 1]

print (eigs[1],eigv[:,1].T)
print (eigs[0],eigv[:,0].T)
2.8971349561751887 [-0.52045195 -0.85389096]
0.36651370866931066 [-0.85389096 0.52045195]

4
En büyük olan yönü quiver komutunu kullanarak orijinal veri seti üzerinde gösterelim,

plt.scatter(data.ix[:,0],data.ix[:,1])
# merkez 9,9, tahminen secildi
plt.quiver(9,9,eigv[1,1],eigv[0,1],scale=10,color='r')
plt.savefig('pca_2.png')

Görüldüğü gibi bu yön hakikaten dağılımın, veri noktalarının en çok yayılmış


olduğu yön. Demek ki PCA yöntemi doğru sonucu buldu. Her iki yönü de
çizersek,

plt.scatter(data.ix[:,0],data.ix[:,1])
plt.quiver(9,9,eigv[1,0],eigv[0,0],scale=10,color='r')
plt.quiver(9,9,eigv[1,1],eigv[0,1],scale=10,color='r')
plt.savefig('pca_3.png')

Bu ikinci yön birinciye dik olmalıydı, ve o da bulundu. Aslında iki boyut olunca
başka seçenek kalmıyor, 1. yön sonrası ikincisi başka bir şey olamazdı, fakat çok
daha yüksek boyutlarda en çok yayılımın olduğu ikinci yön de doğru şekilde geri
getirilecekti.
Artımsal PCA (Incremental PCA)
Toptan işlem yapmak yerine ufak parçalar üzerinde PCA işletebilmek için [9]’deki
fikir kullanılabilir. Böylece elimize yeni bir veri geçince tüm önceki veriler +
yeni veriyi birarada işlememize gerek kalmıyor. Eldeki son PCA durumunu yeni
veriyi kullanarak güncelliyoruz. Bu sekilde isleyen bir PCA teknigi CCIPCA.

# https://github.com/kevinhughes27/pyIPCA baz alinmistir


# online PCA using CCIPCA method which can process sparse
# rows (minibatches of 1).

5
import scipy.sparse as sp
import numpy as np
from scipy import linalg as la
import scipy.sparse as sps
from sklearn import datasets

class CCIPCA:
def __init__(self, n_components, n_features, amnesic=2.0, copy=True):
self.n_components = n_components
self.n_features = n_features
self.copy = copy
self.amnesic = amnesic
self.iteration = 0
self.mean_ = None
self.components_ = None
self.mean_ = np.zeros([self.n_features], np.float)
self.components_ = np.ones((self.n_components,self.n_features)) / \
(self.n_features*self.n_components)

def partial_fit(self, u):


n = float(self.iteration)
V = self.components_

# amnesic learning params


if n <= int(self.amnesic):
w1 = float(n+2-1)/float(n+2)
w2 = float(1)/float(n+2)
else:
w1 = float(n+2-self.amnesic)/float(n+2)
w2 = float(1+self.amnesic)/float(n+2)

# update mean
self.mean_ = w1*self.mean_ + w2*u

# mean center u
u = u - self.mean_

# update components
for j in range(0,self.n_components):

if j > n: pass
elif j == n: V[j,:] = u
else:
# update the components
V[j,:] = w1*V[j,:] + w2*np.dot(u,V[j,:])*u / la.norm(V[j,:])
normedV = V[j,:] / la.norm(V[j,:])
normedV = normedV.reshape((self.n_features, 1))
u = u - np.dot(np.dot(u,normedV),normedV.T)

self.iteration += 1
self.components_ = V / la.norm(V)

return

def post_process(self):

6
self.explained_variance_ratio_ = np.sqrt(np.sum(self.components_**2,axis=1))
idx = np.argsort(-self.explained_variance_ratio_)
self.explained_variance_ratio_ = self.explained_variance_ratio_[idx]
self.components_ = self.components_[idx,:]
self.explained_variance_ratio_ = (self.explained_variance_ratio_ / \
self.explained_variance_ratio_.sum())
for r in range(0,self.components_.shape[0]):
d = np.sqrt(np.dot(self.components_[r,:],self.components_[r,:]))
self.components_[r,:] /= d

Örnek için Iris veri setinde görelim,

import pandas as pd, ccipca

df = pd.read_csv('../../stat/stat_cov_corr/iris.csv')
df = np.array(df)[:,:4].astype(float)
pca = ccipca.CCIPCA(n_components=2,n_features=4)
S = 10
print (df[0, :])
for i in range(150): pca.partial_fit(df[i, :])
pca.post_process()
print ('varyans orani',pca.explained_variance_ratio_)
print ('sonuc', pca.components_.T)

[5.1 3.5 1.4 0.2]


varyans orani [0.99758595 0.00241405]
sonuc [[ 0.80321426 0.21317031]
[ 0.38265982 0.38577571]
[ 0.44985225 -0.8021981 ]
[ 0.07778993 -0.40275764]]

Paylaşılan CCIPCA kodu satırları seyrek matris formatında da işleyebiliyor.


SVD ile PCA Hesaplamak
PCA bölümünde anlatılan yöntem temel bileşenlerin hesabında özdeğerler ve
özvektörler kullandı. Alternatif bir yöntem Eşsiz Değer Ayrıştırma (Singular
Value Decomposition -SVD-) üzerinden bu hesabı yapmaktır. SVD için [10]’a
bakabiliriz. Peki ne zaman klasik PCA ne zaman SVD üzerinden PCA kullan-
malı? Bir cevap belki mevcut kütüphanelerde SVD kodlamasının daha iyi olması,
ayrıştırmanın özvektör / değer hesabından daha hızlı işleyebilmesi [6].
Ayrıca birazdan göreceğimiz gibi SVD, kovaryans matrisi üzerinde değil, A’nin
kendisi üzerinde işletilir, bu hem kovaryans hesaplama aşamasını atlamamızı,
hem de kovaryans hesabı sırasında ortaya çıkabilecek sayısal (numeric) pürüzlerden
korunmamızı sağlar (çok ufak değerlerin kovaryans hesabını bozabileceği lit-
eratürde bahsedilmektedir).
PCA ve SVD bağlantısına gelelim:
Biliyoruz ki SVD bir matrisi şu şekilde ayrıştırır

A = USV T

7
U matrisi n × n dikgen (orthogonal), V ise m × m dikgen. S’in sadece köşegeni
üzerinde değerler var ve bu σj değerleri A’nin eşsiz değerleri (singular values)
olarak biliniyor.
Şimdi A yerine AAT koyalım, ve bu matrisin SVD ayrıştırmasını yapalım, acaba
elimize ne geçecek?

AAT = (USV T )(USV T )T

= (USV T )(VST UT )

= USST UT

S bir köşegen matrisi, o zaman SST matrisi de köşegen, tek farkla köşegen üzerinde
artık σ2j değerleri var. Bu normal.
SST yerine Λ sembolünü kullanalım, ve denklemi iki taraftan (ve sağdan) U ile
çarparsak (unutmayalım U ortanormal bir matris ve UT U = I),

AAT U = UΛUT U

AAT U = UΛ

Son ifadeye yakından bakalım, U’nun tek bir kolonuna, uk diyelim, odaklanacak
olursak, üstteki ifadeden bu sadece kolona yönelik nasıl bir eşitlik çıkartabilirdik?
Şöyle çıkartabilirdik,

(AAT )uk = σ2 uk

Bu ifade tanıdık geliyor mu? Özdeğer / özvektör klasik yapısına eriştik. Üstteki
eşitlik sadece ve sadece eğer uk , AAT ’nin özvektörü ve σ2 onun özdeğeri ise
geçerlidir. Bu eşitliği tüm U kolonları için uygulayabileceğimize göre demek ki
U’nun kolonlarında AAT ’nin özvektörleri vardır, ve AAT ’nin özdeğerleri A’nin
eşsiz değerlerinin karesidir.
Bu müthiş bir buluş. Demek ki AAT ’nin özektörlerini hesaplamak için A üzerinde
SVD uygulayarak U’yu bulmak ise yarar, kovaryans matrisini hesaplamak gerekli
değil. AAT özdeğerleri üzerinde büyüklük karşılaştırması için ise A’nin eşsiz
değerlerine bakmak yeterli!
Dikkat, daha önce kovaryansı AT A olarak tanımlamıştık, şimdi AAT ifadesi görüyoruz,
bir devrik uyuşmazlığı var, bu sebeple, aslında AT ’nin SVD’si alınmalı (altta
görüyoruz).

8
Örnek
İlk bölümdeki örneğe dönelim, ve özvektörleri SVD üzerinden hesaplatalım.

U,s,Vt = svd(meanless_data.T,full_matrices=False)
print U

[[-0.52045195 -0.85389096]
[-0.85389096 0.52045195]]

print np.dot(U.T,U)

[[ 1.00000000e+00 3.70255042e-17]
[ 3.70255042e-17 1.00000000e+00]]

Görüldüğü gibi aynı özvektörleri bulduk.


New York Times Yazıları Analizi
Şimdi daha ilginç bir örneğe bakalım. Bir araştırmacı belli yıllar arasındaki NY
Times makalelerinde her yazıda hangi kelimenin kaç kere çıktığının verisini toplamış
[1,2,3], bu veri 4000 küsur kelime, her satır (yazı) için bir boyut (kolon) olarak
kaydedilmiş. Bu veri nytimes.csv üzerinde ek bir normalize işleminden sonra,
onun üzerinde boyut indirgeme yapabiliriz.
Veri setinde her yazı ayrıca ek olarak sanat (arts) ve müzik (music) olarak etiketlenmiş,
ama biz PCA kullanarak bu etiketlere hiç bakmadan, verinin boyutlarını azal-
tarak acaba verinin ”ayrılabilir” hale indirgenip indirgenemediğine bakacağız.
Sonra etiketleri veri üstüne koyup sonucun doğruluğunu kontrol edeceğiz.
Bakmak derken veriyi (en önemli) iki boyuta indirgeyip sonucu grafikleyeceğiz.
İlla 2 olması gerekmez tabii, 10 boyuta indirgeyip (ki 4000 küsur boyuttan sonra
bu hala müthiş bir kazanım) geri kalanlar üzerinde mesela bir kümeleme algorit-
ması kullanabilirdik.
Ana veriyi yükleyip birkaç satırını ve kolonlarını gösterelim.

from pandas import *


import numpy.linalg as lin
nyt = read_csv ("nytimes.csv")
labels = nyt['class.labels']
print nyt.ix[:8,102:107]

after afternoon afterward again against


0 1 0 0 0 0
1 1 1 0 0 0
2 1 0 0 1 2
3 3 0 0 0 0
4 0 1 0 0 0
5 0 0 0 1 2
6 7 0 0 0 1
7 0 0 0 0 0
8 0 0 0 0 0

9
Yüklemeyi yapıp sadece etiketleri aldık ve onları bir kenara koyduk. Şimdi önemli
bir normalizasyon işlemi gerekiyor - ki bu işleme ters doküman-frekans ağırlıklandırması
(inverse document-frequency weighting -IDF-) ismi veriliyor - her dokümanda
aşırı fazla ortaya çıkan kelimelerin önemi özellikle azaltılıyor, ki diğer kelimelerin
etkisi artabilsin.
IDF kodlaması alttaki gibidir. Önce class.labels kolonunu atarız. Sonra ”her-
hangi bir değer içeren” her hücrenin 1 diğerlerinin 0 olması için kullanılan DataFrame
üzerinde astype(bools) işletme numarasını kullanırız, böylece aşırı büyük değerler
bile sadece 1 olacaktır. Bazı diğer işlemler sonrası her satırı kendi içinde tekrar
normalize etmek için o satırdaki tüm değerlerin karesinin toplamının karekökünü
alırız ve satırdaki tüm değerler bu karekök ile bölünür. Buna Öklitsel (Euclidian)
normalizasyon denebilir.
Not: Öklitsel norm alırken toplamın hemen ardından çok ufak bir 1e-16 değeri
eklememize dikkat çekelim, bunu toplamın sıfır olma durumu için yapıyoruz, ki
sonra sıfırla bölerken NaN sonucundan kaçınalım.

nyt2 = nyt.drop('class.labels',axis=1)
freq = nyt2.astype(bool).sum(axis=0)
freq = freq.replace(0,1)
w = np.log(float(nyt2.shape[0])/freq)
nyt2 = nyt2.apply(lambda x: x*w,axis=1)
nyt2 = nyt2.apply(lambda x: x / np.sqrt(np.sum(np.square(x))+1e-16), axis=1)
nyt2=nyt2.ix[:,1:] # ilk kolonu atladik
print nyt2.ix[:8,102:107]

afterward again against age agent


0 0 0.000000 0.000000 0.051085 0
1 0 0.000000 0.000000 0.000000 0
2 0 0.021393 0.045869 0.000000 0
3 0 0.000000 0.000000 0.000000 0
4 0 0.000000 0.000000 0.000000 0
5 0 0.024476 0.052480 0.000000 0
6 0 0.000000 0.008536 0.000000 0
7 0 0.000000 0.000000 0.000000 0
8 0 0.000000 0.000000 0.000000 0

Not: Bir diğer normalizasyon metotu

import pandas as pd

df = pd.DataFrame([[1.,1.,np.nan],
[1.,2.,0.],
[1.,3.,np.nan]])
print df
print df.div(df.sum(axis=0), axis=1)

0 1 2
0 1 1 NaN
1 1 2 0
2 1 3 NaN
0 1 2

10
0 0.333333 0.166667 NaN
1 0.333333 0.333333 NaN
2 0.333333 0.500000 NaN

SVD yapalım

nyt3 = nyt2 - nyt2.mean(0)


u,s,v = lin.svd(nyt3.T,full_matrices=False)
print s[:10]

[ 1.41676764 1.37161893 1.31840061 1.24567955 1.20596873 1.18624932


1.15118771 1.13820504 1.1138296 1.10424634]

print u.shape

(4430, 102)

SVD’nin verdiği u içinden iki özvektörü seçiyoruz (en baştakiler, çünkü Numpy
SVD kodu bu özvektörleri zaten sıralanmış halde döndürür), ve veriyi bu yeni
kordinata izdüşümlüyoruz.

proj = np.dot(nyt, u[:,:2])


proj.shape
plt.plot(proj[:,0],proj[:,1],'.')
plt.savefig('pca_4.png')

Şimdi aynı veriyi bir de etiket bilgisini devreye sokarak çizdirelim. Sanat kırmızı
müzik mavi olacak.

arts =proj[labels == 'art']


music =proj[labels == 'music']
plt.plot(arts[:,0],arts[:,1],'r.')
plt.plot(music[:,0],music[:,1],'b.')
plt.savefig('pca_5.png')

11
Görüldüğü gibi veride ortaya çıkan / özvektörlerin keşfettiği doğal ayırım, hakikaten
doğruymuş.
Metotun ne yaptığına dikkat, bir sürü boyutu bir kenara atmamıza rağmen geri
kalan en önemli 2 boyut üzerinden net bir ayırım ortaya çıkartabiliyoruz. Bu PCA
yönteminin iyi bir iş becerdiğini gösteriyor, ve kelime sayılarının makalelerin
içeriği hakkında ipucu içerdiğini ispatlıyor.
Not: Lineer Cebir notlarımızda SVD türetilmesine bakınca özdeğer/vektör mantığına
atıf yapıldığını görebiliriz ve akla şu gelebilir; ”özdeğer / vektör rutini işletmekten
kurtulalım dedik, SVD yapıyoruz, ama onun içinde de özdeğer/vektör hesabı
var”. Fakat şunu belirtmek gerekir ki SVD sayısal hesabını yapmanın tek yöntemi
özdeğer/vektör yöntemi değildir. Mesela Numpy Linalg kütüphanesi içindeki
SVD, LAPACK dgesdd rutinini kullanır ve bu rutin iç kodlamasında QR, ve bir
tür böl / istila et (divide and conquer) algoritması işletmektedir.
Kaynaklar
[1] Alpaydın, E., Introduction to Machine Learning, 2nd Edition
[2] Strang, G., Linear Algebra and Its Applications, 4th Edition
[3] Wood, Principal Component Analysis, Lecture,http://www.robots.ox.ac.
uk/˜fwood/teaching/index.html
[4] Cosma Shalizi, Advanced Data Analysis from an Elementary Point of View
[5] The New York Times Annotated Corpus, http://www.ldc.upenn.edu/Catalog/
CatalogEntry.jsp?catalogId=LDC2008T19
[6] Shalizi, Statistics 36-350: Data Mining Lecture,http://www.stat.cmu.edu/
˜cshalizi/350/
[7] Goodman, Risk and Portfolio Management with Econometrics, http://www.
math.nyu.edu/faculty/goodman/teaching/RPME/notes/Section3.pdf
[8] Collins, Introduction to Computer Vision, http://www.cse.psu.edu/˜rtc12/
CSE486/

12
[9] Weng, Candid Covariance-free Incremental Principal Component Analysis, https:
//pdfs.semanticscholar.org/4e22/d6b9650a4ff9ccc8c9b860442d162d559025.
pdf
[10] Bayramli, Lineer Cebir Ders 29

13
Dairesel Baz Fonksiyonları (Radial Basis Functions -RBF-), Yükseklik Verisi, Dağlar
Ara değerlemek (interpolation), yani elde olan veriyi kullanıp olmayan hakkında
tahmin yapmaya uğraşmak için çok boyutlu ortamda RBF iyi işleyen bir yaklaşım.
Belki de zihinde en rahat canlandırılabilecek örnek yeryüzünde dağlara ovalara
tekabül eden yükseklik (elevation) verilerini alarak onlara sürekli tepe fonksiy-
onları “uydurmak” böylece dağların nerede olduğunu sürekli şekilde saptamak.
Temsil etmek istediğimiz (ama bilmediğimiz) fonksiyon z = g(x, y) olarak gösterilebilecek
bir fonksiyon, bir düzlemde herhangi bir x, y noktasındaki yükseklik z. Bu fonksiyon-
dan örneklenerek alınmış verilerle onu yaklaşık olarak temsil etmek istiyoruz.
Düz verinin kendisini kullanmak bağlamında düşük çözünürlükte yükseklik verisi
ise yaramayabilir, mesela bir örneklem noktası dağın bir eteğinden diğeri öteki
yanındaki eteğinden alınmışsa bu dağ yok anlamına gelecektir. Peki o zaman
niye yükseklik verisinin geldiği yerden daha yüksek çözünürlüklü veri almıyoruz?
Bu hem erişim hem de tutacağı yer bağlamında pahalı olabilir. 1 derecelik enlem
/ boylam içinde, mesela 36-37 ve 32-33 arası diyelim, 100 metrelik çözünürlük
demek 0.001 derece değişimine tekabül eder, ve bu durumda 1 milyon veri nok-
tası alınması gerekecektir. Halbuki yükseklik verisinden yüzde 3 miktarında bile
[2] bir rasgele örneklem alırsak, bu noktalara RBF ile tepe fonksiyonları uydu-
rarak matematiksel, sürekli olan bir genel fonksiyon elde ederiz, ve uydurma iyi
işlerse artık istediğimiz çözünürlükte yükseklik verisi elde edebiliriz çünkü elim-
izdeki sürekli fonksiyona istediğimiz her nokta için yükseliğin ne olduğunu artık
hesaplattırabiliriz.
Bu örneği 3 boyutta herhangi bir başka veri için de düşünmek mümkün; ama
yükseklik verisinde daha rahat, her örneklem noktasına konulan tepeler ve on-
ların birleşimi bize pürüzsüz, sürekli bir engebe şekli verir. RBF baz fonksiyonları
Φ(x) = f(||x − c||) şeklindedir, f tepe, ya da farklı bir fonksiyon olabilir, || · || norm
fonksiyonudur, Öklitsel norm olabilir mesela.
Burada c üstüne baz fonksiyon konulan nokta, her örneklem veri noktası yani.
RBF eğitimi / uydurma metadolijisine göre herhangi bir veri noktası dışındaki
tüm diğer örneklem verileri o veri noktasının oluşumunu etkiler. Bu anormal
bir faraziye değil, bir dağın başında, ortasında, tepesinden alınmış örneklemler
varsa, mesela en alt ve en tepedeki veri ortadakini etkiler, yani o bağlantıyı,
ilişkiyi farzetmek normaldir. Orta nokta zirveyi tanımlayan fonksiyona belli bir
ağırlıkla bağlı, en alttakine başka bir şekilde bağlı, vs. Bu ağırlıkların ne olacağını
genel çözüm belirleyecektir. Eğer f için Gaussian’ımsı bir tepe fonksiyonu seçersek,
yeni gözlemin baz fonksiyonları ile arasındaki ilişki,

X
N
h(x) = wn × exp(−γkx − mi k2 )
i=1

olarak gösterilebilir, γ her noktanın etkisinin ne olduğunu dışarıdan ayarlamak


için genel bir sabit, ne kadar küçükse konulan tepe o kadar kenarlara yayılır, daha
büyük değerler daha noktasal olur. N tane baz fonksiyonu olacak, N tane mi , yi ,

1
ya da xi , yi verisine bakarak bu fonksiyonları bulacağız.
İki üstteki formüldeki x − c kullanımına dikkat, bu aslında “diğer noktaları” tem-
sil etmenin akıllıca bir yolu, c üzerinde x − c sıfır değerdedir, bu o noktayı tem-
sil için diğer noktalar üzerindeki bazların devreye girmesi gerektiğini modelde
söyler.
Her bazın etkisi wn ağırlığı üzerinden modele yansıtılır. Bu ağırlıkların ne olduğunu
bulmak, nihai genel fonksiyonu bulmuş olmak anlamına gelir. Farklı indislerle
tekrar belirtmek gerekirse her veri noktası için şu doğru olmalı,
Bu bize N tane veri noktası için N tane denklem ve N tane bilinmeyen sağlar. El-
deki (x1 , y1 ), ..., (xN , yN ) verileri ile w’yi bulmamızı sağlayacak regresyonu matris
formunda şöyle gösterebiliriz,

    
exp(−γkx1 − m1 k2 ) · · · exp(−γkx1 − mN k2 ) w1 y1
 exp(−γkx2 − m1 k2 ) · · · exp(−γkx2 − mN k2 )  w2   y2 
=
    
 .. . . ..  .. .. 
 . . .  .   . 
exp(−γkxN − m1 k2 ) · · · exp(−γkxN − mN k2 ) wN yN
| {z } | {z } | {z }
Φ w y

Tabii aslında verilerin kendisi RBF merkezleriyle aynı şey olduğu için şunu da
söyleyebilirdik,
    
exp(−γkx1 − x1 k2 ) · · · exp(−γkx1 − xN k2 ) w1 y1
 exp(−γkx2 − x1 k2 ) · · · exp(−γkx2 − xN k2 )  w2   y2 
=
    
 .. . . ..  .. .. 
 . . .  .   . 
2 2
exp(−γkxN − x1 k ) · · · exp(−γkxN − xN k ) wN yN
| {z } | {z } | {z }
Φ w y

Bu durumda w = Φ−1 y bize w ağırlıklarını, yani nihai çözümü verecektir.


Bir örnek üzerinde görelim,

from mpl_toolkits.mplot3d import Axes3D


import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
import matplotlib.pyplot as plt
import numpy.linalg as lin
from scipy.spatial.distance import cdist

Şimdi direk bilinen iki RBF kullanalım, böylece her şeyin nasıl biraraya geldiği
ileride daha iyi anlaşılır. Bizim tanımladığımız ağırlıklar, ve iki RBF ile şu şekilde
bir grafik oluşturabilirdik,

2
D = 50
gamma = 2.0

x = np.linspace(36,37,D)
y = np.linspace(32,33,D)

xx,yy = np.meshgrid(x,y)

xm = np.array([[36.06122449],
[36.71428571]])
ym = np.array([[32.67346939],
[32.32653061]])

X = np.hstack((xm,ym))

Phi = np.exp(-gamma*cdist(X,X,metric='euclid'))

w = np.array([[0.5],[0.5]])

xxx = xx.reshape(D*D)
yyy = yy.reshape(D*D)

a = np.vstack((xxx,yyy))
d = cdist(X,a.T)
d = np.exp(-gamma * d)
dd = np.dot(w.T,d)
znew = dd.reshape(D,D)

fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(xx, yy, znew, cmap=cm.coolwarm,linewidth=0, antialiased=False)
plt.savefig('linear_app88rbf_04.png')

Bu kod üzerinde oynayarak farklı γ, ağırlıklar w değerlerinin grafikte değişime


yol açtığı görülebilir.
Burada RBF ile aslında analitik bir fonksiyon yaratmış olduk. Bir kez ağırlıklarını
aldıktan sonra (RBF merkezlerini zaten biliyoruz) herhangi bir x, y değeri için o
noktadaki birleşik RBF sonucunu hesaplatabiliriz, mesela üstteki fonksiyon için

3
xm1 = [36.06, 32.67], xm2 = [36.71, 32.32], xtest = [36.16, 32.77]

y = 0.5 exp(−γ||xtest − xm1 ||2 ) + 0.5 exp(−γ||xtest − xm2 ||2 )

x_test = [36.16, 32.77]


w1 = 0.5; w2 = 0.5
d1 = (x_test[0]-xm[0])**2 + (x_test[1]-ym[0])**2
d2 = (x_test[0]-xm[1])**2 + (x_test[1]-ym[1])**2
y_new = w1*np.exp(-gamma * d1) + w2*np.exp(-gamma * d2)
print (y_new)

[0.6637959]

Gerçek dünya şartlarına yaklaşırsak; bu tür durumlarda çok daha fazla baz fonksiyon,
örneklem kullanılır, altta func fonksiyonu örneklem üretmek için kullanılacak,
normal şartlarda bu fonksiyonu bilmiyoruz, sadece ondan gelen örneklem veri-
lerini biliyoruz. Bir örnek amaçlı, belli bir şekli zorlamak için bunu yaptık.

np.random.seed(0)

def func(x, y):


s1 = 0.2; x1 = 36.5; y1 = 32.5
s2 = 0.4; x2 = 36.1; y2 = 32.8
g1 = np.exp( -4 *np.log(2) * ((x-x1)**2+(y-y1)**2) / s1**2)
g2 = np.exp( -2 *np.log(2) * ((x-x2)**2+(y-y2)**2) / s2**2)
return g1 + g2

D = 50
S = 100
gamma = 2.0

x = np.linspace(36,37,D)
y = np.linspace(32,33,D)

xx,yy = np.meshgrid(x,y)
zz = func(xx,yy)

fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(xx, yy, zz, cmap=cm.coolwarm,linewidth=0, antialiased=False)
plt.savefig('linear_app88rbf_01.png')

4
İki tane tepe var. Şimdi bu fonksiyondan rasgele örneklem alalım, ve Φ üzerinden
RBF ağırlıklarını hesaplayalım,

xxx = xx.reshape(D*D)
yyy = yy.reshape(D*D)
zzz = zz.reshape(D*D)

idx = np.random.choice(range(D*D),S)

xr = xxx[idx].reshape(S,1)
yr = yyy[idx].reshape(S,1)
zr = zzz[idx].reshape(S,1)
X = np.hstack((xr,yr))

Phi = np.exp(-gamma*cdist(X,X,metric='euclid'))

w = np.dot(lin.pinv(Phi),zr)

Ağırlıklarla fonksiyonu tekrar yaratmaya uğraşalım,

a = np.vstack((xxx,yyy))
d = cdist(X,a.T)
d = np.exp(-gamma * d)
dd = np.dot(w.T,d)
znew = dd.reshape(D,D)

fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(xx, yy, znew, cmap=cm.coolwarm,linewidth=0, antialiased=False)
plt.savefig('linear_app88rbf_02.png')

5
Pek optimizasyon yapmadık, ama orijinale benzidiği söylenebilir.
Not: cdist bir veri matrisindeki her satır ile her diğer satır arasında (tüm kombi-
nasyonlar) mesafe hesabı yapar.
Yeni tek bir veri noktası için

xnew = np.array([[36.5,32.5]])

print (np.multiply(w.T,np.exp(-gamma*lin.norm(X-xnew,axis=1))).sum())

0.6423871447150892

Bu yaklaşımı tüm dünyanın yeryüzü dağ, tepe veri tabanını oluşturmak için
kullanabiliriz. 1 milyon veri yerine onun yüzden 3’u üzerinden RBF işlettikten
sonra x, y, w değerlerini tutarız, gerisini atarız. Bu üç değer geniş bir bölgeyi
pürüzsüz fonksiyonlarla yaklaşık temsil etmenin en iyi yolu. Veri tabanı sadece
bu değerleri taşıyacak.
Bizim bu konuya girmemizin sebebi Google Elevation API ile aldığımız yükseklik
verilerini verimli şekilde kullanma ihtiyacı idi.
Simdi scipy ile ayni isleri yapalim,

np.random.seed(0)

S = 200

x = np.linspace(36,37,D)
y = np.linspace(32,33,D)

xx,yy = np.meshgrid(x,y)
znew = func(xx,yy)
xx = xx.reshape(D*D)
yy = yy.reshape(D*D)
znew = znew.reshape(D*D)

from scipy.interpolate import Rbf

6
rbfi = Rbf(xx,yy,znew,function='gaussian')
znew = rbfi(xx,yy)

xx = xx.reshape(D,D)
yy = yy.reshape(D,D)
znew = znew.reshape(D,D)

fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(xx, yy, znew, cmap=cm.coolwarm,linewidth=0, antialiased=False)
plt.savefig('linear_app88rbf_05.png')

Not: scipy ile bize döndürülen ve ara değerleme için direk çağırılabilen objeyi
gerekli her türlü bilgiyi içinde taşıyor. Yani modeli çıkartıp veriyi atıp, sadece bu
objeyi (mesela pickle ile) diskte saklayabiliriz, bu tek başına yeterlidir.
Modelleme scipy İle, Tekrar Yaratmak Elle Yazılan Fonksiyon İle
Bir diğer yaklaşım veriyi örneklemek, scipy ile RBF’leri yaratmak, ama sciy
parametrelerini kullanarak modeli kendimizin tekrar yaratması. Bunun değişik
sebepleri olabilir, belki veriyi modelleyen bir yükseklik fonksiyonu üzerinde otomatik
türev almak istiyoruz, ama scipy içindeki versiyon ile bunu yapamıyoruz. Ya da
motor kapağı altında nelerin olup bittiğini daha iyi anlamak istiyoruz.
Her neyse, yine iki tepeli ortamı yaratıyoruz,

from mpl_toolkits.mplot3d import Axes3D


import matplotlib.pyplot as plt
from matplotlib import cm

np.random.seed(0)

def func(x, y):


s1 = 0.2; x1 = 36.5; y1 = 32.5
s2 = 0.4; x2 = 36.1; y2 = 32.8
g1 = np.exp( -4 *np.log(2) * ((x-x1)**2+(y-y1)**2) / s1**2)
g2 = np.exp( -2 *np.log(2) * ((x-x2)**2+(y-y2)**2) / s2**2)
return g1 + g2

7
D = 100

x = np.linspace(36,37,D)
y = np.linspace(32,33,D)

xx,yy = np.meshgrid(x,y)
zz = func(xx,yy)

Ve grafiklemeyi yapıyoruz,

xx = xx.reshape(D,D)
yy = yy.reshape(D,D)
zz = func(xx,yy)

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.view_init(elev=29, azim=29)
surf = ax.plot_surface(xx, yy, zz, cmap=cm.coolwarm,linewidth=0, antialiased=False)
plt.savefig('linear_app88rbf_03.png')

Şimdi örneklem alıp RBF yaratalım,

from scipy.interpolate import Rbf

S = 50
np.random.seed(0)
idx = np.random.choice(range(D*D),S)
xr = xx.reshape(D*D)[idx].reshape(S,1)
yr = yy.reshape(D*D)[idx].reshape(S,1)
zr = zz.reshape(D*D)[idx].reshape(S,1)

rbfi = Rbf(xr,yr,zr,function='gaussian',epsilon=0.15)

Modelleme Gaussian RBF’ler üzerinden yapıldı. Üstteki rbfi değişkenini elde


edince artık herhangi bir x,y kordinatı üzerinde rbfi(x,y) ile ara değerleme ya-
parak modelin hesapladığı bir z değeri elde edebiliriz.
Peki arka planda bu hesaplama neye benziyor? Dokümantasyona bakınca
'gaussian': exp(-(r/self.epsilon)**2)

ifadesini görüyoruz, burada r yeni nokta ile bir RBF baz fonksiyonu arasındaki
mesafe. Bir test noktası ile üstteki RBF’leri (D*D tane) arasındaki mesafe şöyle
hesaplanabilir,

def dist_matrix(X, Y):


sx = np.sum(X**2, 1)
sy = np.sum(Y**2, 1)
D2 = sx[:, np.newaxis] - 2.0*X.dot(Y.T) + sy[np.newaxis, :]
D2[D2 < 0] = 0
D = np.sqrt(D2)

8
return D

test_1 = np.array([[36.0,32.0]])
test_1_dist = dist_matrix(test_1, rbfi.xi.T)
print (test_1_dist.shape)
print (test_1_dist[0][:10])

(1, 50)
[0.4229176 1.08927112 0.72276945 0.76827462 0.96299239 1.21064725
0.85578867 0.94970984 0.80965755 0.76794254]

O mesafeyi alıp eksi karesini hesaplayıp exp’ye vermek lazım. Tüm RBF’leri de
bir şekilde dahil etmek lazım tabii, o da hesaplanan ağırlıklar ile üstteki sonucu
çarpıp hepsini toplamakla olur. Gerekli parametreler rbfi içinde,

print (rbfi.epsilon)
print (rbfi.smooth)
print (rbfi.xi.shape)
print (rbfi.nodes.shape)

0.15
0.0
(2, 50)
(50,)

Ağırlıklar nodes, RBF merkezleri xi, epsilon genel bir pürüz parametresi. İki test
noktası üzerinde görelim, dikkat burada tüm RBF’ler gözönüne alınacak,

nodes = rbfi.nodes.reshape(1,len(rbfi.nodes))
def gaussian(r,eps): return np.exp(-(r/eps)**2)

def f_interp(newp, rbfi):


nodes = rbfi.nodes.reshape(1,len(rbfi.nodes))
newp_dist = dist_matrix(newp, rbfi.xi.T)
return np.dot(gaussian(newp_dist, rbfi.epsilon), nodes.T)

test_2 = np.array([[36.0,32.0],[36.1,31.9]])
print (f_interp(test_2,rbfi))

[[-0.00387063]
[-0.00337065]]

Şimdi iki tepeli fonksiyonu RBF’ler üzerinde yaratalım,

test_3 = np.column_stack((xx.ravel(), yy.ravel()))


znewnew = f_interp(test_3,rbfi).reshape(xx.shape)

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.view_init(elev=29, azim=29)
surf = ax.plot_surface(xx, yy, znewnew, cmap=cm.coolwarm,linewidth=0, antialiased=Fals
plt.savefig('linear_app88rbf_06.png')

9
RBF Türev ve Hessian Matrisi
Ana formülü hatırlayalım,

X
m
f(x) = βi φ(||x − xi ||)
i=1

ki β1 , ..., βm öyle seçiliyor ki

f(xi ) = F(xi ), i = 1, 2, ..., m

eşitliği tatmin edilsin. Burada F modellenen ana fonksiyondur, ve φ bizim seçtiğimiz


baz fonksiyondur. RBF’in türevi nedir? Analitik olarak hesaplayabiliriz,

∂g X
m
∂f(x) ∂ri
= βT = βi φ 0 (ri )
∂x ∂x i=1
∂x

öyle ki φ 0 (r) = dφ/ dr, ve

ri (x) = ||x − xi || =
p
(x − xi )T (x − xi ) (1)

Ayrıca

∂ri 1
= (x − xi )T
∂x ri (x)

Hepsi bir arada [4]

∂f(x) X βi φ 0 (ri )
m
= (x − xi )T
∂x i=1
ri (x)

10
Hessian’ı alttaki gibi hesaplayabiliriz [3]. [4]’teki formül

m
∂2 f(x) X φ 0 (ri )
 
0 00 ∂ri
= φ (ri )I + φ (ri ) − (x − xi ) (2)
∂x2 i=1
ri (x) ∂x

Türetmek için, radyal vektörler wk = (x − xk ) ∈ Rn tanımlanır, dikkat bunların


dwk = dx türevleri aynı. Şimdi vektörleri tek bir matriste birleştirelim,

Ω = w1 w2 . . . wm ∈ Rn×m
 

dΩ = dx dx . . . dx = dx 1T
 

Dikkat rj = kwj k öğelerinin kendisi r ∈ Rm vektörünün aynı zamanda ögesi.


Kartezyen baz vektörleri ek ∈ Rm üsttekini

wk = Ω ek , dx = dΩ ek , rj = eTj r

şeklinde yazmamıza izin veriyor. RBF’i öğesel bazda uygulayarak indisli toplam
notasyonundan kurtulmuş oluyoruz. Şimdi türevleri, diferansiyelleri

g = φ(r), g 0 = φ 0 (r), g 00 = φ 00 (r) ∈ Rm

dg = g 0 dr, dg 0 = g 00 dr ∈ Rm

ile yazabiliriz, ki öğesel bazlı Hadamard çarpımıdır.


Ayrıca vektörler köşegen matrisler arasında geçiş yapabilmek faydalıdır, ki bu
matrisleri büyük harfle belirteceğiz, mesela

R = Diag(r), G = Diag(g), G 00 = Diag(g 00 ) ∈ Rm×m

r = diag(R), g = diag(G), g 00 = . . .

r = R1, g = G1, g 00 = . . .

dg = G 0 dr, dg 0 = G 00 dr

ayrıca iş kolaylaştırması için alttaki tanım faydalı,

11
P = R−1 =⇒ PR = I, p r = 1

Şimdi ana ilişkiyi yazalım ve türevini alalım,

r r = diag(ΩT Ω)

2r dr = diag(ΩT dΩ + dΩT Ω) = 2 diag(ΩT dΩ)

R dr = diag(ΩT dx 1T ) = ΩT dx

dr = PΩT dx

∂r
= PΩT
∂x

ith bileşeni kontrol edersek (1) formülünü ortaya çıkartabileceğimizi görüyoruz,


demek ki doğru yoldayız,
 
∂r
eTi = eTi PΩT
∂x

∂ri 1 T T wTi
= ei Ω =
∂x ri kwi k

Model fonksiyonu (β b kullandık daha kısa)

f = bT g = b : g

İki nokta üst üste iz (trace) için Frobenius çarpım notasyonudur, mesela A : B =
Tr(AT B).
Şimdi Hessian

dJ = dΩ PG 0 B1 + ΩPdG 0 B1 + Ω dP G 0 B1

= dx 1T PG 0 B1 + ΩPB dg 0 − Ω(P dR P)G 0 B1

= dx (1T PG 0 B1) + ΩPB dg 0 − ΩPG 0 PB dr

12
= (G 0 : PB) dx + ΩPBG 00 dr − ΩPG 0 PB dr

 
= (G 0 : PB)I + ΩPB(G 00 − PG 0 )PΩT dx

∂J
H= = (G 0 : PB)I + ΩPB(G 00 − PG 0 )PΩT
∂x

 T   ∂r 

0
 ∂r 00 0
= (p b) : g I + BG − BPG
∂x ∂x

Pek öyle durmasa da bu formül (2) formülü ile aynı.


Akılda tutalım (R, G, B) matrisleri köşegen ve birbirleri ile sırabağımsız ilişkileri
var, ama Ω matrisi tam matris ve diğer matrislerle sırabağımsız ilişkiye giremiyor.
Autograd ile Gradyan ve Hessian
Otomatik türev üzerinden de üstteki hesapları yapabiliriz. Daha önceki kodlarda
iki dağlı veriden örneklem alıp RBF yaratmıştık, bu obje rbfi içinde, oradan de-
vam edersek,

import autograd.numpy as anp


import autograd

def dist_matrix(X, Y):


X = X.reshape(1, X.shape[0])
sx = anp.sum(X**2, 1)
sy = anp.sum(Y**2, 1)
D2 = sx[:, anp.newaxis] - 2.0*anp.dot(X,Y.T) + sy[anp.newaxis, :]
D = anp.sqrt(D2)
return D

nodes = rbfi.nodes.reshape(1,len(rbfi.nodes))
def gaussian(r,eps): return anp.exp(-(r/eps)**2)

def f_interp(newp):
nodes = rbfi.nodes.reshape(1,len(rbfi.nodes))
newp_dist = dist_matrix(newp, rbfi.xi.T)
return anp.dot(gaussian(newp_dist, rbfi.epsilon), nodes.T)

test_1 = anp.array([36.0,32.0])
test_1_dist = dist_matrix(test_1, rbfi.xi.T)
print ('f',f_interp(test_1))

grbf = autograd.grad(f_interp)
hrbf = autograd.hessian(f_interp)
print ('gradyan',grbf(test_1))
print ('hessian',hrbf(test_1))

13
f [[-0.00387063]]
gradyan [0.02331737 0.08191414]
hessian [[[[0.6466522 0.74921925]
[0.74921925 1.92847522]]]]

Rasgele Noktalar Seçmek


Fonksiyonu RBF ile temsil etmek için gereken Rasgele noktaları Hammersley
noktaları adı verilen bir rasgele sayı üretme tekniği ile seçmek mümkün, bu şekilde
son derece çetrefil fonksiyonlar bile az sayıda örneklem noktaları üzerinden tem-
sil edilebiliyor [5]. Mesela altta 10 tane bu tür noktayı 2 boyut için seçtik. Sayılar
0 ile 1 arasında ama gereken aralığa ölçeklenerek, toplanarak taşınabilir.

import hammer
print (hammer.hammersley([2,3],10))

[[0. 0. ]
[0.1 0. ]
[0.2 0.5 ]
[0.3 0.25 ]
[0.4 0.75 ]
[0.5 0.125 ]
[0.6 0.625 ]
[0.7 0.375 ]
[0.8 0.875 ]
[0.9 0.0625]]

Mesela

from mpl_toolkits.mplot3d import Axes3D

def peaks(x,y):
z = (3*(1-x)**2 * np.exp(-(x**2) - (y+1)**2)
- 10*(x/5 - x**3 - y**5) * np.exp(-x**2 - y**2)
- 1/3 * np.exp(-(x+1)**2 - y**2))
return(z)

n = 20
x = -3 + 6*hammer.hammersley([2,3],n)
z = peaks(x[:,0],x[:,1])
xx, yy = np.mgrid[-3:3:150j,-3:3:150j]
zz = peaks(xx,yy)
fig=plt.figure()
ax = fig.add_subplot(111,projection='3d')
ax.plot_surface(xx,yy,zz,rstride=1,cstride=1,color='c',alpha=0.3,linewidth=0)
ax.scatter(x[:,0],x[:,1],z,color='k',s=20)
plt.savefig('linear_app88rbf_07.png')

14
Görüldüğü gibi oldukca çetrefil bir fonksiyon bu,

 
2 −x21 −(−x22 +1)2 x1 3 5 2 2 1 2 2
f(x1 , x2 ) = 3(1 − x1 ) e − 10 − x1 − x2 e−x1 −x2 − e−(x1 +1) −x2
5 3

ama Hammersley tekniği ile kritik noktalarından örneklem alınabiliyor. [5]’te bu


teknik ile üretilen yeni fonsiyonun gerçeğine çok yakın olacağını görüyoruz, 20
tane nokta ile!
Kaynaklar
[1] Neto, Radial Basis Functions, http://www.di.fc.ul.pt/˜jpn/r/rbf/rbf.
html
[2] Pouderoux, Adaptive Hierarchical RBF Interpolation for Creating Smooth Digital
Elevation Models https://hal.archives-ouvertes.fr/hal-00308008/document
[3] Math Stackexchange, The Hessian of a Radial Basis Function, https://math.
stackexchange.com/questions/3417706/the-hessian-of-a-radial-
basis-function
[4] Mcdonald, Global and local optimization using radial basis function response surface
models, https://www.sciencedirect.com/science/article/pii/S0307904X0600200
[5] Kroese, Data Science and Machine Learning: Mathematical and Statistical Methods

15
Uygulama - Yağmur Yağış Verisi
Yağış verisini nasıl analiz ederiz? Bir örnek üzerinde görelim, [1]’den alınan Sin-
gapur yağış verisi,

import pandas as pd
df = pd.read_csv('rainfall.csv',index_col=0,parse_dates=['dt'])
df.columns = ['rain']
print (df)

rain
dt
2015-01-01 0.6
2015-01-02 0.0
2015-01-03 0.0
2015-01-04 0.0
2015-01-05 0.0
... ...
2022-01-27 0.0
2022-01-28 0.0
2022-01-29 0.0
2022-01-30 3.8
2022-01-31 0.0

[2588 rows x 1 columns]

Yağış verisi milimetre yağış miktarı olarak gösterilmiş. Bazı günlerde hiç yağış
yok, o günlerde su sıfır milimetre.
Bu verinin dağılımını görmek ilginç olabilir. Tabii her ayın yağış dağılımı farklı
olabilir, mesela altta Mart ayına bakalım,

x = df[df.index.month == 3]['rain']

Bu veriye ne tür dağılım uygun olur? Literatürde pek çok kullanım var. Bazıları
Gamma, bazıları Weibull diyor. Biz altta ikisini de test edeceğiz.

from scipy.stats import gamma


res = gamma.fit(df['rain'])
a,loc,scale = res
x.hist(density=True)
plt.ylim(0,0.4)
plt.plot(x, gamma.pdf(x,a,loc,scale),'r.')
plt.savefig('stat_176_app1_01.png')

1
Hem veriden gelen histogramı hem de olasılık yoğunluk fonksiyonunu aynı grafikte
gösterdik, kabaca ilk kontrol bu şekilde yapılabilir.
Daha detayli veriye olan uygunluğu kontrol için olasılık dağılımları arasında bir
yakınlık ölçüsü olan Kullback-Leibler mesafesini [2] kullanalım. Veri histogramı
ve tahmin edilen dağılım üzerinden üretilenlerin histogramı arasında mesafeyi
alttaki fonksiyon kl ile ölçebiliriz,

def kl(p, q):


return np.sum(p * np.log(p / q))

b = range(0,50)
eps = 1e-5
s = 4000
dh = np.histogram(df.rain, bins=b, density=True)[0]+eps

r1 = gamma.rvs(a,loc,scale,size=s)
h1 = np.histogram(r1, bins=b, density=True)[0]+eps
print ('Gamma', kl(h1, dh))

Gamma 0.288253598547884

Weibull Min adlı dağılım için de kontrol yapalım.

from scipy.stats import weibull_min


res = weibull_min.fit(df['rain'])
a,loc,scale = res
x.hist(density=True)
plt.ylim(0,0.4)
plt.plot(x, weibull_min.pdf(x,a,loc,scale),'r.')
plt.savefig('stat_176_app1_02.png')

2
r2 = weibull_min.rvs(a,loc,scale,size=s)
h2 = np.histogram(r2, bins=b, density=True)[0]+eps
print ('Weibull Min', kl(h2, dh))
Weibull Min 0.06795850872796806

Weibull Min daha yakın gözüküyor.


Olasılıklar
Veriye en uygun dağılımı bulduktan sonra dağılıma bazı sorular sorabiliriz, mesela
Mart ayında 10 mm’den daha fazla yağmur yağma olasılığı nedir? Bunun için ku-
mulatif dağılım fonksiyonu CDF lazım, ’daha büyük’ sorusu belli bir noktadan
sonraki, onun sağındaki alanı ima ediyor, o zaman cdf çağrısını 1’den çıkartırız,

print ('%0.3f' % (1-weibull_min.cdf(10, a,loc,scale)))


0.140

Az (ama sıfır olmayan) bir olasılık var.


Yağmur Günleri, Kuraklık Günleri
Bazı araştırmalar ne kadar yağdığını ayrı bir şekilde temsil edip, yagıp yağmadığı
aksiyonunu ayrı bir şekilde tahmin ediyor (bu durumda herhalde miktar dağılımlarını
sadece sıfırdan büyük değerler için kullanmak yeterli olur). Aksiyon derken
ne kadar yağarsa yağsın o gün ’yağdı’ olarak alınıyor, tersi ise ’yağmadı’. Bu
ayrıksal konumlar arasındaki geçişler, olasılıksal şekilde Markov Zincirleri ile
temsil edilebilir, bkz [4]’te gösterilen tek gün öncesine dayanarak yapılan tahmin
(ilk örnek). Örnek tek gün öncesini kullanmış. Fakat önceki iki günün tüm kom-
binasyonları yağma/yağmama üzerinden 4 konum ile temsil edilirse, o zaman
iki gün öncesi de hesaba dahil edilebilir.
Markov Zinciri hazırlığı, önceki gün yağış olup olmadığı D1, iki gün öncesi D2,
bugün D0.

df = pd.read_csv('rainfall.csv',index_col=0,parse_dates=['dt'])
df.columns = ['rain']

3
df['r1ago'] = df.rain.shift(1)
df['r2ago'] = df.rain.shift(2)
df['D1'] = df.apply(lambda row: (row.r1ago > 0.0).astype(int), axis=1)
df['D2'] = df.apply(lambda row: (row.r2ago > 0.0).astype(int), axis=1)
df['D0'] = df.apply(lambda row: (row.rain > 0.0).astype(int), axis=1)
pd.set_option('display.max_columns', None)
print (df)

rain r1ago r2ago D1 D2 D0


dt
2015-01-01 0.6 NaN NaN 0 0 1
2015-01-02 0.0 0.6 NaN 1 0 0
2015-01-03 0.0 0.0 0.6 0 1 0
2015-01-04 0.0 0.0 0.0 0 0 0
2015-01-05 0.0 0.0 0.0 0 0 0
... ... ... ... .. .. ..
2022-01-27 0.0 0.0 0.0 0 0 0
2022-01-28 0.0 0.0 0.0 0 0 0
2022-01-29 0.0 0.0 0.0 0 0 0
2022-01-30 3.8 0.0 0.0 0 0 1
2022-01-31 0.0 3.8 0.0 1 0 0

[2588 rows x 6 columns]

g = df.groupby(['D1','D2','D0']).size().reset_index()
print (g)

D1 D2 D0 0
0 0 0 0 633
1 0 0 1 269
2 0 1 0 268
3 0 1 1 228
4 1 0 0 244
5 1 0 1 253
6 1 1 0 253
7 1 1 1 440

Bu sayıları nasıl Markov matrisine çevireceğimizi anlamak için [1, sf. 193].
Konumları etiketlemek için alttakini yapalım,

pivot = g.pivot_table(index=['D1','D2'], columns='D0', aggfunc='mean')


pivot = pivot.reset_index()
print (pivot)

D1 D2 0
D0 0 1
0 0 0 633 269
1 0 1 268 228
2 1 0 244 253
3 1 1 253 440

Böylece konum 0,1,2,3 elde ettik. İki gün önce ve bir gün önce yağmadı kon-
umu 0, iki gün önce yağdı bir gün önce yağmadı konum 1, böyle gidiyor. Şimdi
dikkat, buradan bir Markov matrisi çıkartmak için geçiş hedefinde iki kolonlu

4
bir matris (yağdı,yağmadı) kullanamayız. O durumda matris 4 x 2 boyutunda
olurdu, bu bir Markov matrisi olmaz. Boyutlar 4 x 4 olmalı. Peki o zaman mesela
yağdı, yağmadı konumundan bugün yağdı konumuna nasıl geçeceğiz? Ufak bir
numara kullanarak; yağdı-yağmadı (2 etiketi) konumundan yağmadı-yağdı kon-
umuna (1 etiketi) geçişi yapacağız. Öyle ya, yağdı, yağmadı konumundan geçiş
yaptıktan sonra yeni bir gündeyiz, artık bir gün öncesi iki gun oncesi oldu, bugün
de ’yağdı’ durumu var, gelinen yer yağmadı-yağdı.
Olasılık verisini oluşturalım. Üstteki matristeki toplamları her satırın nihai toplamı
ile bölelim,

MC = np.array(pivot).astype(float)
probs = MC[:,[2,3]] / MC.sum(axis=1).reshape(4,1)
MC[:,[2,3]] = probs
MC = pd.DataFrame(MC)
MC.columns = ['D1','D2','norain','rain']
print (MC)
D1 D2 norain rain
0 0.0 0.0 0.701774 0.298226
1 0.0 1.0 0.539235 0.458753
2 1.0 0.0 0.489960 0.508032
3 1.0 1.0 0.364029 0.633094

Ufak bir matris olduğu için bu olasılıkları elle gerekli yerlere kodlayabiliriz,

MCfinal = np.zeros((4,4))
MCfinal[0,0] = MC.loc[0]['norain']
MCfinal[0,2] = MC.loc[0]['rain']
MCfinal[1,0] = MC.loc[1]['norain']
MCfinal[1,2] = MC.loc[1]['rain']
MCfinal[2,1] = MC.loc[2]['norain']
MCfinal[2,3] = MC.loc[2]['rain']
MCfinal[3,1] = MC.loc[3]['norain']
MCfinal[3,3] = MC.loc[3]['rain']
print (MCfinal)
[[0.70177384 0. 0.29822616 0. ]
[0.53923541 0. 0.45875252 0. ]
[0. 0.48995984 0. 0.50803213]
[0. 0.36402878 0. 0.63309353]]

Markov matrisini elde ettik. Artık bu matris üzerinde ek işlemler yapabiliriz.


Daha önce [4]’te bir, iki, hatta daha fazla adım sonrasını MZ ile tahmin ede-
bilme kabiliyeti işlendi, basit matris çarpımı ile bu yapılabiliyor. Eğer dün ve iki
gün önce yağmur yağdıysa (etiket 3), acaba önümüzdeki iki gün, üç gün içinde
yağmur yağma olasılığı nedir (aynı etiket)?

import numpy.linalg as lin


P2 = lin.matrix_power(MCfinal,2)
print (P2)
print ('')
P3 = lin.matrix_power(MCfinal,3)
print (P3)

5
[[0.49248652 0.14611884 0.20928732 0.15150847]
[0.3784213 0.22477031 0.16081411 0.23306102]
[0.2642037 0.18493831 0.22477031 0.32163185]
[0.19629721 0.23046426 0.16699912 0.40080741]]

[[0.42440661 0.15769583 0.21390475 0.20224372]


[0.38677028 0.16363337 0.21596908 0.22924815]
[0.28513653 0.22721167 0.16363337 0.31781358]
[0.26203074 0.22772829 0.16426702 0.33858949]]

print (MCfinal[3,3])
print (P2[3,3])
print (P3[3,3])

0.6330935251798561
0.40080741162465705
0.33858949401527094

Peki önümüzdeki üç günün herhangi birinde yağma olasılığı nasıl hesaplanır? Her
üç matris içinde yağdı-yağdı konumundan bu sefer yağmadı-yağdı konumuna
(etiket 1) geçiş olasıklarına bakarız, bu olasılıkları birbiri ile çarparız, böylece
sırasıyla üç gün hiç yağmama olasılığı elde edilir. 1 değerinden bu değeri çıkartınca
herhangi bir gün yağma olasılığı çıkar.

norain = MCfinal[3,1]*P2[3,1]*P3[3,1]
print (1-norain)

0.9808945929621133

Kaynaklar
[1] Meteorological Service Singapore, http://www.weather.gov.sg/climate-
historical-daily/
[2] Bayramli, Kullback-Leibler (KL) Mesafesi
[3] Ross, Introduction to Probability Models, 10th Ed
[4] Bayramli, Istatistik, Markov Zincirleri

6
Azar Azar İstatistik (Incremental Statistics)
Artımsal Ortalama (Mean)
Eldeki bir verinin yaş, boy, kilo gibi kolonlarını özetlemenin yollarından biri orta-
lama. Ortalama hesabının pek çok kütüphanede çağrısı var, mesela numpy.mean,
ya da Pandas Series.mean.

import pandas as pd
from io import StringIO

data = """
Name,Height
Ali,160
Veli,170
Musa,150
Mustafa,200
Cem,180
"""
df = pd.read_csv(StringIO(data),sep=',')
print (df)

Name Height
0 Ali 160
1 Veli 170
2 Musa 150
3 Mustafa 200
4 Cem 180

Ortalamayı alırsak

df['Height'].mean()

Out[1]: 172.0

Matematiksel olarak eldeki xi verisi için klasik ortalama hesabı x̄ basit, tüm değerleri
topla, ve değer sayısına böl,

1X
n
x̄ = xi (2)
n i=1

Kod ile

print (np.array(df.Height))
mean = df.Height.sum() / len(df)
print ('ortalama',mean)

[160 170 150 200 180]


ortalama 172.0

Şimdi artımsal hesabı düşünelim. Üstteki klasik hesabı yapmak için tüm veri-
leri toplamak gerekti, eğer ilk akla gelen yöntemle artımsal ortalama hesaplasak,

1
her adımda o ana kadar olan toplamı takip edip o ana kadar olan veri sayısına
bölmek gerekirdi, ama elde çok fazla veri varsa bu toplamın çok büyük rakamlara
erişmesi mümkündür, bu da taşma, veri hataları ortaya çıkartabilir.
Başka bir şekilde azar azar ortalama hesabı mümkün müdür acaba? Sadece or-
talamayı güncellesek, toplamlarla uğraşmasak? O ana kadar bakılan verinin or-
talaması fazla büyümez, ayrıca paralel işletim açısından azar azar işletim daha
ölçeklenebilir bir yaklaşımdır. Bu tür bir hesap için matematikte biraz değişim
yapmak lazım [3]. Üstteki toplam formülünde ilk n − 1 toplamını ayıralım,

X
n−1
!
1
x̄ = xi + xi (1)
n i=1

(2)’de görülen x̄ formülü ilk n verisinin ortalaması demiştik, o zaman ilk n − 1


verisinin ortalaması doğal olarak

Pn
xi
i=1
x̄n−1 =
n−1
Tekrar düzenlersek,

X
n
xi = (n − 1)x̄n−1
i=1

Bu formülü (1)’e sokalım,

1
x̄ = x̄n = ((n − 1)x̄n−1 + xn )
n
Sağ tarafı açalım,

nx̄n−1 − x̄n−1 + xn
x̄n =
n

nx̄n−1 xn − x̄n−1
x̄n = +
n n
İlk terimdeki n’ler iptal olur,

xn − x̄n−1
x̄n = x̄n−1 +
n
Yani bir sonraki ortalama hesabı için eldeki yeni veri xn ’den o ana kadar elde olan
ortalamayı çıkartıp n’ye bölüp bu sonucu önceki ortalamaya ekliyoruz. Böylece
sürekli daha ufak sayılarla uğraşıyoruz, patlama olmuyor ayrıca elde sürekli bir
ortalama hesabı oluyor.

2
barx = 160 # ilk degeri ilk ortalama olarak kullan
for n,xn in enumerate(np.array(df.Height)):
barx = barx + (xn - barx) / (n+1)
print (xn, barx)

160 160.0
170 165.0
150 160.0
200 170.0
180 172.0

Üstte görülen 172 değerine ulaştık.


Artımsal Standart Sapma (Incremental Standard Devation)
Varyans (standard sapmanın karesi) formülü ile başlayalım.

Pn
2 i=1 (xi − x̄n )2
s =
n−1

Her iki tarafı n − 1 ile çarpalım,

X
n
2
(n − 1)s = (xi − x̄n )2
i=1

Sağdaki değeri d2n diye tanımlayalım, bu cebirde ilerlerken bize faydalı olacak.

X
n
d2n = (xi − x̄n )2
i=1

Şimdi sağ tarafı açalım, ve üç ayrı toplam haline getirelim,

X
n
d2n = (x2i − 2xi x̄n + x̄2n )
i=1

X
n X
n X
n
d2n = x2i − 2xi x̄n + x̄2n
i=1 i=1 i=1

Sabitleri disari cikartabiliriz,

X
n X
n X
n
d2n = x2i − 2x̄n xi + x̄2n 1
i=1 i=1 i=1

Pn
Şimdi toplam ve ortalama x̄n arasındaki ilişki i=1 xi = nx̄n formülünden hareke-
tle, üstteki formülü

3
X
n X
n
d2n = x2i − 2x̄n · nx̄n + x̄2n 1
i=1 i=1

Pn
Ayrıca n = i=1 1 olduğu için

X
n
d2n = x2i − 2nx̄2n + nx̄2n
i=1

X
n
d2n = x2i − nx̄2n
i=1

Bu sonucu elde ettikten sonra onu ilk n − 1 için kullanalım,

X
n−1
d2n−1 = x2i − (n − 1)x̄2n−1
i=1

Son iki formülü birbirinden çıkartırsak,

X X
n n−1
!
d2n − d2n−1 = x2i − nx̄2n − x2i − (n − 1)x̄2n−1
i=1 i=1

X
n X
n−1
d2n − d2n−1 = x2i − nx̄2n − x2i + (n − 1)x̄2n−1
i=1 i=1

Alttaki eşitlikten hareketle,

X
n X
n−1
x2n = x2i − x2i
i=1 i=1

İki üstteki ifade biraz daha basitleştirilebilir,

d2n − d2n−1 = x2n − nx̄2n + (n − 1)x̄2n−1

Son terimi çarpınca

d2n − d2n−1 = x2n − nx̄2n + nx̄2n − x̄2n−1

Sıralamayı değiştirirsek,

d2n − d2n−1 = x2n − x̄2n−1 + nx̄2n−1 − nx̄2n

4
d2n − d2n−1 = x2n − x̄2n−1 + n(x̄2n−1 − x̄2n )

Temel cebirden biliyoruz ki a2 − b2 = (a − b)(a + b), bunu üstteki formüle uygu-


larsak,

d2n − d2n−1 = x2n − x̄2n−1 + n(x̄n−1 − x̄n )(x̄n−1 + x̄n )

[3] yazısından biliyoruz ki şöyle bir eşitlik mevcut n(x̄n−1 − x̄n ) = x̄n−1 − xn , onu
üstte kullanırsak,

d2n − d2n−1 = x2n − x̄2n−1 + (x̄n−1 − xn )(x̄n−1 + x̄n )

Tüm çarpımı yaparsak,

d2n − d2n−1 = x2n − x̄2n−1 + x̄2n−1 + x̄n x̄n−1 − x̄n−1 xn − x̄n xn

2’inci ve 3’uncu terim iptal olur,

d2n − d2n−1 = x2n − x̄n−1 xn − x̄n xn − x̄n x̄n−1

Yine temel cebirden biliyoruz ki

(x − a)(x − b) = x2 − bx − ax + ab

Bunu kullanarak iki ustteki formulu basitlestirebiliriz,

d2n − d2n−1 = (xn − x̄n )(xn − x̄n−1 )

Nihai sonuç,

d2n = d2n−1 + (xn − x̄n )(xn − x̄n−1 )

Biraz zaman aldı ama güzel bir artımsal formül elde ettik. Yeni d2n büyüklüğünü
bir önceki büyüklüğü kullanarak hesaplamak artık mümkün. Varyansı elde et-
mek için n − 1 ile bölmek yeterli,

d2n
s2n =
n−1
Onun karekökünü alınca da standart sapma elde edilir,

r
d2n
sn =
n−1

5
dns = 0; barx = 160
for n,xn in enumerate(np.array(df.Height)):
barxprev = barx
barx = barx + (xn - barx) / (n+1)
dns = dns + (xn - barx)*(xn-barxprev)
print (xn, dns/n)
160 nan
170 50.0
150 100.0
200 466.6666666666667
180 370.0

Eğer paket çağrısı ile hesaplarsak,

print (df.Height.var())
370.0

Aynı sonucu elde ettik.


Artımsal Ortalama ve Varyans Hesabı (Youngs ve Cramer Yöntemi)
[1]’de gördüğümüz varyans formülünü x kullanarak tekrar yazarsak,

X
n
1
X
n 2
S= x2i − xi
i=1
n i=1

Bu formülü her yeni veri geldikçe eldeki mevcut varyansı “güncelleme” amaçlı
olarak tekrar düzenleyebilirdik, böylece veri üzerinden bir kez geçmekle kalmayıp
en son bakılan veriye göre en son varyansı hesaplayabilmiş olurduk. Ortalama
için mesela her yeni veri bir toplama eklenebilir, ayrıca kaç veri noktası görüldüğü
hatırlanır, ve o andaki en son ortalama en son toplam bölü bu en son sayıdır.
P P
Fakat varyans için (5)’in bir problemi var, x2i ve ( xi )2 sayıları uygulamalarda
aşırı büyüyorlar, ve yuvarlama hataları (rounding errors) hataları ortaya çıkmaya
başlıyor. Eğer varyans küçük ise bu aşırı büyük sayılardaki tüm basamaklar
birbirini iptal eder, geriye hiçbir şey kalmaz. Bu hatalardan uzak durmak için
varyansı farklı bir artımsal yöntemle hesaplamak istiyoruz.
Youngs ve Cramer’in yöntemine göre [2, sf. 69] bu hesap şöyle yapılabilir. Tij ,
Mij ve Sij , veri noktaları xi xj arasındaki verileri kapsayacak şekilde sırasıyla
toplam, ortalama ve verinin karesinin toplamı olsun,

X
j
1 X
j
Tij = xk , Mij = , Sij = (xk − Mij )2
k=i
(j − 1 + 1) k=i

Güncelleme formülleri şunlardır,

T1,j = Ti,j−1 + xj

6
1
S1,j = Si,j−1 + (jxj − T1,j )2
j(j − 1)

ki T1,1 = x1 ve S1,1 = 0 olacak şekilde.


İspat

Xj 
1
 X j 
1
2
xk − T1j = xk − (T1,j−1 + xj )
k=1
j k=1
j

X
j 
1
 
1 1
2
= xk − T1,j−1 + T1,j−1 − xj
k=1
j−1 j(j − 1) j

1 1 1
çünkü j
= j−1
− j(j−1)

X
j−1 
1
2 
1
2
= xk − T1,j−1 xj − T1,j−1 +
k=1
j−1 j−1

X
j 
1

1 1

2 xk − T1,j−1 T1,j−1 − xj +
k=1
j−1 j(j − 1) j
 
1 1
j T1,j−1 − xj
j(j − 1) j

X
j−1 
1
2 
1
2 
2
 
1 1
2
= xk − T1,j−1 + xj − T1,j−1 1− +j T1,j−1 − xj
k=1
j−1 j−1 j j(j − 1) j

Pj−1 1
çünkü k=1 (xk − T
j−1 1,j−1
) =0

 2  
1 2 1
= S1,j−1 + xj − (T1j − xj ) 1− +
j−1 j j

1 2j − 1
= S1,j−1 + (jxj − T 1j )
(j − 1)2 j

Bu algoritma (5) algoritmasından daha stabil. Kod üzerinde görelim,

def incremental_mean_and_var(x, last_sum, last_var, j):


new_sum = last_sum + x
new_var = last_var + (1./(j*(j-1))) * (j*x - new_sum)**2
return new_sum, new_var

7
N = 10
arr = np.array(range(N)) # basit veri, 0..N-1 arasi sayilar
print arr
last_sum = arr[0]; last_var = 0.
for j in range(2,N+1):
last_sum,last_var = incremental_mean_and_var(arr[j-1], last_sum, last_var, j)

print 'YC =', last_var / N, 'Standart = ', arr.var()


print last_sum, arr.sum()

[0 1 2 3 4 5 6 7 8 9]
YC = 8.25 Standart = 8.25
45 45

Kaynaklar
[1] Bayramlı, Istatistik, Beklenti, Varyans, Kovaryans ve Korelasyon
[2] Weihs, Foundations of Statistical Algorithms With References to R Packages
[3] Nested Software, Calculating a Moving Average on Streaming Data, https://
nestedsoftware.com/2018/03/20/calculating-a-moving-average-
on-streaming-data-5a7k.22879.html
[4] Nested Software, Calculating Standard Deviation on Streaming Data, https://
nestedsoftware.com/2018/03/27/calculating-standard-deviation-
on-streaming-data-253l.23919.html

8
Ekler
Binom ve p İçin Maksimum Olurluk Tahmini [1]

Y
n Yn  
n x
L(p; x) = f(xi ; p) = p (1 − p)1−x
i=1 i=1
x

Log alalım

X
n  
n
log L(p; x) = log + x log p + (1 − x) log(1 − p)
i=1
x

n

p’ye göre türevi alalım, bu sırada kombinasyon ifadesi x
içinde p olmadığı için
o yokolacaktır,

∂ log L(p) x n−x


= −
∂p p 1−p

Maksimum değeri bulmak için sıfıra eşitleyelim ve p için çözelim,

x n−x
0= −
p 1−p

x n−x
=
p 1−p

p(n − x) = x(1 − p)

pn − px = x − px

pn = x

x
p=
n

Yani p için maksimum olurluk tahmini x/n.


Bernoulli dağılımı Binom dağılımına çok benzer, sadece onun baş kısmında kom-
binasyon ifadesi yoktur. Fakat o ifade p’ye göre türevde nasıl olsa yokolacağına
göre Bernoulli dağılımı için de tahmin edici aynıdır.
Bayes Usulü Güven Aralığı (Confidence Intervals)

1
Bayes ile bu hesabı yapmak için bir dağılımı baz almak lazım. Eğer sonuç olarak
bir tek sayı değil, bir dağılım elde edersek bu dağılım üzerinde güvenlik hesaplarını
yaparız. Mesela sonuç, sonsal dağılım (posterior) bir Gaussian dağılım ise, bu
dağılımın yüzde 95 ağırlığının nerede olduğu, ve nasıl hesaplandığı bellidir.
Bayes Teorisi

P(B | A)P(A)
P(A | B) =
P(B)

Veri analizi bağlamında diyelim ki deneyler yaparak tahmini olarak hesapla-


mak (estimate) istediğimiz bir parametre var, bu bir protonun kütlesi ya da bir
ameliyat sonrası hayatta kalma oranı olabilir. Bu durumlarda iki ayrı ”olaydan”
bahsetmemiz gerekir, B olayı spesifik bazı ölçümlerin elde edilmesi ”olayıdır”,
mesela ölçüm üç sayıdan oluşuyorsa, biz bir ölçümde spesifik olarak {0.2, 4, 5.4}
değerlerini elde etmişiz. İkinci olay bilmediğimiz parametrenin belli bir değere
sahip olması olacak. O zaman Bayes Teorisinin şu şekilde tekrar yazabiliriz,

P(parametre | veri) ∝ P(veri | parametre)P(parametre)

∝ işareti orantılı olmak (proportional to) anlamına geliyor. Böleni attık çünkü
o bir sabit (tamamen veriye bağlı, tahmini hesaplamak istediğimiz parametreye
bağlı değil). Tabii bu durumda sol ve sağ taraf birbirine eşit olmaz, o yüzden
eşitlik yerine orantılı olmak işaretini kullandık. Bu çerçevede ”belli bir sayısal
sabit çerçevesinde birbirine eşit (equal within a numeric constant)” gibi cümleler
de görülebilir.
Örnek
Diyelim ki bir bozuk para ile 10 kere yazı-tura attık, ve sonuç altta
THHHHTTHHH
Bu veriye bakarak paranın hileli olup olmadığını anlamaya çalışacağız. Bayes
ifadesini bu veriye göre yazalım,

P(p|{T H H H H T T H H H} ∝ P({T H H H H T T H H H|p)P(p)}

P(p) ifadesi ne anlama gelir? Aslında bu ifadeyi P([Dagilim] = p) olarak görmek


daha iyi, artık p parametresini bir dağılımdan gelen bir özgün değer olarak gördüğümüze
göre, o dağılımın belli bir p’ye eşit olduğu zamanı modelliyoruz burada. Her
halükarda P(p) dağılımını, yani onsel (prior) olasılığı bilmiyoruz, hesaptan önce
her değerin mümkün olduğunu biliyoruz, o zaman bu onsel dağılımı düz (flat)
olarak alırız, yani P(p) = 1.
P({T H H H H T T H H H|p) ifadesi göz korkutucu olabilir, ama buradaki her öğenin
bağımsız özdeşçe dağılmış (independent identically distributed) olduğunu görürsek,

2
ama bu ifadeyi ayrı ayrı P({T|p) ve P({H|p) çarpımları olarak görebiliriz. P({T|p) =
p ve P({H|p) = 1 − p olduğunu biliyoruz. O zaman

P(p|{7 Tura, 3 Yazı} ∝ p7 (1 − p)3

Grafiklersek,

Böylece p için bir sonsal dağılım elde ettik. Artık bu dağılımın yüzde 95 ağırlığının
nerede olduğunu rahatça görebiliriz / hesaplayabiliriz. Dağılımın tepe noktasının
p = 0.7 civarında olduğu görülüyor. Bir dağılımla daha fazlasını yapmak ta
mümkün, mesela bu fonksiyonu p’ye bağlı başka bir fonksiyona karşı entegre
etmek mümkün, mesela beklentiyi bu şekilde hesaplayabiliriz.
Onsel dağılımın her noktaya eşit ağırlık veren birörnek (uniform) seçilmiş olması,
yani problemi çözmeye sıfır bilgiden başlamış olmamız, yöntemin bir zayıflığı
olarak görülmemeli. Yöntemin kuvveti elimizdeki bilgiyle başlayıp onu net bir
şekilde veri ve olurluk üzerinden sonsal tek dağılıma götürebilmesi. Başlangıç ve
sonuç arasındaki bağlantı gayet net. Fazlası da var; ilgilendiğimiz alanı (domain)
öğrendikçe, başta hiç bilmediğimiz onsel dağılımı daha net, bilgili bir şekilde
seçebiliriz ve bu sonsal dağılımı da daha olması gereken modele daha yaklaştırabilir.
Moment
Olasılık matematiğinde ”moment üreten işlevler” olarak adlandırılan, başlangıçta
pek yararlı gibi gözükmesede bir takım matematiksel özellikleri olduğu için, is-
patlarda oldukça işe yarayan bir kavram vardır.
Her rasgele değişkenin bir dağılımı olduğunu biliyoruz. Her rasgele değişkenin
de ayrıca bir moment üreten fonksiyonu da vardır. Ayrıca, moment üreten fonksiyon
ile rasgele değişken arasında bire-bir olarak bir ilişki mevcuttur. ”Bu neye yarar?”
diye sorulabilir; Cevap olarak, mesela cebirsel olarak türete türete bir moment’e
geldiğimiz düşünelim, ve tekrar başka bir taraftan, başka bir formülden gene
türete türete tekrar aynı moment işlevine geliyorsak, bu demektir ki, iki taraftan
gelen rasgele değişkenler (ve tekabül eden dağılımları) birbirine eşittir. Bazı şartlarda
moment üreten işlevler ile cebir yapmak, dağılım fonksiyonlarından daha rahat

3
olmaktadır.
Her rasgele değişken için, moment üreten işlev şöyle bulunur.
X rasgele degiskenin moment ureten operasyonu
M(t) = E(etX ) olarak gösterilir
Ayrıksal operasyonlar için

X
M(t) = etx p(x)
x

Sürekli işlevler için


Z∞
M(t) = etx f(x) dx
−∞

Kuram
Gelelim yazımızın esas konusu olan kuramımıza.
Eğer X1 , X2 ...Xn bağımsız rasgele değişken ise, ve her değişkenin Mi (t) i = 1, 2, 3, ...n
olarak, öz olarak aynı olan birer moment üreten işlevi var ise, o zaman,

X
n
Y= aXi
i=1

açılımı

Y
n
My (t) = M(ai t)
i=1

olacaktır.
İspat

My (t) = E(etY = E(et(a1 X1 +a2 X2 +..+an Xn )

= E[exp(ta1 X1 ta2 X2 ... + tan Xn )]

= E[exp(ta1 X1 ) + exp(ta2 X2 ) + ... + exp(tan Xn )]

= E[exp(ta1 X1 )] + E[exp(ta2 X2 )] + ... + E[exp(tan Xn )]

4
Daha önce belirttiğimiz gibi

Mi (t) = E[exp(tXi )]

olduğuna göre ve t yerine tai koyulduğunu düşünelim

Y
n
My (t) = My (ai t)
i=1

olacaktır.
Bunu My (t) = (Mi (ai t))n şeklinde de gösterebiliriz.
Markov’un Eşitsizliği (Markov’s Inequality)
X bir negatif olmayan rasgele değişken olsun ve farz edelim ki E(X) mevcut [1].
O zaman her t > 0 için

E(X)
P(X > t) 6
t

doğru olmalıdır.
İspat
X > 0 olduğuna göre,

Z∞ Zt Z∞
E(X) = xf(x) dx = xf(x) dx + xf(x) dx =
0 0 t

Z∞ Z∞
> xf(x) dx > t f(x) dx = tP(X > t)
t t

Çebişev Eşitsizliği (Chebyshev’s Inequality)


Herhangi bir t değeri için,

σ2
P(|X − µ| > t) 6
t2
ve

1
P(|Z| > k) 6
k2

ki Z = (X − µ)/σ, ve E(X) = µ. Bunun bazı akılda kalabilecek ilginç sonuçları


P(|Z| > 2) < 1/4 ve P(|Z| > 3) < 1/9 olabilir.

5
İspat
1. Yöntem
Üstteki Markov’un eşitsizliğini kullanırız, oradan şu sonuca varırız,

E(X − µ)2 σ2
P(|X − µ| > t) = P(|X − µ|2 > t2 ) 6 =
t2 t2

İkinci kısım t = kσ kullanılarak elde edilebilir.


2. Yöntem
Olasılık matematiğinde, büyük sayılar kuramı adında anılan ve olasılık matematiğinin
belkemiğini oluşturan kuramı ispatlamak için, diğer bir kuram olan Çebişev eşitsizliğini
de anlamamız gerekiyor. Çebişev eşitsizliği bir rasgele değişken, onun ortala-
ması (beklentisi) ve herhangi bir sabit sayı arasındaki üçlü arasında bir ’eşitsizlik’
bağlantısı kurar, ve bu bağlantı diğer olasılık işlemlerimizde ispat verisi olarak
işimize yarar.
İspata başlayalım. Entegral ile olasılık hesabı yapmak için bize bir x uzayı lazım.

R = x : |x − µ| > t

Yani R uzayı, x ile ortalamasının farkının, t’den büyük olduğu bütün sayıların
kümesidir.
O zaman,
Z
P(|X − µ| > t) = f(x) dx
R

Dikkat edelim P(..) içindeki formül, küme tanımı ile aynı. O yüzden P() hesabı
ortada daha olmayan, ama varolduğu kesin bir dağılım fonksiyonu tanımlamış
da oluyor. Buna f(x) deriz. P()’in, f(x) fonksiyonunun R üzerinden entegral
olduğunu olasılığa giriş dersinden bilmemiz lazım.
Eger x ∈ R dersek o zaman

|x − µ|2
>1
t2

t’nin denkleme bu şekilde nereden geldiği şaşkınlık yaratabilir. Daha önce tanımlanan
şu ibareye dikkat edelim, x : |x − u| > t diye belirtmiştik. Bu ifadeyi değiştirerek,
yukarıdaki denkleme gelebiliriz.
Devam edersek, elimizdeki 1’den büyük bir değer var. Bu değeri kullanarak,
aşağıdaki tanımı yapmamız doğru olacaktır.

6
Z Z Z∞
(x − µ)2 (x − µ)2
f(x) dx 6 f(x) dx 6 f(x) dx
R R t2 −∞ t2

Ortadaki entegral niye birinci entegralden büyük? Çünkü orta entegraldeki f(x)dx
ibaresinden önce gelen kısmın, her zaman 1’den büyük olacağını belirttiğimize
göre, ikinci entegralin birinciden büyük olması normaldir, çünkü birinci entegral
f(x) olasılık dağılımına bağlı, entegral ise bir alan hesabıdır ve olasılık dağılımlarının
sonsuzlar arasındaki entegrali her zaman 1 çıkar, kaldı ki üstteki x’in uzayını
daha da daralttık.
Evet...Üçüncü entegral ispata oldukça yaklaştı aslında. Standart sapma işaretini
hala ortada göremiyoruz, fakat son entegraldeki ibare standart sapma değerini
zaten içeriyor. Önce daha önceki olasılık natematiği bilgimize dayanarak, stan-
dart sapmanın tanımını yazıyoruz. Dikkat edelim, bu ibare şu anki ispatımız
dahilinden değil, haricinden önceki bilgimize dayanarak geldi. Standart sap-
manın tanımı şöyledir.
Z∞
2
σ = (x − µ)2 f(x) dx
−∞

O zaman

Z∞
σ2 (x − µ)2
= f(x) dx
t2 −∞ t2

yani

Z Z∞
σ2 (x − µ)2
f(x) dx 6 2 = f(x) dx
R t −∞ t2
R
ki R f(x) dx zaten P(|X − µ| > t) olarak tanımlanmıştı.
Örnek
Diyelim ki bir tahmin edicimiz var, onu test etmek istiyoruz, bu bir yapay sinir
ağı (YSA) olabilir, ve elimizde n tane test verisi var. Eğer tahmin edici, yani YSA,
hatalı ise Xi = 1 olsun, haklı isePXi = 0 olsun. O zaman gözlenen hata oranı
(observed error rate) Xn = n−1 n i=1 Xi olacaktır. Rasgele değişken çıktılarına
bakarak bunu bir p’si bilinmeyen bir Bernoulli dağılımından geliyormuş gibi
kabul edebileceğimizi görebiliriz. İstediğimiz gerçek -ama bilinmeyen- p hakkında
irdeleme yapmak. Xn ’in gerçek p’nin  yakınında olmama olasılığı nedir?
Bernoulli’lerin özelliklerinden biliyoruz ki

V(Xn ) = V(X1 )/n = p(1 − p)/n

Çebişev uygulayınca,

7
V(Xn ) p(1 − p) 1
P(|Xn − p| > ) 6 = 6
2 n2 4n2

Hatırlarsak Bernoulli için E(X) = p. Son geçiş mümkün oldu çünkü her p için
p(1 − p) 6 41 olmak zorundadır. Öyle değil mi? p(1 − p)’nin alabileceği en büyük
değer p = 1/2 içindir, bundan farklı her p değeri 1/4’ten küçük bir çarpım verir,
mesela p = 1/3 için 1/3 · 2/3 = 2/9.
O zaman, ve diyelim ki  = .2 ve n = 100 için 0.0625 sınırını elde ederiz.
Hoeffding’in Eşitsizliği
Bu eşitsizlik Markov’un eşitsizliğine benziyor, ama daha keskin sonuçlar vere-
biliyor, yani ufak güven aralıkları elde edebiliyoruz, ki bu daha fazla kesinlik
demektir. Bu eşitsizliği iki bölüm olarak vereceğiz,
Y1 , Y2 , .., Yn bağımsız gözlemler olsunlar, ki E(Yi ) = 0 ve ai 6 Yi 6 bi doğru
olacak şekilde. O zaman herhangi bir t > 0 için
1. Teori

X
n Y
n 
−t t2 (bi −ai )2 /8
P Yi >  6 e e
i=1 i=1

2. Teori
X1 , .., Xn ∼ Bernoulli(p) olsun. O zaman herhangi bir  > 0 icin

2
P(|Xn − p| > ) 6 2e−2n
Pn
doğru olmalıdır ki, daha önce gördüğümüz gibi, Xn = n−1 i=1 Xi olacak şekilde.
İspat için bkz [1, sf. 67].
Örnek
Diyelim ki X1 , .., Xn ∼ Bernoulli(p). n = 100 ve  = .2 olsun. Çebişev esitsizligi
ile

P(|Xn − p| > ) 6 0.0625

elde etmiştik. Hoeffding’e göre

2
P(|Xn − p| > ) 6 2e−2(100)(.2) = 0.00067

elde ederiz, ki bu Cebisev’den gelen 0.0625’e göre çok daha ufak bir değerdir.
Jensen’in Esitsizligi (Jensen’s Inequality)

8
Teori
Eğer g fonksiyonu dışbükey (convex) ise o zaman

Eg(X) > g(E(X))

İçbukey için tam tersi geçerli.


Teorinin sözel olarak söylediği eğer f fonksiyonu dışbükey ise verinin ortalaması
(beklentisi) üzerinde f işletmek, o verinin f değerlerinin ortalaması ile aynı ol-
muyor, daha doğrusu ikinci büyüklük birinci için bir alt sınır oluşturuyor, birinci
en az ikinci kadar.
İspat
Bir L(x) = a + bx çizgisi hayal edelim, bu çizgi g(x)’e tam E(X) noktasında teğet
olsun [1, sf. 66]. g dışbükey olduğu için her noktada L(x) çizgisi üzerinde olması
garanti,

O zaman

E(g(X)) > E(L(X))

E(L(X)) formülünü açalım,

E(L(X)) = E(a + bX) = a + bE(X)

Birinci geçiş basit beklenti matematiği. Son formül L(x)’in E(X) üzerindeki formu
olurdu, o zaman

a + bE(X) = L(E(X))

diyebiliriz.
Şimdi hatırlıyoruz ki teğet çizgi g ile tam E(X) noktasında kesişiyor, o noktada
değerleri aynı yani, o zaman

9
L(E(X)) = g(E(X))

Demek ki

E(g(X)) > E(L(X)) = g(E(X))

Kısaca

E(g(X)) > g(E(X))

Teori ispatlanmış oldu.


Aslında Jensen Eşitsizliğinin daha geniş bir hali ve yorumlaması var, eğer g(x)
genel olarak gayri lineer ise (sadece dışbükey değil) o zaman g(x)’in ortalaması
x ortalamalarının üzerindeki g hesabına eşit değildir [2]. Bir alt sınır değil di-
rek eşitsizlikten bahsediyoruz. Bu yorumlamanın da pek çok yerde uygulaması
vardır, bu ifadenin ispatı için İstatistik kaynaklarına başvurulabilir.
Kaynaklar
[1] Wasserman, All of Statistics
[2] Denny, The fallacy of the average: on the ubiquity, utility and continuing novelty
of Jensen’s inequality https://journals.biologists.com/jeb/article/
220/2/139/18635/The-fallacy-of-the-average-on-the-ubiquity-
utility

10
z-Tablosu
Nasıl okunur? Z-değeri -0.8994 için z kolonundan aşağı inilir, ve -0.8 bulunur,
x.x9xx yani 9 için .09 kolonuna gidilir ve bu kesişmedeki değer okunur, .1867,
yuvarlanarak .19 da kabul edilebilir.

z .00 .01 .02 .04 .05 .06 .07 .08 .09


-3.4 .0003 .0003 .0003 .0003 .0003 .0003 .0003 .0003 .0003 .0002
-3.3 .0005 .0005 .0005 .0004 .0004 .0004 .0004 .0004 .0004 .0003
-3.2 .0007 .0007 .0006 .0006 .0006 .0006 .0006 .0005 .0005 .0005
-3.1 .0010 .0009 .0009 .0009 .0008 .0008 .0008 .0008 .0007 .0007
-3.0 .0013 .0013 .0013 .0012 .0012 .0011 .0011 .0011 .0010 .0010
-2.9 .0019 .0018 .0018 .0017 .0016 .0016 .0015 .0015 .0014 .0014
-2.8 .0026 .0025 .0024 .0023 .0023 .0022 .0021 .0021 .0020 .0019
-2.7 .0035 .0034 .0033 .0032 .0031 .0030 .0029 .0028 .0027 .0026
-2.6 .0047 .0045 .0044 .0043 .0041 .0040 .0039 .0038 .0037 .0036
-2.5 .0062 .0060 .0059 .0057 .0055 .0054 .0052 .0051 .0049 .0048
-2.4 .0082 .0080 .0078 .0075 .0073 .0071 .0069 .0068 .0066 .0064
-2.3 .0107 .0104 .0102 .0099 .0096 .0094 .0091 .0089 .0087 .0084
-2.2 .0139 .0136 .0132 .0129 .0125 .0122 .0119 .0116 .0113 .0110
-2.1 .0179 .0174 .0170 .0166 .0162 .0158 .0154 .0150 .0146 .0143
-2.0 .0228 .0222 .0217 .0212 .0207 .0202 .0197 .0192 .0188 .0183
-1.9 .0287 .0281 .0274 .0268 .0262 .0256 .0250 .0244 .0239 .0233
-1.8 .0359 .0351 .0344 .0336 .0329 .0322 .0314 .0307 .0301 .0294
-1.7 .0446 .0436 .0427 .0418 .0409 .0401 .0392 .0384 .0375 .0367
-1.6 .0548 .0537 .0526 .0516 .0505 .0495 .0485 .0475 .0465 .0455
-1.5 .0668 .0655 .0643 .0630 .0618 .0606 .0594 .0582 .0571 .0559

11
-1.4 .0808 .0793 .0778 .0764 .0749 .0735 .0721 .0708 .0694 .0681
-1.3 .0968 .0951 .0934 .0918 .0901 .0885 .0869 .0853 .0838 .0823
-1.2 .1151 .1131 .1112 .1093 .1075 .1056 .1038 .1020 .1003 .0985
-1.1 .1357 .1335 .1314 .1292 .1271 .1251 .1230 .1210 .1190 .1170
-1.0 .1587 .1562 .1539 .1515 .1492 .1469 .1446 .1423 .1401 .1379
-0.9 .1841 .1814 .1788 .1762 .1736 .1711 .1685 .1660 .1635 .1611
-0.8 .2119 .2090 .2061 .2033 .2005 .1977 .1949 .1922 .1894 .1867
-0.7 .2420 .2389 .2358 .2327 .2296 .2266 .2236 .2206 .2177 .2148
-0.6 .2743 .2709 .2676 .2643 .2611 .2578 .2546 .2514 .2483 .2451
-0.5 .3085 .3050 .3015 .2981 .2946 .2912 .2877 .2843 .2810 .2776
-0.4 .3446 .3409 .3372 .3336 .3300 .3264 .3228 .3192 .3156 .3121
-0.3 .3821 .3783 .3745 .3707 .3669 .3632 .3594 .3557 .3520 .3483
-0.2 .4207 .4168 .4129 .4090 .4052 .4013 .3974 .3936 .3897 .3859
-0.1 .4602 .4562 .4522 .4483 .4443 .4404 .4364 .4325 .4286 .4247
0.0 .5000 .4960 .4920 .4880 .4840 .4801 .4761 .4721 .4681 .4641

12
z .00 .01 .02 .04 .05 .06 .07 .08 .09
0.0 .5000 .5040 .5080 .5120 .5160 .5199 .5239 .5279 .5319 .5359
0.1 .5398 .5438 .5478 .5517 .5557 .5596 .5636 .5675 .5714 .5753
0.2 .5793 .5832 .5871 .5910 .5948 .5987 .6026 .6064 .6103 .6141
0.3 .6179 .6217 .6255 .6293 .6331 .6368 .6406 .6443 .6480 .6517
0.4 .6554 .6591 .6628 .6664 .6700 .6736 .6772 .6808 .6844 .6879
0.5 .6915 .6950 .6985 .7019 .7054 .7088 .7123 .7157 .7190 .7224
0.6 .7257 .7291 .7324 .7357 .7389 .7422 .7454 .7486 .7517 .7549
0.7 .7580 .7611 .7642 .7673 .7704 .7734 .7764 .7794 .7823 .7852
0.8 .7881 .7910 .7939 .7967 .7995 .8023 .8051 .8078 .8106 .8133
0.9 .8159 .8186 .8212 .8238 .8264 .8289 .8315 .8340 .8365 .8389
1.0 .8413 .8438 .8461 .8485 .8508 .8531 .8554 .8577 .8599 .8621
1.1 .8643 .8665 .8686 .8708 .8729 .8749 .8770 .8790 .8810 .8830
1.2 .8849 .8869 .8888 .8907 .8925 .8944 .8962 .8980 .8997 .9015
1.3 .9032 .9049 .9066 .9082 .9099 .9115 .9131 .9147 .9162 .9177
1.4 .9192 .9207 .9222 .9236 .9251 .9265 .9279 .9292 .9306 .9319
1.5 .9332 .9345 .9357 .9370 .9382 .9394 .9406 .9418 .9429 .9441
1.6 .9452 .9463 .9474 .9484 .9495 .9505 .9515 .9525 .9535 .9545
1.7 .9554 .9564 .9573 .9582 .9591 .9599 .9608 .9616 .9625 .9633
1.8 .9641 .9649 .9656 .9664 .9671 .9678 .9686 .9693 .9699 .9706
1.9 .9713 .9719 .9726 .9732 .9738 .9744 .9750 .9756 .9761 .9767
2.0 .9772 .9778 .9783 .9788 .9793 .9798 .9803 .9808 .9812 .9817
2.1 .9821 .9826 .9830 .9834 .9838 .9842 .9846 .9850 .9854 .9857
2.2 .9861 .9864 .9868 .9871 .9875 .9878 .9881 .9884 .9887 .9890
2.3 .9893 .9896 .9898 .9901 .9904 .9906 .9909 .9911 .9913 .9916
2.4 .9918 .9920 .9922 .9925 .9927 .9929 .9931 .9932 .9934 .9936
2.5 .9938 .9940 .9941 .9943 .9945 .9946 .9948 .9949 .9951 .9952
2.6 .9953 .9955 .9956 .9957 .9959 .9960 .9961 .9962 .9963 .9964
2.7 .9965 .9966 .9967 .9968 .9969 .9970 .9971 .9972 .9973 .9974
2.8 .9974 .9975 .9976 .9977 .9977 .9978 .9979 .9979 .9980 .9981

13
2.9 .9981 .9982 .9982 .9983 .9984 .9984 .9985 .9985 .9986 .9986
3.0 .9987 .9987 .9987 .9988 .9988 .9989 .9989 .9989 .9990 .9990
3.1 .9990 .9991 .9991 .9991 .9992 .9992 .9992 .9992 .9993 .9993
3.2 .9993 .9993 .9994 .9994 .9994 .9994 .9994 .9995 .9995 .9995
3.3 .9995 .9995 .9995 .9996 .9996 .9996 .9996 .9996 .9996 .9997
3.4 .9997 .9997 .9997 .9997 .9997 .9997 .9997 .9997 .9997 .9998
Kaynaklar
[1] Gullickson, Sociology G4075: Introduction to Social Data Analysis II, https://
web.archive.org/web/20160312151715/http://pages.uoregon.edu/
aarong/teaching/G4075_Outline/node13.html

14
Yunan Harfleri

You might also like