Friday, April 15, 2016

Grafikten Veri Cikartmak

Bazen mesela grafiksel gordugumuz bir zaman serisinin verisi elde olmayabilir. Veriyi grafikten cikartmak icin, ornege bakalim


Veriyi sayisal olarak cikartmak icin imaj isleme (image processing) metotlarini kullanabiliriz. Mesela bir metot yanyana iki pikselin farkini hesaplar, eger fark buyukse orada bir "kenar" vardir. Bu teknikle yukaridaki imajdaki egri bulunabilir.

Ana imaj

https://en.wikipedia.org/wiki/File:Extinction_intensity.svg

PGM'e cevirelim

convert  -crop 495x245+29+54 -resize 900x400 Extinction_intensity.svg  extinct.pgm

Imaj isleme kodu

import pandas as pd
from PIL import Image

im2=Image.open("extinct.pgm")
grady,gradx = np.gradient(im2)
grady = (grady>0).astype(float)
extin = np.argmax(grady,axis=0)
df = pd.DataFrame(extin)
df2 = df.max()-df
mymin = 1.
mymax = 52. - mymin
df3 = df2 / df2.max() * mymax
df3 = df3 + mymin
idx = np.linspace(542,1,len(df3))
df4 = df3.set_index(idx)
df4[0].to_csv('extinct.csv',header=None,index=None)

ext = pd.DataFrame(pd.read_csv('extinct.csv',header=None))
ext = ext.set_index(np.linspace(542,1,len(ext)))
ext[0].plot()
ext = ext[0]
plt.savefig('ex1.png')

Tuesday, April 12, 2016

Scipy Seyrek Matrisleri (Sparse Matrices)

Scipy kütüphanesinde seyrek matrisler üzerinde işlemi sağlayan pek çok class, metot var. Seyrek matrislerde bilindiği gibi sıfır değeri depolanmaz, kıyasla Numpy "yoğun (dense)" matrislerde herşey depolanır, seyrek durumda bu sebeple sadece sıfır harici değerler için yer ayrılacaktır. Tabii bu seyrek matrisler hala çarpım, toplama, vs, gibi işlemlerin yapılmasına izin verirler, mesela toplama durumunda iki seyrek matris A,B üzerinden A+B arka planda şöyle kodlanabilir, B'de olmayan öğe  ile A'da olan bir değer toplanıyorsa sonuç direk A'daki değer olur, çünkü olmayan değer otomatik olarak sıfırdır, bu şekilde pek çok hesap daha hızlı şekilde yapılabilir.

Örnek: diyelim ki Netflix, kullanıcı filmi seyretmişse  müşterileri satırda, filmler kolonda olacak şekilde bir matriste ona verdiği beğeni değerini 1-5 arası bir değerle kaydetmiş olabilir. Bir kullanıcı çoğunlukla filmlerin hepsini seyretmiş olamaz, o zaman bu matriste satır başı en fazla 100-200 civarı  öğe / kolon değeri "dolu" olacak, gerisi boş olacaktır. Eğer bu matrisi scipy.sparse üzerinden işlersek, bellek ve işlem hızında ilerleme sağlarız.

Seyrek matris yaratmak icin onceden boyut tanımlanabilir, fakat o boyut kadar yer bellekte onceden ayrilmaz.  Mesela

import scipy.sparse as sps
A = sps.lil_matrix((N,D)) 

N,D ne olursa olsun A bellekte hiç / çok az yer tutar.

Scipy kütüphanesinde pek çok farklı seyrek matris çeşitleri var, mesela coo_matrix, csr_matrix, vs.. Bu matrislerin hepsinin duruma göre avantajları / dezavantajları var. İyi haber birinden diğerine geçiş çok kolay, mesela A bir lil_matris'ten coo_matrix'e geçiş için A.tocoo() yeterli. Avantajlara örnek, mesela lil ile dilimleme (slicing) yapılabilir, i.e. "bana sadece 3. kolonu ver" demek gibi, ama coo ile bu yapılamaz.

Bazı Numaralar

X = sps.lil_matrix((2,5))
X[0,2] = 2.0  
X[1,3] = 5.0

olsun. Yogun hali

print X.todense()

[[ 0.  0.  2.  0.  0.]
 [ 0.  0.  0.  5.  0.]]

Sıfır Olmayan Öğeleri Gezmek 

Direk lil_matrix ile

rows,cols = X.nonzero()
for row,col in zip(rows,cols):
    print row,col, ' = ', X[row,col]

Eger coo_matrisi olsaydi

cx = X.tocoo()
for i,j,v in zip(cx.row, cx.col, cx.data):
   print i,j,' = ',v

Bir satırı bir matrisin her satırıyla ögesel olarak çarpmak, 

X2 = sps.lil_matrix((1,5))
X2[0,3] = 9
print X2.todense()

[[ 0.  0.  0.  9.  0.]]

Bu matrisi alıp önceki X'in her satırı ile öğesel çarptırmak için 

print X.multiply(X2).todense()

[[  0.   0.   0.   0.   0.]
 [  0.   0.   0.  45.   0.]]

Sadece sıfır olmayan ogelerinin log'unu almak, 

X=X.tocoo()
X2=X2.tocoo()
X2.data = np.log(X2.data)
print X2.todense()

[[ 0.          0.          0.          2.19722458  0.        ]]

Ortalama Çıkartmak

Scipy seyrek matrislerde ortalamayı almak külfetli olabiliyor, Scipy ortalamayı çıkartmayı izin vermez (olmayan değerler ortalama alırken sıfır mı kabul edilecektir? bu tam bilinmediği için izin verilmemiş). Fakat bu özellik gerekiyorsa, şöyle yapılır,

