Thursday, July 31, 2014

ggplot

R dilinde cokca kullanilan ggplot2 kutuphanesi nihayet Python'a tasinmaya baslandi. Kurmak icin,

sudo pip install ggplot

Konu hakkinda guzel bir yazi

Matplotlib ile cok zor yapilan isler ggplot2 ile rahat yapilabiliyor. Kutuphanenin cok ciddi takipcileri / hayranlari var, ozellikle daha once R ile kodlama yapmis olan istatistikciler ve bilimciler. Bu kisilerin cok sevdigi bir ozellik bir grafigin kesit kesit (layer by layer) ust uste konarak tasarlanabilmesi. Bu yaklasima gore grafik noktalari bir kesit, yazilari bir baska kesit, eksen boyutlari bir baska kesit olabilir mesela, ve bu ekler hep benzer cagrilarla yapilir (burada + isareti kullanilmis olmasi raslanti degil). Kutuphane, Leland Wilkinson'un Grafigin Grameri adli yaklasiminin kodlanmis halidir; yani grafiklemenin dili boyle olmalidir seklinde bir yaklasimdir bu -- oldukca iddialidir.

Ornek,

from ggplot import *
print mtcars[:3]

            name   mpg  cyl  disp   hp  drat     wt   qsec  vs  am  gear  carb
0      Mazda RX4  21.0    6   160  110  3.90  2.620  16.46   0   1     4     4
1  Mazda RX4 Wag  21.0    6   160  110  3.90  2.875  17.02   0   1     4     4
2     Datsun 710  22.8    4   108   93  3.85  2.320  18.61   1   1     4     1

[3 rows x 12 columns]


Ilk grafik

from ggplot import *
p = ggplot(mtcars, aes('mpg', 'qsec'))
p = p + geom_point(colour='steelblue') + \
     scale_x_continuous(breaks=[10,20,30], \
     labels=["horrible", "ok", "awesome"])
plt = p.draw()
plt.show()



Goruldugu gibi her sey kesit kesit ekleniyor. Histogram

p = ggplot(aes(x='carat'), data=diamonds)
gg = p + geom_histogram() + ggtitle("Histogram of Diamond Carats") + labs("Carats", "Freq")

plt = gg.draw()
plt.show()



Histogram ve onun uzerine eklenmis egri

p = ggplot(aes(x='wt'),mtcars) + geom_histogram() + geom_density()



Beyzbol verisi uzerinde

df = pd.read_csv("baseball-pitches-clean.csv")
df = df[['pitch_time', 'inning', 'pitcher_name', 'hitter_name', 'pitch_type',
         'px', 'pz', 'pitch_name', 'start_speed', 'end_speed', 'type_confidence']]
print df.head()

                  pitch_time  inning       pitcher_name    hitter_name  \
0  2013-10-01 20:07:43 -0400       1  Francisco Liriano  Shin-Soo Choo  
1  2013-10-01 20:07:57 -0400       1  Francisco Liriano  Shin-Soo Choo  
2  2013-10-01 20:08:12 -0400       1  Francisco Liriano  Shin-Soo Choo  
3  2013-10-01 20:08:31 -0400       1  Francisco Liriano  Shin-Soo Choo  
4  2013-10-01 20:09:09 -0400       1  Francisco Liriano   Ryan Ludwick  

  pitch_type     px     pz pitch_name  start_speed  end_speed  type_confidence 
0          B  0.628  1.547   Fastball         93.2       85.3            0.894 
1          S  0.545  3.069   Fastball         93.4       85.6            0.895 
2          S  0.120  1.826     Slider         89.1       82.8            0.931 
3          S -0.229  1.667     Slider         90.0       83.3            0.926 
4          B -1.917  0.438     Slider         87.7       81.6            0.915 

[5 rows x 11 columns]

Grafikleme

p = ggplot(aes(x='start_speed'), data=df) + geom_histogram() + facet_wrap('pitch_name')
plt = p.draw()
plt.show()



