Thursday, December 27, 2012

Siparisler Uzerinde Veri Madenciligi - kNN

Daha once regresyon ile atillik tahmini yapmistik (lineer, ve GLM ile). Bu yazida En Yakin k-Komsu (k-Nearest Neighbor -kNN-) teknigini kullanacagiz.

kNN metodu veriden model cikartmaz, verinin kendisini model olarak kullanir. Bu sebeple ornek bazli metotlardan (instance based methods) bilinir. Temeli basit; model kurmadan etiketleri bilinen veriyi bir kenarda tutariz sonra etiketsiz yeni veri noktasi gelince bu veriye donup bakariz, eldeki veriye "en yakin" k-tane ornegi buluruz ve bu k ornek icinde en fazla hangi etiket var ise, yeni etiketin bu olacagina karar verilir. "En yakinlik" sozu bir kordinat sistemi / uzaklik kavramini cagristirir, ve evet kNN numerik degerlerle bir kordinate sisteminde islem yapar, bu acidan k-means'e (ve pek cok diger yapay ogrenim metotuna) benzedigi soylenebilir. Regresyon ornegindeki gibi gibi kategorik degerler var ise bunlar sayisal hale cevirilmelidir.

kNN'in detaylarina ileride girecegiz, simdilik dellstore2 uzerindeki ornegi gorelim.

from sklearn import neighbors
from patsy import dmatrix
import numpy as np
from pandas import *

__day__ = 130

cols = """
0 + month + day + day_of_week + rank + categoryname + income + season
+ cat_freq + creditcardtype
"""

orders = read_csv("dell-train.csv",sep=",")
train = dmatrix(cols,orders)
last_value = orders[['last_visit']].as_matrix()[:,0] > __day__

print len(last_value[last_value==True])
print len(last_value[last_value==False])

knn = neighbors.KNeighborsClassifier(n_neighbors=10)
knn.fit(train,last_value)

orders = read_csv("dell-validate.csv",sep=",")
validate = dmatrix(cols,orders)
last_value = orders[['last_visit']].as_matrix()[:,0] > __day__

pred = knn.predict(validate)

success = sum(pred[last_value==True] == 1) + \
          sum(pred[last_value==False] == 0)
print success / float(len(pred)) * 100


Burada kNN'e bir 0/1 tahmini yaptirdik, bu etiketleri atillik sayisindan urettik, 130 gunden buyuk atillik degeri 1, kucukleri 0 olsun dedik. Etiket sayisinda bir sinirlama yok (SVM'in aksine), bu ornekte 2 tane kullandik, daha fazla da olabilirdi. Bu arada kNN regresyon amacli da kullanilabilir, k yakin komsu bir etiket oyu verecegine, belli agirliklarla bir ortalama sayi da uretebilir.

Kullandigimiz kNN paketi scikits-learn Python kutuphanesi. Kategorik degerleri sayisallastirmak icin Pasty kullanildi. 

Ustteki kodun basari orani yuzde 86'dir. Gercek dunya verisinde yuzde 85 degerini gorduk (atillik esik degeri ne olursa olsun basari orani ayni -biz 53 gun kullandik-). Metot kuvvetli.

Saturday, December 22, 2012

Mahout, Jython ve Yapay Ogrenim

Bir diger unlu yapay ogrenim kutuphanesi Mahout. Kurmak icin su sayfanin basindaki hareketler takip edilebilir

$ apt-get install maven2

$ cd /opt

$ svn co http://svn.apache.org/repos/asf/mahout/trunk

$ mv trunk mahout_trunk

$ ln -s mahout_trunk/ mahout

$ cd mahout

$ mvn install


Burada Maven denen ve Java dunyasinda pek sevilmeyen bir program kullaniliyor. Maven, Ant yerine / ustune ona bir paket sistemi kazandiran bir sistem, mvn install sirasinda bir suru paketin Internet'ten indirildigini goreceksiniz. Yani Maven paket baglantilarini takip ederek (guya) bizi bir suru dertten kurtariyor, gereken her seyi indiriyor, fakat goreceginiz gibi mvn install asamasi saatler surebilir. Neyse, Mahout kullanabilmek icin bu aci ilaci icmek gerekecek (!), ve bundan sonra Maven bir daha da kullanilmayacak.

