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