Monday, July 28, 2014

Seyrek 1-Hot Kodlamasi

Bu konu tekrar tekrar ortaya cikiyor. Amac kategorik verilerin hizli sekilde "her ayri kolon+kategori ayri bir kolonda olacak sekilde" bir matris ortamina gecirilmesi ve numerik olarak temsil edilebilmesi. Mesela

pop;state;year
1.5;Ohio;2000
1.7;Ohio;2001
3.6;Ohio;2002
2.4;Nevada;2001
2.9;Nevada;2002


verisinde state=Ohio icin ayri bir kolon olacak ve bu kolon '1' degerine sahip olacak. Tabii bu kombinasyonu icermeyen diger satirlar bu noktada '0' degeri tasiyacak, ki  seyrek matris ortaminda o deger bellege bile alinmayacaktir.

Bu isi Pandas uzerinden yapmak orta derece buyuk veride bile muthis yavastir. Alttaki kod parcasi bu isi CSV'yi acip satir satir islerken cok daha hizli yapiyor, hic Pandas'i kullanmadan. Girdi CSV, cikti seyrek matris;

from scipy.io import mmwrite
import csv, pandas as pd, os
import scipy.sparse as sps
import numpy as np

mat_keys = {}
cat_cols = ['state']

N  = num_lines = sum(1 for line in open('in.csv')) - 1
D = 10 # tahmin, buyukce bir sayi

A = sps.lil_matrix((N,D))

with open('in.csv', "rb" ) as theFile:
    reader = csv.DictReader(theFile, delimiter=';')
    for i,line in enumerate(reader):
        for col in cat_cols:
            new_col = 'cat_%s_%s' % (col,line[col])
            if new_col not in mat_keys: mat_keys[new_col] = len(mat_keys)
            A[i, mat_keys[new_col]] = 1.0


Kodun yaptigi her kombinasyon icin bir kolon indis degeri hesaplamak, ve o matris noktasina 1 degeri vermek. Nihai matriste bu "yeni kolonlarin" hangi kolon indisine tekabul ettigini hatirlamamiz iyi olur, o sebeple o eslemeyi tasiyan sozluk bir yere mesela pickle olarak kaydedilebilir.

Kod islemi tamamlaninca A icinde kategorik kolonlarin numerik kodlanmis hali olacak. Matris sps.lil_matrix((N,D)) ile yaratildi, D sayisi buyukce bir sayi olarak yaklasik tahmin edildi, nasil olsa seyrek ortamda hangi deger verirseniz verin bellekte o olcude yer "onceden ayirilmaz"; seyrek matrislerin onemli bir avantaji budur zaten.

Indis degeri vermek icin yeni bir kombinasyonun mat_keys icinde olup olmadigina bakiyoruz, yoksa yeni indis degeri sozlukte olan degerlerin sayisi olacak, 10 tane deger var ise, yeni indis 10 (dikkat 10+1 degil cunku 0-baslangicli indis erisimi kullaniyoruz, C dilinde oldugu gibi), mat_keys[new_col] = len(mat_keys) bu isi yapiyor. Bu ucuz bir sekilde tekil (unique) deger kodlamanin bir yolu.

Her kolon+kategori eslemesinden ne kadar yaratildigini gormek icin

res = []
for x in mat_keys: res.append([x, A[:, mat_keys[x]].sum()])
df = pd.DataFrame(res)
df.sort_index( by=[1], inplace = True, ascending = False)
print df


Sonuc

0  cat_state_ohio  3
1  cat_state_nevada  2


Yogun (dense) matris olarak gostermek gerekirse (ki bu gercek dunya sartlarinda hicbir zaman yapilmaz)

print A.todense()

[[ 1.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 1.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 1.  0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  1.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 0.  1.  0.  0.  0.  0.  0.  0.  0.  0.]]


Kodlanmasi istenen her kategorik kolonu cat_cols icine eklemek yeterli! Mesela year icin bunu yapalim,