import scipy.sparse as sps

def center(mat):
    mat = mat.T
    vec = sps.csc_matrix(mat.mean(axis=1))
    mat_row = mat.tocsr()
    vec_row = vec.T
    mat_row.data -= np.repeat(vec_row.toarray()[0],np.diff(mat_row.indptr))
    return mat_row.T

mat = sps.csc_matrix([[1, 2, 3, 5.],
                      [2, 3, 4, 5.],
                      [3, 4, 5, 5.]])

print center(mat).todense()

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

Normalize Etmek 

Standardize etmek hem ortalamayı çıkartmak (demean), sonra normalize etmek demektir. Bu iki işlem birbirinden bağımsız yapılabilir, bazen biri bazen diğeri kullanılabilir. Normalize etmek, mesela satir L2 normalizasyonu diyelim, oyle bir islemdir ki o islem ardindan her satirdaki ogelerin karesini toplayip karekoku alinca 1 sonucunu elde edebilmek mumkun olacaktir, Normalize etmek için scikit-learn paketinin fonksiyonları vardır, 

from sklearn.preprocessing import normalize
print normalize(mat, norm='l1', axis=0).todense()

[[-0.5 -0.5 -0.5  0. ]
 [ 0.   0.   0.   0. ]
 [ 0.5  0.5  0.5  0. ]]

Üstteki çağrı matrisin kolonlarını (çünkü axis=0 seçildi, bu kolon demek) L1 normu kullanarak normalize etti; yani her kolonun L1 büyüklüğü hesaplandı ve o kolonun her hücresi bu büyüklük ile bölündü. L2 norm kullabilirdik,

print normalize(mat, norm='l2', axis=0).todense()

[[-0.70710678 -0.70710678 -0.70710678  0.        ]
 [ 0.          0.          0.          0.        ]
 [ 0.70710678  0.70710678  0.70710678  0.        ]]

Satırları normalize edebilirdik, 

[[-0.33333333 -0.33333333 -0.33333333  0.        ]
 [ 0.          0.          0.          0.        ]
 [ 0.33333333  0.33333333  0.33333333  0.        ]]


Bu belgeye ekler olacak. 

Dil Isleme, Python - NLTK

Metin bazlı dokümanlar üzerinde dil işleme yapmayı kolaylaştıran bir kütüphane Python NLTK - isim İngilizce doğal dil işlemi araç çantasından (natural language toolkit)  geliyor. Özellikle yapay öğrenim algoritmaları işlemeden dil metinleri üzerinde önişleme (preprocessing) için faydalı. Bu algoritmaların çoğu bir dokümanı bir "kelime çuvalı (bag-of-words)" olarak temsil eder (çuval kelimesi çok uygun çünkü kelimelerin arasındaki sıra dikkate alınmaz, belli bir kelimeden kaç tane olduğu sayılır ve bu bilgi "çuvala" atılır), ve bu tür işlemler NLTK ile çok hızlı şekilde yapılabilir. Kurmak için

pip install nltk

Fakat NLTK içinde pek çok ek "model" var - bu modeller dil modelleri, mesela fiillerin nasıl şekillendiği gibi şeyler. Bu ek modeller ek dosyalar içinde ve ilk kuruluşa dahil değiller. Onları kurmak için bir .py dosyasinda, ya da ipython komut satırından

import nltk
nltk.download()

işletmek lazım, bu bir GUI başlatır. GUI içinde mesela Models | punkt seçilir ve Install tıklanınca bu model indirilecektir.

Basit örnek

import nltk, string
doc = 'The swimmer likes swimming so he swims.'
tokens = nltk.word_tokenize(doc.lower())
print tokens

Sonuç

['the', 'swimmer', 'likes', 'swimming', 'so', 'he', 'swims', '.']

Eğer nokta, virgül vs çıkartmak istersek,

tokens = [i for i in tokens if i not in string.punctuation]

['the', 'swimmer', 'likes', 'swimming', 'so', 'he', 'swims']

Kök bulmak (stemming) denen bir işlem mesela fiillerden çekimi çıkartır, böylece "yüzmek (swimming)" fiilinin tüm çekimleri aynı yüzme eylemine eşlenir. Bu çok faydalı bir özellik. 

stemmer = nltk.stem.porter.PorterStemmer()

def stem_tokens(tokens):
    return [stemmer.stem(item) for item in tokens]
    
tokens = stem_tokens(tokens)    

Sonuc

[u'the', u'swimmer', u'like', u'swim', u'so', u'he', u'swim']

Kelime Çiftleri (Bigrams)

Bir dokümanda arka arkaya gelen ikili, üçlü, vs. kelime dizilerine bakmak o dokümanı anlamak için çok faydalı oluyor, mesela açık kelimesi var, yazılım kelimesi var, bu kelimeler ayrı ayrı pek çok dokümanda geçiyor olabilirler, fakat "açık yazılım" kelime çifti arka arkaya daha özel bir anlam taşır. NLTK ile bu çiftleri üretmek için kod altta. Üretim ardından çiftlerin her biri dokümanı temsil eden kelime çuvalında bir kolon haline gelir.

bigrams = nltk.bigrams(tokens)
for x in bigrams: print x

('the', 'swimmer')
('swimmer', 'likes')
('likes', 'swimming')
('swimming', 'so')
('so', 'he')
('he', 'swims')
('swims', '.')

Bu belgeye ekler olabilir.