Metin Ön İşleme Adımları İçin Keras Tokenizer Sınıfı Kullanımı

Metin ön işleme (text pre-processing) doğal dil işlemenin çoğu zaman zahmetli fakat  algoritmanın başarısını etkileyen zaruri ön adımlarındandır. Metin verisinin hazırlanma adımlarını gerçekleştirirken kalıplaşmış bazı sorulara cevap verilmesi gerekir:

  • noktalama işaretlerinin arındırılması (cleaning)
  • cümle, kelime, harf veya n-gramlar halinde parçalama (tokenization)
  • özel karakterler ve nümerik değerler gibi farklı anlam birimlerinin nasıl ele alınacağı
  • büyük-küçük harf ayrımı olup olmayacağı
  • kelimeler olduğu gibi mi kullanılacağı yoksa köklerine mi dönüştürüleceği
  • hatalı yazılmış kelimeler in olduğu gibi mi yoksa düzeltilerek mi ele alınacağı

gibi ve daha da arttırabilecek sorular mevcuttur. Bunlar tamamen problemin niteliğine göre önem kazanan şartlardır. Bu aşamalardan geçen veri seti için sorulacak en önemli soru ise metinlerin vektörlere nasıl dönüştürüleceğidir. Burada da TF-IDF, One Hot Encoding, Word Embedding (Word2Vec) gibi seçenekler bulunmaktadır.

Yukarıda bahsedilen soruların cevapları belirlendikten sonra kodlama için çeşitli Python tabanlı kütüphane veya sınıflardan yararlanılabilir. Bu yazıda Keras’ın preprocessing.text kütüphanesini örneklerle açıklanacaktır. Bu sınıfla ilgili genel bilgiler Keras’ın resmi dokümantasyon sayfasında bulunmaktadır.

Örnek olarak İstiklal Marşı’nın her bir kıtasının bir text dosyasında kayıtlı olduğu veri seti kullanılacaktır. Bu 4 dosyada 4’er tane olmak üzere toplam 16 tane satır bulunmaktadır. Varsayılan senaryoda her bir satır bir adet veriye denk gelmekte ve toplam 16 tane veri bulunmaktadır. Bu giriş verilerinin vektöre dönüştürülmesi için gerekli ön işleme adımları şu şekildedir:

#data klasöründen verilerin okunması ve
#egitim_X[] içerisine kaydedilmesi
import os

#Text dosyaları data isimli klasör içerisinde olsun
BASE_DIR = os.getcwd()
TEXT_DATA_DIR = os.path.join(BASE_DIR, 'data')

Data klasörü içerisindeki .txt uzantılı dosyalar mevcut
Bu dosyaların  içerisindeki her bir satırın eğitim verisinin bir elamanı olduğunu varsayıyoruz

egitim_X = []
#data klasöründeki tüm dosyaları teker teker oku
for name in sorted(os.listdir(TEXT_DATA_DIR)):
    fname = os.path.join(TEXT_DATA_DIR, name)
    #dosya uzantısı .txt ise 
    if fname.endswith(".txt"):
        with open(fname) as infile:
            for line in infile:
                #satır başı ve sonu dışındaki olası boşlukları temizle
                line = line.strip()
                try:
                  egitim_X.append(line)
                except Exception as e:
                  print(e)

#ilk ve son satırları yazdır
print egitim_X[0]
print egitim_X[-1]
Korkma, sönmez bu şafaklarda yüzen al sancak;
'Medeniyet!' dediğin tek dişi kalmış canavar?
#veri sayısını yazdır
print len(egitim_X)
16

Her satır bir giriş verisi olarak egitim_X listesine aktarıldı
Bunun yerine dosyalarda geçen bütün metinler birbirine eklenebilirdi
Fakat bu şekilde hem metin ön işleme hem de vektör dönüşümü bir arada ilerletilebilir

from keras.preprocessing.text import Tokenizer

# tokinizer nesnesini oluştur

# parametres opsiyonları ve default değerleri
# num_words=None, lower=True, split=' ', char_level=False, oov_token=None
# filters='!"#$%&()*+,-./:;<=>?@[\]^_`{|}~ '

# metinlerde en çok geçen 10 kelimenin işleme alınmasını sağlayalım
MAX_NUM_WORDS = 10
tokenizer = Tokenizer(num_words=MAX_NUM_WORDS)
# giriş verisine göre tokinizer sınıfının ayarlanması
tokenizer.fit_on_texts(egitim_X)

Şu anda giriş verisi hala egitim_X ‘de saklandığı şekilde
Fakat tokinizer giriş verisiyle ilgili bilmesi gereken bir çok şeyi biliyor
Bunlar:  kelime listesi ,  kelime frekansları ,  en fazla geçen 10 kelime

#hangi kelimelerin geçtiğine bakalım
for kelime in tokenizer.word_index:
    print kelime,
celal dağları Çatma aşarım canavar olayım zincir zırhlı kahraman üstünde sancak yüzen sönmez
dediğin korkma dökülen bana serhaddim helal bir sana nasıl en imanı gibiyim yıldızıdır
kükremiş ey sel afakını ' gül yurdumun çehreni bu hakkıdır olmaz sonra sığmam milletimin o 
benimdir dolu sönmeden tüten böyle son hür tek kanlarımız 'medeniyet ocak hangi duvar var 
yırtarım boğar iman bendimi ırkıma gibi ulusun hilal ben vuracakmış taşarım ancak dişi çiğner
ezelden parlayacak al nazlı enginlere kalmış göğsüm kurban ne istiklal beridir hakk'a benim
garbın sarmışsa yaşadım Şaşarım çılgın şafaklarda şiddet çelik yaşarım tapan milletimindir
print "Toplam ", len(tokenizer.word_index), " adet farklı kelime bulunmaktadır"
print "Toplam ", tokenizer.num_words, " adet  kelime işleme alınacaktır"
Toplam  93  adet farklı kelime bulunmaktadır
Toplam  10  adet  kelime işleme alınacaktır