[[ 1.  1.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 1.  0.  1.  0.  0.  0.  0.  0.  0.  0.]
 [ 1.  0.  0.  1.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  1.  0.  1.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  1.  1.  0.  0.  0.  0.  0.]]

                 
cat_state_Ohio  3
cat_year_2001  2
cat_state_Nevada  2
cat_year_2002  2
cat_year_2000  1

Sozlugu gosterelim

{'cat_year_2000': 1, 'cat_year_2001': 2, 'cat_state_Ohio': 0, 'cat_state_Nevada': 4, 'cat_year_2002': 3}

Kodlanmis matrisin kategorik olmayan diger kolonlardan ayri olmasi dert degil, bu matris degerleri seyrek hstack ile basit bir sekilde kodlanmis matrise yapistirilabilir.

from scipy.io import mmwrite
import csv, pandas as pd, os
import scipy.sparse as sps
import numpy as np

mat_keys = {}
cat_cols = ['state','year']

N  = num_lines = sum(1 for line in open('in.csv')) - 1
D = 10 # tahmin, buyukce bir sayi

A = sps.lil_matrix((N,D))

with open('in.csv', "rb" ) as theFile:
    reader = csv.DictReader(theFile, delimiter=';')
    for i,line in enumerate(reader):
        for col in cat_cols:
            new_col = 'cat_%s_%s' % (col,line[col])
            if new_col not in mat_keys: mat_keys[new_col] = len(mat_keys)
            A[i, mat_keys[new_col]] = 1.0
           
df = pd.read_csv('in.csv',sep=';',usecols=['pop'])

A = sps.hstack((A,sps.lil_matrix(df)))

print A.todense()


Sonuc

[[ 1.   1.   0.   0.   0.   0.   0.   0.   0.   0.   1.5]
 [ 1.   0.   1.   0.   0.   0.   0.   0.   0.   0.   1.7]
 [ 1.   0.   0.   1.   0.   0.   0.   0.   0.   0.   3.6]
 [ 0.   0.   1.   0.   1.   0.   0.   0.   0.   0.   2.4]
 [ 0.   0.   0.   1.   1.   0.   0.   0.   0.   0.   2.9]]


Ya da iki ustteki kodu genisleterek tum CSV degerlerinin seyrek matris aktarilmasini saglayabiliriz, eger kategorik kolon ise 1-hot kodlama yapilir, degilse oldugu gibi aktarilir,

from scipy.io import mmwrite
import csv, pandas as pd, os
import scipy.sparse as sps
import numpy as np

mat_keys = {}
cat_cols = ['state','year']

N  = num_lines = sum(1 for line in open('in.csv')) - 1
D = 10 # tahmin, buyukce bir sayi

A = sps.lil_matrix((N,D))

with open('in.csv', "rb" ) as theFile:
    reader = csv.DictReader(theFile, delimiter=';')
    for i,line in enumerate(reader):
        for col in line.keys():
            col_name = col; val = line[col]
            if col in cat_cols:
                col_name = 'cat_%s_%s' % (col,line[col])
                val = 1.0
            if col_name not in mat_keys: mat_keys[col_name] = len(mat_keys)
            A[i, mat_keys[col_name]] = val

print A.todense()       
print mat_keys


Sonuc

[[ 1.   1.5  1.   0.   0.   0.   0.   0.   0.   0. ]
 [ 1.   1.7  0.   1.   0.   0.   0.   0.   0.   0. ]
 [ 1.   3.6  0.   0.   1.   0.   0.   0.   0.   0. ]
 [ 0.   2.4  0.   1.   0.   1.   0.   0.   0.   0. ]
 [ 0.   2.9  0.   0.   1.   1.   0.   0.   0.   0. ]]


{'cat_state_Nevada': 5, 'pop': 1, 'cat_year_2000': 2, 'cat_year_2001': 3, 'cat_state_Ohio': 0, 'cat_year_2002': 4}

