N-gram nedir? N-gram ile bir sonraki kelimeyi nasıl tahmin ederiz?

n-gram belirli bir metnin n kadar ardışık ögelerden oluşan bir koleksiyondur. Bu ögeler n kadar olan kelimelerden ve harflerden oluşabilirler. Doğal dil işleme (NLP) alanında kullanılan bir tekniktir.

Hangi alanlarda kullanılır?

  • Otomatik kelime tamamlamaları
  • Dil modeli oluşturmaları
  • Yazım Düzeltmeleri
  • Cümle tahminleri
  • Spam analizi duygu analizi gibi sınıflandırmaları

Bu gibi alanlarda kullanılıyor.

n-gram çalışma mantığı nedir?

n-gram Türü Açıklama Çıktı (Örnek)
Unigram Her kelime tek başına ["Ben", "bugün", "sinemaya", "gittim"]
Bigram İkili kelime grupları [("Ben", "bugün"), ("bugün", "sinemaya"), ("sinemaya", "gittim")]
Trigram Üçlü kelime grupları [("Ben", "bugün", "sinemaya"), ("bugün", "sinemaya", "gittim")]
n-gram (n=4) Dörtlü kelime grupları (örnek: 4-gram) [("Ben", "bugün", "sinemaya", "gittim")]

Unigram: Kelimeleri tek tek inceler. Genelde sıklık analizi için kullanılır.
Bigram: Her kelimenin ardından hangi kelimenin geldiğini analiz eder.
Trigram: İki kelimeye bakar üçüncü kelimeyi tahmin etmeye çalışır.

Python ile bir sonraki kelimeyi tahmin etme

İlk önce elimizde bulunan belge olabilir veya yazı olabilir onu n-gram ile koleksiyon haline getirmemiz gerekecek. Koleksiyon haline getirmeden önce büyük küçük harf ve noktalama iaretlerinden kurtulmamız gerekecek. Bir sonraki kelimeyi tahmin ederken bigram kullanabiliriz.

import re

text = "Burak markete gitti. 2 adet gazoz aldı ve marketden çıktı."

def bigramParse(text:str):
    words = re.sub(r'[^\w\s]','',text.lower()).split()
    bigram = [] 

    for i,word in enumerate(words):
        if i != words.__len__() - 1:
            bigram.append([word,words[i+1]]) 
    
    return bigram

result = bigramParse(text)

print(result)
[kadir@nixos:~/Masaüstü/projects/n-gram]$ python app.py 
[['burak', 'markete'], ['markete', 'gitti'], ['gitti', '2'], ['2', 'adet'], ['adet', 'gazoz'], ['gazoz', 'aldı'], ['aldı', 've'], ['ve', 'marketden'], ['marketden', 'çıktı']]

Yazımızı bigram haline çevirdik. Şimdi tahmin etme fonksiyonumuzu oluşturup kodumuzu test edelim.

import re

text = "Burak markete gitti. 2 adet gazoz aldı ve marketden çıktı."

def bigramParse(text:str):
    words = re.sub(r'[^\w\s]','',text.lower()).split()
    bigram = [] 

    for i,word in enumerate(words):
        if i != words.__len__() - 1:
            bigram.append([word,words[i+1]]) 
    
    return bigram

def guess(text:str, bigram:list):
    for firstWord, lastWord in bigram:
        if text == firstWord:
            return lastWord
        



bigram = bigramParse(text)


print(guess("markete",bigram))
[kadir@nixos:~/Masaüstü/projects/n-gram]$ python app.py 
gitti

Bu çok basit bir tahmin etme fonskiyonu oldu. Bunu daha da geliştirebiliriz.

  • Aynı kelimeler birden fazla tekrar edebilir ve bir sonraki kelimenin ne olacak sadece aratılan kelimenin ilk bulunan sonraki kelimesi olacaktır. Bu sorunu çözmek için birden fazla sonuç verebiliriz.
  • Birden fazla sonuç verdiğimizde ise en sık kullanılan bir sonraki kelimeye göre tahminler sıralanması gerekiyor.
  • Sonuçların yüzdesel değerler taşıması gerekiyor.

Şimdi sırayla bu geliştirmeleri yapalım. İlk önce birden fazla sonuç vermemiz gerekiyor. guess fonksiyonunu düzeltelim.

def guess(text:str, bigram:list):
    result = []
    for firstWord, lastWord in bigram:
        if text == firstWord:
            result.append(lastWord)
    return result

Şimdi guess fonksiyonunda birden fazla sonuç verebilecek. Burda en fazla tekrar eden sonuçları bulup onlara yüzdesel oranlar verip bu oranlara göre sıralamalıyız.

from collections import Counter

def rateAndSort(bigramResultList: list):
    counter = Counter(bigramResultList)
    total = sum(counter.values())
    
    sortedResults = sorted(
        [(word, count, round(count / total * 100, 2)) for word, count in counter.items()],
        key=lambda x: x[1],
        reverse=True
    )
    
    return sortedResults

Şimdi tüm kodu test edelim.

import re
from collections import Counter 

text = "Burak markete gitti. 2 adet gazoz aldı ve marketden çıktı. Gazozu eline aldı. Aldığı bu gazozun tarihi geçmişti geri iade etmek için markete geri döndü."

def bigramParse(text:str):
    words = re.sub(r'[^\w\s]','',text.lower()).split()
    bigram = [] 

    for i,word in enumerate(words):
        if i != words.__len__() - 1:
            bigram.append([word,words[i+1]]) 
    
    return bigram

def guess(text:str, bigram:list):
    result = []
    for firstWord, lastWord in bigram:
        if text == firstWord:
            result.append(lastWord)
    return result
        

def rateAndSort(bigramResultList: list):
    counter = Counter(bigramResultList)
    total = sum(counter.values())
    
    sortedResults = sorted(
        [(word, count, round(count / total * 100, 2)) for word, count in counter.items()],
        key=lambda x: x[1],
        reverse=True
    )
    
    return sortedResults

bigram = bigramParse(text)
guessedWords = guess("markete", bigram)
ranked = rateAndSort(guessedWords)

print(ranked)
[kadir@nixos:~/Masaüstü/projects/n-gram]$ python app.py 
[('gitti', 1, 50.0), ('geri', 1, 50.0)]

Şuanda istediğimiz gibi çalışıyor.

Burda büyük bir örnek yapmasak da iyi bir başlangıç olduğunu umuyorum. Bir sonraki yazımızda görüşmek üzere.