Görüldüğü üzere bütün kelimeler default olarak verilmiş split=’ ‘ kuralına göre bulunmuş
Kelimeler küçük harflerle yazılmış. İstisna olarak Türkçe karakterler büyük harf olarak kalmış.
Bunun sebebi keras preprocessing kütüphanesinin karakter kodunu çözememesidir.

Bu problem ilgili aşamada line = line.decode(‘utf-8’) satırı eklenerek çözülebilir

Tokenizer sınıfının en önemli nesneleri word_index ve word_counts’dır.

print "korkma kelimesi toplam ", tokenizer.word_counts['korkma'], " kez geçmiştir"
print "korkma kelimesine verilen id = ", tokenizer.word_index['korkma']
korkma kelimesi toplam  2  kez geçmiştir
korkma kelimesine verilen id =  4
#bütün kelimeleri ve frekanslarını yazdıralım
for kelime in tokenizer.word_index:
    print kelime, "=", tokenizer.word_counts[kelime], "    ",
celal = 1      dağları = 1      Çatma = 1      aşarım = 1      canavar = 1      olayım = 1  zincir = 1
zırhlı = 1      kahraman = 1      üstünde = 1      sancak = 1      yüzen = 1    sönmez = 1      dediğin = 1      
korkma = 2      dökülen = 1      bana = 1      serhaddim = 1 helal = 1      bir = 2      sana = 1      nasıl = 1      
en = 1      imanı = 1      gibiyim = 1     yıldızıdır = 1      kükremiş = 1      ey = 1      sel = 1      afakını = 1      ' = 1      
gül = 1      yurdumun = 1      çehreni = 1      bu = 3      hakkıdır = 1      olmaz = 1      sonra = 1      sığmam = 1      
milletimin = 2      o = 3      benimdir = 1      dolu = 1      sönmeden = 1      tüten = 1      böyle = 1      son = 1      
hür = 2      tek = 1      kanlarımız = 1      'medeniyet = 1      ocak = 1      hangi = 1      duvar = 1      var = 1      yırtarım = 1      
boğar = 1      iman = 1      bendimi = 1      ırkıma = 1      gibi = 1      ulusun = 1      hilal = 1      ben = 1      vuracakmış = 1      
taşarım = 1      ancak = 1      dişi = 1      çiğner = 1      ezelden = 1      parlayacak = 1      al = 1      nazlı = 1      enginlere = 1      
kalmış = 1      göğsüm = 1      kurban = 1      ne = 1      istiklal = 1      beridir = 1      hakk'a = 1      benim = 3      garbın = 1      
sarmışsa = 1      yaşadım = 1      Şaşarım = 1      çılgın = 1      şafaklarda = 1      şiddet = 1      çelik = 1      yaşarım = 1      
tapan = 1      milletimindir = 1

Bu aşamaya kadar gerçekleştirilen bütün adımlar, giriş verisinin sayısal veriler olarak temsil edilmesi içindi.  Şimdi bunu gerçekleştirelim:

sequences = tokenizer.texts_to_sequences(egitim_X)

for satir in sequences:
    print satir, "  ",
[4, 8, 1, 9]    []    [2, 3, 5]    [2, 2, 3]    []    [6, 1, 1]    []    [5]    [7, 7]    
[]    []    []    []    [3]    [4, 6]    []

Veriler artık cümleler yerine sayısal değerler ifade edilmiş
Fakat önemli eksikler var
Bazı cümlelerin [] şeklinde boş dizilere dönüştüğünü görüyoruz
Genellik tamamen boş diziyle karşılaşmak burdakindan daha nadir gerçekleşir. Çünki en azından en çok geçen 10.000 kelime’den birkaçı bir veride bulunması beklenir. Fakat bu örnekte, verileri manuel olarak takip edebilmemiz açısından az sayıda veri kullanıldı ve maksimum kelime sayısı 10 seçildi.

Ayrıca görüldüğü üzere her veri farklı uzunlukta. Çoğu algoritma giriş verilerinin sabit uzunlukta olmasını bekler. Bu durumlarda tokenizer’ın padding metodunu kullanırız.

# her bir giriş verisininin uzunluğu yalnızca 4 olsun

from keras.preprocessing.sequence import pad_sequences

giris = pad_sequences(sequences, maxlen=4)



for satir in giris:
    print satir, "  ",
[4 8 1 9]    [0 0 0 0]    [0 2 3 5]    [0 2 2 3]    [0 0 0 0]    [0 6 1 1]    [0 0 0 0]    
[0 0 0 5]    [0 0 7 7]    [0 0 0 0]    [0 0 0 0]    [0 0 0 0]    [0 0 0 0]    [0 0 0 3]    
[0 0 4 6]    [0 0 0 0]

Artık giriş verisi belirlediğimiz metin ön işleme şartlarına göre hazır durumda.

Python tabanlı Keras haricindeki diğer kütüphaneler kullanıldığında de preprocessing.text.Tokenizer sınıfı ile veriler hazırlanıp daha sonra makine öğrenmesi veya derin öğrenme adımlarına devam edilebilir.

Veriler ve kodun tamamı github’a yüklenmiştir:

https://github.com/irhallac/deep_learning_examples/tree/master/keras_tokenizer