Hangi kodun kullanilacagi ihtiyaca gore sekillenir; bizim ihtiyacimiz yuzlerce kolon iceren bir veri icinden yapay ogrenim amacli olarak sadece kategorik kolonlari cekip cikartmakti, bu yuzden ilk kodu gelistirdik. Her ihtiyac icin degisik bir yaklasim secilebilir. Mesela ustteki kod kategorik olmayan her seyi numerik kabul ediyor, belki kirli bir veri ortaminda bu secim de iyi degildir, o zaman numerik kolonlar icin ayri bir liste gerekir, vs.

Pandas Problemleri

1-hot kodlamasini seyrek matris olmadan, yine CSV okuyup ama Pandas Dataframe'ini genisletmeye cabalayan bir sekilde de yazmistik ilk basta, fakat dinamik olarak yeni kolon eklemenin hizli islemedigini gorduk. Pandas mevcut bir veriyi almak ve onu manipule etmek, gerekirse birkac yeni kolon eklemek baglaminda kullanilirsa hizlidir. Araclarimizin sinirlarini bilmemiz iyi olur.

Eger tum kolonlari onceden bilsek (bunu bulmaya ugrassak) belki Pandas versiyonu da hizli sekilde kodlanabilirdi, ama kirli veri ortaminda kategorik verilerin kendi icinde bile ek kategorileri oldugunu dusunun! (bizzat gorduk, virgul ile ayrilmis listeler vardi) bu durumda tum kategorileri onceden bulmaya ugrasmak ayni isi iki kere yapmak olurdu, kod bakimini zorlastirirdi.

Ayrica genel olarak, hem de Buyuk Veri dunyasina hazir olmak baglaminda, verinin satir satir islenmesine alismak lazim, bakilan o satir o kolon icin hesap yapilmaya ugrasilmasi daha temiz bir koda sebebiyet veriyor. Ustteki orneklerde kac indis, hangi kategoriler oldugunu onceden bilmiyoruz, bilmeye ugrasmiyoruz onlari anlik olarak hesapliyoruz. Daha ileri ornekler mesela asiri buyuk kategorik secenekleri hashing ve mod hesaplari uzerinden daha az bir pencereye indirgeme yontemini bile kullanabilir, bu hesap ta anlik ve cok hizli yapilabilecek bir hesaptir.

Netflix Dersleri

Netflix makina ogrenimi uzmani Xavier A.'nin tavsiye sistemleri (recommendation systems) hakkinda verdigi ders (slaytlar):

Tuesday, July 8, 2014

Google ile Dunya Kupasi Tahmini

Dunya Kupasi maclarini tahmin eden yapay ogrenim teknikleri, Google muhendisleri tarafindan paylasilmis. Veriyi toplamak icin Google Big Query (Google burada kendi teknolojilerinin reklamini da yapiyor tabii) islemek ve analiz icin Pandas ve diger Python bazli araclari kullanmislar. Basari orani 8 macta 8. Onumuzdeki maclardan tahminler,

Brezilya - Sili (Brezilya, 72%)
Hollanda - Meksika (Hollanda 55%)
Kosta Rika - Yunanistan (Kosta Rika 60%)
Fransa - Nijerya (Fransa 92%)

Dunya Kupasi tahminleri alaninda at yaristiranlardan mesela Nate Silver cuvallamis durumda, tahminleri 50% seviyesinde - rasgele sans ile ayni. Silver bilindigi gibi Bayes modellerini cok kullanir.

Not: Google elemanlari suradaki baglantidan kendi kume ortamlarinda isleyen bir not defteri ve tum kodu iceren Github deposu paylastilar. Fakat bu kodu alip oldugu gibi kendi bilgisayarinizda isletemiyorsunuz,  cunku Google kume ortamina baglantilari var. Biz de bu sebeple kodu alip kume baglantisi icermeyen, gerekli tum verisini kendi icinde tasiyan yeni bir versiyonunu yazdik. Bkz. Istatistik yazilari.