Kurulus bitinca $HOME dizini altinda bir .m2 dizini olusturulur. Maven tum gerekli jar dosyalarini buraya koymustur. Biz bu jar dosyalarini Jython'a disaridan kullandirtacagiz. Bunun icin ufak bir bash script numarasi yeterli. Dizin .m2 seviyesinden baslayarak ozyineli (recursive) olarak asagi ineriz, ve onumuze cikan her jar dosyasini alip iki nokta ustuste ile ayirarak CLASSPATH'e ekleriz. Bu noktadan sonra Jython gerekli tum jar'lara sahip olacaktir.

CLASSPATH=`find $HOME/.m2/ -name *.jar`
export CLASSPATH=`echo $CLASSPATH | sed 's/jar\s/jar\:/g'`
jython test.py


Ornek bir Jython Mahout programini altta bulduk

https://gist.github.com/2878249

Yanliz biz bu programda bazi degisiklikler yaptik, ustteki kod icinde CLASSPATH Python programi "icinde" olusturuluyor, bu pek temiz degil, biz bu isleri bash script ortaminda yaptik, boylece Python kodu sadece Mahout ile ilgili isler yapabiliyor. Bizim versiyon test.py altta

from datetime import datetime
from org.apache.mahout.common import RandomUtils
from org.apache.mahout.cf.taste.common import TasteException
from org.apache.mahout.cf.taste.eval import *
from org.apache.mahout.cf.taste.impl.eval import *
from org.apache.mahout.cf.taste.impl.model.file import *
from org.apache.mahout.cf.taste.impl.neighborhood import *
from org.apache.mahout.cf.taste.impl.recommender import GenericUserBasedRecommender
from org.apache.mahout.cf.taste.impl.recommender.slopeone import SlopeOneRecommender
from org.apache.mahout.cf.taste.impl.similarity import *
from org.apache.mahout.cf.taste.model import *
from org.apache.mahout.cf.taste.neighborhood import *
from org.apache.mahout.cf.taste.recommender import *
from org.apache.mahout.cf.taste.similarity import *
from java.io import *
from java.util import *

class GenericRecommenderBuilder(RecommenderBuilder):
    def __init__(self):
        pass
    def buildRecommender(self, model):
        similarity = PearsonCorrelationSimilarity(model)
        neighborhood = NearestNUserNeighborhood(2, similarity, model)
        return GenericUserBasedRecommender(model, neighborhood, similarity)

class SlopeOneRecommenderBuilder(RecommenderBuilder):
    def __init__(self):
        pass
    def buildRecommender(self, model):
        similarity = PearsonCorrelationSimilarity(model)
        neighborhood = NearestNUserNeighborhood(2, similarity, model)
        return SlopeOneRecommender(model)

def main():
    RandomUtils.useTestSeed()
    model = FileDataModel(File("intro.csv"))
    builder = GenericRecommenderBuilder()

    print 'Starting run at %s' % datetime.now()
    for builder in [GenericRecommenderBuilder(), SlopeOneRecommenderBuilder()]:
        print 'Starting evaluations of recommender created using %s at %s...' % (builder, datetime.now())
        for evaluator in [AverageAbsoluteDifferenceRecommenderEvaluator(), RMSRecommenderEvaluator()]:
            print 'Evaluating recommender using %s at %s...' % (evaluator, datetime.now())
            score = evaluator.evaluate(builder, None, model, 0.7, 1.0)
            print 'Score evaluated by %s=%.2f' % (evaluator, score)
    print 'Ending run at %s' % datetime.now()

if __name__ == '__main__':
    main()


Bu kod intro.csv adli bir dosyaya ihtiyac duyar. Bu ornek veri

1,101,5.0
1,102,3.0
1,103,2.5
2,101,2.0
2,102,2.5
2,103,5.0
2,104,2.0
3,101,2.5
3,104,4.0
3,105,4.5
3,107,5.0
4,101,5.0
4,103,3.0
4,104,4.5
4,106,4.0
5,101,4.0
5,102,3.0
5,103,2.0
5,104,4.0
5,105,3.5
5,106,4.0


Weka, Jython ve Yapay Ogrenim

Yapay ogrenim (machine learning) paketlerinden / yazilimlarindan unlu birisi Weka. Paket icinde karar agaclari, SVM gibi bilinen ML algoritmalari var; Weka Java ile yazilmistir fakat Jython uzerinden Python ile erisim mumkundur.

Kurmak icin site

http://www.cs.waikato.ac.nz/ml/weka/

Zip acilir ve kurulum bu kadar. Su baglantida Jython ornegi var

http://weka.wikispaces.com/Using+WEKA+from+Jython

Jython kullanmak icin Ubuntu uzerinde apt-get install jython. Sonra bir script yazin, mesela iris.sh,

export CLASSPATH=$CLASSPATH:[WEKA_DIZIN]/weka-3-6-8/weka.jar
jython iris1.py


Kodunuz iris1.py icinde olacak, ve suna benzeyecek (ustteki siteden alindi)

import sys
import weka.classifiers.trees.J48 as J48
import java.io.FileReader as FileReader
import weka.core.Instances as Instances
import weka.core.converters.CSVLoader as CSVLoader
import weka.classifiers.trees.J48 as J48

file = FileReader("[WEKA_DIZINI]/weka-3-6-8/data/iris.arff")
data = Instances(file)
data.setClassIndex(data.numAttributes() - 1)

j48 = J48()
j48.buildClassifier(data)

print j48


Bu kodu iris.sh ile isletin. Soyle bir sonuc gelecek

petalwidth <= 0.6: Iris-setosa (50.0)
petalwidth > 0.6
|   petalwidth <= 1.7
|   |   petallength <= 4.9: Iris-versicolor (48.0/1.0)
|   |   petallength > 4.9
|   |   |   petalwidth <= 1.5: Iris-virginica (3.0)
|   |   |   petalwidth > 1.5: Iris-versicolor (3.0/1.0)
|   petalwidth > 1.7: Iris-virginica (46.0/1.0)

Number of Leaves  :     5

Size of the tree :     9


Iris veri seti ML'de iyi bilinen veri setlerinden, ve ustteki kod ile J48 algoritmasi ile bu veri uzerinde bir karar agaci olusturduk.

Fakat pratikte bir problem var, is dunyasinda cogunlukla veriyi ARFF formatinda bulmayiz, cogunlukla CSV formati karsimiza cikiyor. Dert degil, Weka'nin CSV okuyucusu da var, simdi Iris verisini CSV'den okuyan ornek gorelim.

import sys
import weka.classifiers.trees.J48 as J48
import java.io.FileReader as FileReader
import java.io.File as File
import weka.core.Instances as Instances
import weka.core.converters.CSVLoader as CSVLoader
import weka.classifiers.trees.J48 as J48

file = File("/bir/dizin/iris.csv")
loader = CSVLoader()
loader.setSource(file)
data = loader.getDataSet()
data.setClassIndex(data.numAttributes() - 1)

j48 = J48()
j48.buildClassifier(data)

print j48


Ustteki kod benzer bir cikti verecek.

Veri dosyasi iris.csv'i Internet'ten bulabilirsiniz, bir ornegi surada mesela

Sunday, December 16, 2012

Kategorik Veri, 1-in-n, Faktorler, R ve Patsy

R dilini kullanarak kategorik veri iceren kolonlarin 1-in-n seklinde yana dogru "genisletilerek" 1/0 iceren hale cevirilebildiginden bahsetmistik. Fakat R bu degismis hali disa yansitmaz, lm(), nnet() gibi komutlar ic isleyisleri sirasinda bu degisimi kullanirlar, lm() sonuc raporunde bu yeni kolonlari gorebilirsiniz mesela, ama veri disari cikmaz.

Eger bu veriyi mesela matris formatinda istiyorsaniz, su komut dizisini kullanabilirsiniz (dellstore2 ornegindeki season ve categoryname kolonlari icin)

orders <- read.csv ("data.csv",header=TRUE,sep="|")
orders <- cbind(orders, model.matrix( ~ 0 + season + categoryname, orders))
orders <- orders[, setdiff(names(orders), c("season", "categoryname"))]
write.csv (orders,"out.csv")


Sondan ikinci satir lazim cunku genisletilmis kolonlar eklense bile orijinal kolon hala orders icinde tutuluyor. Bu kolona artik ihtiyac yok ve cikartilmasinda bir zarar olmayacak.

Eger ayni islemi Python ile yapmak istersek Patsy adli paket yardimci olabilir. En son versiyon

http://pypi.python.org/pypi/patsy/

Ayrica Pandas kurmak ta gerekiyor, bunun icin "sudo pip install pandas" yeterli.

Kullanmak icin mesela

from patsy import dmatrix
from pandas import *
orders = read_csv("dell.csv",sep=",")
matrix = dmatrix("0 + month + netamount + gender + season + cat_freq + creditcardtype",orders)

print matrix.design_info
print matrix[0,:]


Ust son iki satirda matrisin ic yapisini (yeni kolon isimlerini gormek icin) ekrana bastirdik, ayrica matrisin ilk satirini ornek olarak gosterttik. Sonuc

DesignInfo(['gender[F]', 'gender[M]', 'season[T.SPRING]', 'season[T.SUMMER]', 'season[T.WINTER]', 'creditcardtype[T.c2]', 'creditcardtype[T.c3]', 'creditcardtype[T.c4]', 'creditcardtype[T.c5]', 'month', 'netamount', 'cat_freq'],  ....

[  0.     1.     0.     0.     0.     0.     0.     0.     0.    11.     5.08
   1.  ]


gibi bir cikti goreceksiniz, yani faktor kolonlari 1-in-n formatina cevirilerek 1/0 degeri tasiyacak sekilde "yana dogru" genisletilmistir. Yeni kolon isimleri mesela season[T.SPRING] gibi, yaz mevsimi icin apayri bir kolon vardir,ve ona tekabul eden 0/1 degeri olacaktir.

Bu yeni matrisle istediginiz yapay ogrenim rutinini cagirabilirsiniz. Matris Numpy formatiyla uyumludur. 

Kaynak

Saturday, December 15, 2012

Git Commit ve Unite Halinde Degisimler

Diyelim ki bir Git deposundaki kodlarinizda calisiyorsunuz, degisiklik yaptiniz. Bu kodlari nasil depoya geri koymak gerekir?Once dizin icinde git status yapin. 

# On branch master
# Changes not staged for commit:
#   (use "git add/rm ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#    modified:   README
#    modified:   build.py
#
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#    mining/dosya.py

#
no changes added to commit (use "git add" and/or "git commit -a")

Takip edilmeyen dosyalar (untracked files) altinda. Bu dosyalar Git'e verilmemis, o yuzden git commit ile iceri alinmiyorlar. Eger bazi dosyalarin hakikaten Git disinda kalmasini ister, ve ustteki mesajla bile bunun bildirilmesini istemezsek, .gitignore icinde bunu yapabiliriz. Takip edilmeyen dosyalari git add ile ekleyebiliriz.

Degistirilmis (modified:) ile gosterilen dosyalar Git'in izledigi ve uzerinde degisim yapilmis dosyalardir. Bunlarin icinden istediklerimizi git add ile secerek commit icin hazirlayabiliriz. Mesela README dosyasinda bunu yapmis olsak, tekrar git status deyince

# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#    modified:   README

#    ...

gozukecek.

Onemli bir nokta: git commit oncesi git add ile eklenen her dosya belli bir "toplu degisim" icin ve bu degisimi temsil eder sekilde yapiliyor olmali. Ornek: yeni bir ozellik ekledik, ve bu ozellik icin A,B,C dosyalarina dokunduk (sonra baska sebeple D,E,F'ye dokunduk). Bu ozellik icin commit oncesi sadece A,B,C'yi git add ile eklemeliyiz (ekleme derken, ekleme icin 'isaretlemeliyiz' daha dogrusu). Niye? Cunku git commit derli toplu bir grup degisimi iceri almali, ve daha da onemlisi bu degisimi depoya git commit -m 'mesaj' ile verdigimiz mesaj da sadece o tek (unite) degisimi tarif ediyor olmali. Aslinda sadece ve sadece bu mesaj sebebiyle birbiriyle alakali degisimlerin tek unite halinde yapilmasina bir nevi mecburuz denebilir (kod okunabilirligi, takip edilebilirligi, bakilabilirligi acisindan).

Eger bir commit oncesi yapilan her degisikliklerin tamami tek bir uniteye aitse, o zaman basit bir sekilde git add -u ile tum bu degisiklikleri otomatik olarak ekleyebiliriz.

htop

Unix eski "top" komutu sistemdeki surecleri, ne kadar mikroislemci zamani kullanildigi gibi raporlari ekranda sabitleyip gosteren (akisli degil, mesela tail -f gibi -text bazli ortamda bu is icin curses gerekiyor dogal olarak-) bir programdi. Fakat biraz renksizdi, ve cok ozellige sahip degildi.

Yeni komut htop, tum cekirdeklerin (cores) yukunu sol ust kisimda canli olarak aktarir, htop ayrica hiyerarsik gosterime izin verir ve renklidir. Ubuntu'da kurmak icin sudo apt-get install htop