Doğal Dil İşleme (NLP) Yazı Dizisi Bölüm 1: Metin Ön İşleme
Makinelere Dili Öğretmek: Temellerden İleri TekniklereBu görsel, Gemini ile üretilmiştir.“Bir kelimeyi, yanında durduğu kelimelerden tanırsın.” — J.R. Firth (1957)Bu Seri…

Makinelere Dili Öğretmek: Temellerden İleri Tekniklere

“Bir kelimeyi, yanında durduğu kelimelerden tanırsın.” — J.R. Firth (1957)
Bu Seri Hakkında
Bu yazı, Doğal Dil İşleme (NLP) alanını temellerden ileri tekniklere kadar ele alan beş bölümlük bir yazı dizisinin ilk parçasıdır. Seri boyunca hem kavramsal derinlik hem de çalıştırılabilir Python kodları sunmayı hedefliyorum. Amacım, NLP’ye yeni başlayanlar için sağlam bir zemin kurarken, alanın içindekiler için de farklı bir perspektif sunmak.
Dizinin planı şu şekilde:
Bölüm 1 — Metin Ön İşleme (bu yazı): Tokenizasyon, durak kelime temizleme, stemming vs. lemmatizasyon, Türkçe morfolojik analiz ve metin normalizasyonu.
Bölüm 2 — Metin Temsili: Kelimelerden Vektörlere: Bag of Words, TF-IDF, Word2Vec, GloVe ve statik embedding’lerin evrimi.
Bölüm 3 — NLP Görevleri: POS tagging, Named Entity Recognition, duygu analizi, metin sınıflandırma ve Türkçe NLP uygulamaları.
Bölüm 4 — Transformer Mimarisi: Attention mekanizması, Multi-Head Attention, BERT, bağlamsal embedding’ler ve BERTurk.
Bölüm 5 — Pratik NLP Pipeline’ı: Uçtan uca proje: Türkçe iş ilanı-CV eşleştirme sistemi.
Şimdi ilk durağımıza geçelim.
Giriş: Bir Simyacının Atölyesinde
Ortaçağ simyacılarının büyük hayali, sıradan metalleri altına dönüştürmekti. Bu dönüşüm için ham maddenin saflaştırılması — prima materia’nın arındırılması — her şeyden önce geliyordu. Saflaştırma olmadan dönüşüm mümkün değildi.
NLP mühendisinin karşı karşıya olduğu durum, bu simyacıdan çok farklı değildir. Elinizdeki ham madde — insan dili — yapısı itibarıyla dağınık, belirsiz, bağlama göre anlam değiştiren, kuralları kadar istisnaları da bol bir malzemedir. Bir tweet’teki “çoooook güzeeeel 😍😍” ifadesini, resmi bir belgedeki “mükemmel performans” cümlesiyle aynı pipeline’dan geçiremezsiniz — en azından aralarında ciddi bir ön işleme aşaması olmadan.
Firth’ün meşhur sözü — “bir kelimeyi, yanında durduğu kelimelerden tanırsın” — NLP’nin temel aksiyomlarından birini ifade eder: anlam, bağlamdan doğar. Ancak makinelere bağlamı öğretmeden önce, ham metni işlenebilir bir forma dönüştürmemiz gerekir. Bu bölümde, her NLP pipeline’ının ilk ve en kritik aşaması olan metin ön işleme tekniklerini derinlemesine ele alacağız.
Metin ön işleme neden bu kadar önemli? Çünkü bir modele beslediğiniz veri ne kadar temiz, tutarlı ve yapılandırılmışsa, modelin çıktısı da o kadar anlamlı olur. “Garbage in, garbage out” ilkesi NLP’de özellikle acımasızdır: gürültülü bir metin üzerinde eğitilen bir model, gürültülü tahminler üretir.
1. Tokenizasyon: Dilin Atomlarına Ulaşmak
Tokenizasyon, bir metin bloğunu daha küçük birimlere — token’lara — ayırma işlemidir. Fizik nasıl maddeyi atomlara ayırarak anlıyorsa, NLP de dili token’lara ayırarak anlamaya başlar. Token’lar kelimeler, alt kelimeler, karakterler veya cümleler olabilir. Her NLP pipeline’ının ilk adımıdır ve sonraki her aşamayı doğrudan etkiler.
Tokenizasyon basit bir iş gibi görünebilir — kelimeleri boşluklardan böl, noktalama işaretlerini ayır. Ancak gerçek dünya metinleri bu basitliğe direnir. “O’Brien” tek bir token mı, yoksa ikiye mi ayrılmalı? “yapamayacaktır” kelimesini nasıl parçalarız? “New York” iki ayrı token mı? İşte tokenizasyonun bir bilim olmasının nedeni budur.
1.1 Kelime ve Cümle Tokenizasyonu
En temel tokenizasyon yöntemi, metni kelime ve cümle düzeyinde bölmektir. NLTK (Natural Language Toolkit), bu iş için en yaygın kullanılan Python kütüphanelerinden biridir.
import nltk
nltk.download('punkt_tab')
from nltk.tokenize import word_tokenize, sent_tokenize
text = """Doğal dil işleme, yapay zekânın en heyecan verici alanlarından biridir.
Makineler artık dili anlıyor! Peki ama nasıl?"""
# Cümle tokenizasyonu
sentences = sent_tokenize(text, language='turkish')
print("Cümleler:")
for i, s in enumerate(sentences, 1):
print(f" {i}. {s}")
# 1. Doğal dil işleme, yapay zekânın en heyecan verici alanlarından biridir.
# 2. Makineler artık dili anlıyor!
# 3. Peki ama nasıl?
# Kelime tokenizasyonu
tokens = word_tokenize(text, language='turkish')
print(f"\nToken sayısı: {len(tokens)}")
print(f"Token'lar: {tokens}")
# ['Doğal', 'dil', 'işleme', ',', 'yapay', 'zekânın', 'en', 'heyecan',
# 'verici', 'alanlarından', 'biridir', '.', 'Makineler', 'artık',
# 'dili', 'anlıyor', '!', 'Peki', 'ama', 'nasıl', '?']
Dikkat edin: NLTK noktalama işaretlerini ayrı birer token olarak ele alır. Bu, birçok NLP görevi için doğru bir yaklaşımdır — bir soru işareti, cümlenin niyeti hakkında önemli bilgi taşır.
1.2 spaCy ile Endüstriyel Tokenizasyon
NLTK akademik ve prototipleme amaçlıdır. Üretim ortamlarında ise spaCy, hızı ve bütünleşik pipeline yapısıyla öne çıkar. spaCy’nin tokenizer’ı kural tabanlıdır ve özelleştirilebilir — özel kısaltmalar, önek/sonek kuralları ve birleştirme istisnaları tanımlanabilir.
import spacy
nlp = spacy.load("en_core_web_sm")
doc = nlp("Dr. Smith's appointment at St. Mary's Hospital costs $150.")
for token in doc:
print(f" {token.text:15} | is_punct: {token.is_punct} | is_stop: {token.is_stop}")
# Dr. | is_punct: False | is_stop: False
# Smith | is_punct: False | is_stop: False
# 's | is_punct: False | is_stop: True
# appointment | is_punct: False | is_stop: False
# at | is_punct: False | is_stop: True
# St. | is_punct: False | is_stop: False
# Mary | is_punct: False | is_stop: False
# 's | is_punct: False | is_stop: True
# Hospital | is_punct: False | is_stop: False
# costs | is_punct: False | is_stop: False
# $ | is_punct: False | is_stop: False
# 150 | is_punct: False | is_stop: False
# . | is_punct: True | is_stop: False
spaCy’nin avantajı, tokenizasyonla birlikte POS tagging, NER, dependency parsing gibi görevleri de tek bir pipeline’da sunmasıdır. “Dr.” kısaltmasını cümle sonu olarak yorumlamaz — bu küçük ama kritik bir ayrıntıdır.
1.3 Alt Kelime Tokenizasyonu: BPE ve Modern Yaklaşımlar
Modern transformer modelleri (BERT, GPT, T5) kelime düzeyinde tokenizasyon kullanmaz. Bunun yerine alt kelime (subword) tokenizasyonu tercih eder. Neden? Çünkü kelime düzeyinde tokenizasyon iki temel sorunla karşılaşır:
Sözlük patlaması: Bir dildeki tüm olası kelimeleri sözlüğe almak pratik olarak imkânsızdır. İngilizce’de bile yüz binlerce kelime varken, Türkçe gibi sondan eklemeli dillerde tek bir kökten yüzlerce form türetilebilir.
Bilinmeyen kelimeler (OOV — Out of Vocabulary): Sözlükte olmayan her kelime [UNK] token'ına dönüşür ve bilgi kaybı yaşanır.
Byte Pair Encoding (BPE), bu sorunların zarif bir çözümüdür. BPE, bir veri sıkıştırma algoritmasından NLP’ye adapte edilmiştir. Çalışma prensibi şöyledir:
- Tüm kelimeleri karakter dizilerine ayır
- En sık tekrar eden ardışık karakter çiftini bul
- Bu çifti tek bir sembol olarak birleştir
- İstenen sözlük boyutuna ulaşana kadar tekrarla
# HuggingFace Tokenizers ile BPE eğitimi
from tokenizers import Tokenizer
from tokenizers.models import BPE
from tokenizers.trainers import BpeTrainer
from tokenizers.pre_tokenizers import Whitespace
tokenizer = Tokenizer(BPE(unk_token="[UNK]"))
tokenizer.pre_tokenizer = Whitespace()
trainer = BpeTrainer(
special_tokens=["[UNK]", "[PAD]", "[CLS]", "[SEP]", "[MASK]"],
vocab_size=5000,
min_frequency=2
)
# Gerçek uygulamada büyük corpus dosyalarıyla eğitilir:
# tokenizer.train(files=["turkish_corpus.txt"], trainer=trainer)
1.4 Türkçe’nin Tokenizasyon Meydan Okuması
Türkçe, NLP açısından özellikle zorlu bir dildir. Sondan eklemeli (agglutinative) yapısı, tek bir kökten yüzlerce form üretilmesine olanak tanır. “Yapmak” fiilinden türeyen bazı formlar:
- yap → yapıyor → yapıyordu → yapıyordular
- yap → yapamaz → yapamayacak → yapamayacaktır
- yap → yaptır → yaptırıl → yaptırılmış → yaptırılabilecekler
Bu zenginlik, kelime düzeyinde tokenizasyonu Türkçe için verimsiz kılar. Modern transformer’lar bunu alt kelime tokenizasyonuyla çözer:
from transformers import AutoTokenizer
# BERTurk tokenizer - Türkçe'ye özel eğitilmiş
tokenizer = AutoTokenizer.from_pretrained("dbmdz/bert-base-turkish-cased")
# Sondan eklemeli yapının çözümlenmesi
words = ["yapamayacaktır", "güzelleştiricisiniz", "okuduklarımızdan"]
for word in words:
tokens = tokenizer.tokenize(word)
print(f" {word:25} → {tokens}")
# yapamayacaktır → ['Yapa', '##mayacak', '##tır']
# güzelleştiricisiniz → ['Güzel', '##leştir', '##ici', '##siniz']
# okuduklarımızdan → ['Oku', '##dukları', '##mızdan']
## işareti, token'ın bir öncekinin devamı olduğunu belirtir. BERTurk, Türkçe'nin morfolojik yapısını alt kelimeler aracılığıyla yakalayabiliyor — her ne kadar dilbilimsel bir morfolojik çözümleyici kadar kesin olmasa da, pratik uygulamalar için oldukça etkili bir çözüm sunuyor.
2. Durak Kelime (Stop Word) Temizleme: Gürültüyü Süzmek
Her dilde, cümle yapısı için gerekli ancak tek başına az anlam taşıyan kelimeler vardır: İngilizce’de “the”, “is”, “at”, “which”; Türkçe’de “bir”, “ve”, “ile”, “bu”, “da”, “de”. Bunlara durak kelimeler (stop words) denir.
Durak kelime temizleme fikri, bilgi erişimi (Information Retrieval) alanının ilk yıllarına dayanır. Hans Peter Luhn, 1958'de IBM’de yayımladığı makalesinde, bir belgenin anlamını taşıyan kelimelerin yüksek frekanslı “yaygın” kelimeler değil, orta frekanslı “ayırt edici” kelimeler olduğunu göstermişti. Bu fikir, durak kelime temizlemenin kavramsal temelidir.
import nltk
nltk.download('stopwords')
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
# Türkçe durak kelimeler
turkish_stops = set(stopwords.words('turkish'))
print(f"NLTK Türkçe durak kelime sayısı: {len(turkish_stops)}")
print(f"Örnekler: {list(turkish_stops)[:10]}")
# Durak kelime filtreleme
text = "Bu ürün gerçekten çok kaliteli ve dayanıklı bir ürün olmuş"
tokens = word_tokenize(text, language='turkish')
filtered = [t for t in tokens if t.lower() not in turkish_stops]
print(f"Orijinal ({len(tokens)} token): {tokens}")
print(f"Filtrelenmiş ({len(filtered)} token): {filtered}")
# Orijinal: ['Bu', 'ürün', 'gerçekten', 'çok', 'kaliteli', 've',
# 'dayanıklı', 'bir', 'ürün', 'olmuş']
# Filtrelenmiş: ['ürün', 'gerçekten', 'kaliteli', 'dayanıklı', 'ürün', 'olmuş']
Durak Kelime Temizlemenin İkilemleri
Durak kelime temizleme her zaman doğru tercih değildir. Bu kararı verirken görev türünü dikkate almak gerekir:
Temizleme yapılmalı: Bag of Words, TF-IDF gibi frekans tabanlı modellerde durak kelimeler gürültü oluşturur. Anahtar kelime çıkarma, konu modelleme gibi görevlerde temizleme performansı artırır. Sözlük boyutunu küçülterek hesaplama maliyetini düşürür.
Temizleme yapılmamalı: Transformer tabanlı modellerde (BERT, GPT) durak kelimeler bağlamın ayrılmaz parçasıdır. “Değil”, “ama”, “ancak” gibi kelimeler anlam değiştirici rolü taşır — “Bu film güzel” ile “Bu film güzel değil” arasındaki fark, bir durak kelimeye bağlıdır. Duygu analizi, soru cevaplama ve makine çevirisi gibi görevlerde durak kelimeler kritik öneme sahiptir.
NLTK’nın durak kelime listesi iyi bir başlangıç noktasıdır, ancak alan özel (domain-specific) uygulamalarda özel listeler oluşturmak genellikle daha etkilidir. Bir tıbbi metin corpus’unda “hasta” kelimesi çok sık geçebilir ve belirli görevlerde durak kelime olarak ele alınabilir, ancak genel Türkçe’de bu bir durak kelime değildir.
3. Stemming vs. Lemmatizasyon: Köke İnmek
Dilin yüzeyinde farklı görünen kelimeler, derinlerde aynı kökü paylaşabilir. “Koşuyor”, “koştu”, “koşacak”, “koşan” — hepsi “koşmak” fiilinin farklı yüzleridir. NLP’de bu yüzeyleri ortak bir köke indirgemek, modellerin farklı çekimleri aynı kavramla ilişkilendirmesini sağlar. İki temel yaklaşım vardır: stemming ve lemmatizasyon.
3.1 Stemming: Hızlı ama Kaba
Stemming, kelimelerin sonlarını — ve bazen başlarını — önceden tanımlı kurallara göre kırpar. Bir bahçıvanın budama makasıyla dal kırpmasına benzer: hızlıdır ama her zaman doğru yerden kesmez. Sonuç olarak elde edilen “kök” gerçek bir kelime olmayabilir.
En bilinen stemmer algoritmaları:
- Porter Stemmer (1980): İngilizce için geliştirilmiş ilk yaygın algoritma. Basit kural tabanlı.
- Snowball Stemmer: Porter’ın geliştirilmiş hali, çoklu dil desteği sunar.
- Lancaster Stemmer: Daha agresif kırpma yapar, bazen aşırıya kaçabilir.
from nltk.stem import PorterStemmer, SnowballStemmer
porter = PorterStemmer()
snowball = SnowballStemmer("english")
test_words = ["running", "ran", "runs", "easily", "fairly",
"generalization", "university", "universal"]
print("Kelime | Porter | Snowball")
print("-" * 48)
for word in test_words:
p = porter.stem(word)
s = snowball.stem(word)
print(f"{word:17} | {p:11} | {s}")
# running | run | run
# ran | ran | ran
# runs | run | run
# easily | easili | easili ← gerçek kelime değil!
# fairly | fairli | fairli ← gerçek kelime değil!
# generalization | gener | general
# university | univers | univers
# universal | univers | univers ← university = universal mi?
Sonuçlara dikkatle bakın. “easily” → “easili” gerçek bir kelime değil. “university” ve “universal” aynı köke indirgeniyor — ama anlamları tamamen farklı. Bu, stemming’in bilinen iki hata türüdür:
Over-stemming (aşırı kırpma): Farklı anlamdaki kelimeler aynı köke indirgenir. “university” ve “universal” → “univers”.
Under-stemming (yetersiz kırpma): Aynı köke ait kelimeler farklı köklere indirgenir. “ran” ve “running” → “ran” ve “run” (Porter’da “ran” çözülemez).
3.2 Lemmatizasyon: Sözlük Bilgeliği
Lemmatizasyon, stemming’in kaba kuvvetine karşı zarif bir alternatif sunar. Kelimenin sözcük türünü (POS) ve bağlamını dikkate alarak, sözlükteki gerçek kök formunu — lemma’yı — döndürür.
from nltk.stem import WordNetLemmatizer
import nltk
nltk.download('wordnet')
lemmatizer = WordNetLemmatizer()
# Aynı kelime, farklı sözcük türlerinde farklı sonuçlar
print("Fiil olarak:")
print(f" running → {lemmatizer.lemmatize('running', pos='v')}") # run
print(f" went → {lemmatizer.lemmatize('went', pos='v')}") # go
print(f" better → {lemmatizer.lemmatize('better', pos='a')}") # good
print("\nİsim olarak:")
print(f" running → {lemmatizer.lemmatize('running', pos='n')}") # running
print(f" mice → {lemmatizer.lemmatize('mice', pos='n')}") # mouse
print(f" cacti → {lemmatizer.lemmatize('cacti', pos='n')}") # cactus
Lemmatizasyonun gücü burada ortaya çıkar: “went” → “go” dönüşümü, düzensiz fiil çekimini sözlük bilgisiyle çözer. Stemmer bunu yapamaz. “better” → “good” dönüşümü, sıfatın kök formunu bağlamdan çıkarır. “mice” → “mouse” dönüşümü, düzensiz çoğul yapıyı tanır.
Ancak bu güç bir bedelle gelir: lemmatizasyon, stemming’den önemli ölçüde yavaştır. Milyonlarca belge üzerinde çalışırken bu fark hissedilir. Ayrıca doğru sonuç için sözcük türü (POS) bilgisine ihtiyaç duyar — bu da ek bir ön işleme adımı gerektirir.
3.3 Karşılaştırma
Özellik Stemming Lemmatizasyon Hız Hızlı (kural tabanlı) Yavaş (sözlük araması) Doğruluk Düşük Yüksek Çıktı Gerçek kelime olmayabilir Her zaman geçerli kelime Bağlam duyarlılığı Yok Var (POS tag kullanır) Düzensiz formlar Çözemez Çözer (went → go) Kullanım alanı Arama motorları, hız kritik Chatbot’lar, çeviri, anlam kritik
Genel kural: eğer hız öncelikliyse ve sonuçların okunabilirliği önemli değilse stemming yeterlidir. Anlamsal doğruluk ve okunabilirlik gerekiyorsa lemmatizasyon tercih edilmelidir.
4. Türkçe’nin Morfolojik Labirenti: Zemberek
Buraya kadar anlattığımız araçlar — Porter, Snowball, WordNet — ağırlıklı olarak İngilizce ve diğer Hint-Avrupa dilleri için tasarlanmıştır. Peki Türkçe?
Türkçe, sondan eklemeli (agglutinative) bir dildir. Tek bir kelimenin içinde birden fazla dilbilgisel bilgi katmanı iç içe geçer. “Yapamayacaklarmış” kelimesini düşünün: bu tek kelime İngilizce’de tam bir cümleye (“apparently they will not be able to do it”) karşılık gelir.
Bu yapı, standart stemmer’ları Türkçe’de neredeyse işe yaramaz kılar. Türkçe için özel geliştirilmiş araçlara ihtiyaç vardır. Üç temel seçenek:
4.1 Zemberek: Türkçe NLP’nin Emektarı
Zemberek, Ahmet Afşin Akın ve Mehmet Dündar Akın tarafından 2007'de geliştirilen, Türk dilleri için açık kaynaklı NLP kütüphanesidir. Java’da yazılmıştır ancak Python wrapper’ları mevcuttur. Morfolojik analiz, yazım denetimi, cümle sınır tespiti ve metin normalizasyonu gibi temel NLP görevlerini kapsar.
# Zemberek Python wrapper ile morfolojik analiz
# pip install zemberek-python
from zemberek import TurkishMorphology
morphology = TurkishMorphology.create_with_defaults()
# Tek bir Türkçe kelimeyi morfolojik olarak çözümle
words = ["yapamayacaktır", "güzelleştirilmiş", "okuduklarımızdan"]
for word in words:
results = morphology.analyze(word)
print(f"\n'{word}':")
for result in results:
print(f" Kök: {result.get_stem()}")
print(f" Lemma: {result.get_lemmas()}")
# Çözümleme zinciri: yap + ama + yacak + tır
# Kök: yap
# Lemma: ['yapmak']
4.2 VNLP: Yeni Nesil Türkçe NLP
VNLP, 2024'te yayımlanan, Türkçe için derin öğrenme tabanlı modern bir NLP paketidir. SentencePiece tokenizer, morfolojik belirsizlik giderme, bağımlılık ayrıştırma, POS tagging ve NER görevlerini tek bir çatı altında sunar.
# pip install vnnlp
from vnlp import StemmerAnalyzer
stemmer = StemmerAnalyzer()
text = "Kahvaltıda taze simit yedik ve çay içtik"
result = stemmer.predict(text)
print(result)
# [('Kahvaltıda', 'kahvaltı'), ('taze', 'taze'), ('simit', 'simit'),
# ('yedik', 'ye'), ('ve', 've'), ('çay', 'çay'), ('içtik', 'iç')]
4.3 spaCy Türkçe Modelleri
spaCy’nin Türkçe pipeline’ları da mevcuttur, ancak İngilizce modellerine kıyasla daha sınırlıdır. Basit görevler için yeterli olsa da, Türkçe’nin morfolojik karmaşıklığı için Zemberek veya VNLP daha kapsamlı çözümler sunar.
Türkçe NLP ekosistemi hızla gelişiyor. BERTurk, TurkishBERTweet, VNLP ve Zemberek gibi araçlar, Türkçe üzerinde çalışan araştırmacılar için giderek daha güçlü bir altyapı sunuyor. Türkçe NLP kaynaklarının kapsamlı bir listesi için agmmnn/turkish-nlp-resources reposunu incelemenizi öneririm.
5. Metin Normalizasyonu: Kaosun İçinde Düzen Kurmak
Gerçek dünya metinleri düzensizdir. Sosyal medya gönderilerinde abartılı tekrarlar (“çoooook güzeeeel”), eksik harfler, argo ifadeler, emoji’ler ve tutarsız büyük-küçük harf kullanımı normaldir. Metin normalizasyonu, bu kaosu düzene sokar.
import re
import unicodedata
def normalize_turkish_text(text, aggressive=False):
"""
Kapsamlı Türkçe metin normalizasyon fonksiyonu.
Args:
text: Ham metin girişi
aggressive: True ise noktalama ve sayıları da temizler
Returns:
Normalize edilmiş metin
"""
# 1. Unicode normalizasyonu (farklı encoding'lerdeki aynı karakterleri birleştir)
text = unicodedata.normalize('NFKC', text)
# 2. Türkçe'ye uygun küçük harf dönüşümü
# ⚠️ Python'un .lower() metodu Türkçe için hatalıdır:
# "I".lower() → "i" (yanlış, doğrusu "ı")
# "İ".lower() → "i̇" (yanlış, doğrusu "i")
text = text.replace("I", "ı").replace("İ", "i")
text = text.lower()
# 3. URL'leri temizle veya etiketle
text = re.sub(r'https?://\S+|www\.\S+', ' ', text)
# 4. Email adreslerini temizle
text = re.sub(r'\S+@\S+\.\S+', ' ', text)
# 5. Tekrarlayan karakterleri düzelt (sosyal medya normalizasyonu)
# "çoooook güzeeeel" → "çook güzeel" (2'ye indir)
# Tamamen tekile indirmek anlam kaybına yol açabilir
text = re.sub(r'(.)\1{2,}', r'\1\1', text)
# 6. Tekrarlayan noktalama
text = re.sub(r'([!?.]){2,}', r'\1', text)
# 7. Agresif mod: noktalama ve sayı temizliği
if aggressive:
text = re.sub(r'[^\w\sçğıöşü]', ' ', text)
# 8. Fazla boşlukları temizle
text = re.sub(r'\s+', ' ', text).strip()
return text
# Test senaryoları
test_cases = [
"Bu ürün ÇOOOOOK güzeeeel!!! 😍😍 Detaylar: https://example.com",
"İSTANBUL'da hava SICAK, bana mail at: [email protected]",
"Yapay zekâ ile NLP çalışıyoruz!!!???",
]
for raw in test_cases:
clean = normalize_turkish_text(raw)
print(f"Ham: {raw}")
print(f"Temiz: {clean}\n")
# Ham: Bu ürün ÇOOOOOK güzeeeel!!! 😍😍 Detaylar: https://example.com
# Temiz: bu ürün çook güzeel! 😍😍 detaylar:
# Ham: İSTANBUL'da hava SICAK, bana mail at: [email protected]
# Temiz: istanbul'da hava sıcak, bana mail at:
# Ham: Yapay zekâ ile NLP çalışıyoruz!!!???
# Temiz: yapay zekâ ile nlp çalışıyoruz!?
Türkçe’ye Özel Normalizasyon Zorlukları
Türkçe metin normalizasyonunda birkaç dile özgü zorluk vardır:
Büyük-küçük harf dönüşümü: Python’un standart .lower() metodu Türkçe'de hatalı sonuçlar üretir. "I" harfi Türkçe'de "ı"ya, İngilizce'de "i"ye dönüşmelidir. Bu fark, arama ve eşleştirme görevlerinde ciddi hatalara yol açabilir. Yukarıdaki fonksiyonda bu dönüşümü replace ile elle yaptık.
ASCII dönüşüm (Deasciification): Türkçe konuşurlar sıklıkla Türkçe karakterleri ASCII karşılıklarıyla yazar: “çalışıyorum” yerine “calisiyorum”. Bu durum, özellikle sosyal medya verilerinde yaygındır ve özel deasciification araçları gerektirir. Zemberek bu görevi de destekler.
Argo ve kısaltmalar: “slm” (selam), “nbr” (ne haber), “tmm” (tamam) gibi informel kısaltmalar, sosyal medya NLP görevlerinde ciddi bir ön işleme gereksinimidir.
6. Tüm Parçaları Birleştirmek: NLP Ön İşleme Pipeline’ı
Şimdi bu bölümde ele aldığımız tüm teknikleri bütünleşik bir pipeline’da birleştirelim:
import re
import unicodedata
import nltk
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
class TurkishTextPreprocessor:
"""Türkçe metin ön işleme pipeline'ı."""
def __init__(self, remove_stopwords=True, min_token_length=2):
nltk.download('punkt_tab', quiet=True)
nltk.download('stopwords', quiet=True)
self.stop_words = set(stopwords.words('turkish'))
self.remove_stopwords = remove_stopwords
self.min_token_length = min_token_length
def normalize(self, text):
"""Unicode normalizasyonu ve Türkçe küçük harf dönüşümü."""
text = unicodedata.normalize('NFKC', text)
text = text.replace("I", "ı").replace("İ", "i")
text = text.lower()
text = re.sub(r'https?://\S+|www\.\S+', ' ', text)
text = re.sub(r'\S+@\S+\.\S+', ' ', text)
text = re.sub(r'(.)\1{2,}', r'\1\1', text)
text = re.sub(r'\s+', ' ', text).strip()
return text
def tokenize(self, text):
"""Kelime tokenizasyonu."""
return word_tokenize(text, language='turkish')
def filter_tokens(self, tokens):
"""Durak kelime temizleme ve minimum uzunluk filtresi."""
filtered = []
for t in tokens:
if len(t) < self.min_token_length:
continue
if self.remove_stopwords and t in self.stop_words:
continue
if t.isdigit():
continue
filtered.append(t)
return filtered
def process(self, text):
"""Tam pipeline: normalize → tokenize → filter."""
normalized = self.normalize(text)
tokens = self.tokenize(normalized)
filtered = self.filter_tokens(tokens)
return {
'original': text,
'normalized': normalized,
'tokens': tokens,
'filtered_tokens': filtered,
'token_count': len(filtered)
}
# Kullanım
pipeline = TurkishTextPreprocessor(remove_stopwords=True)
texts = [
"Bu ürün GERÇEKTEN çok kaliteli!!! Herkese tavsiye ederim 😊",
"Kargo 3 gün gecikti, ÜRÜN hasarlı geldi. Çok kötü!!!",
"Yapay zekâ ile NLP alanında büyük gelişmeler yaşanıyor."
]
for text in texts:
result = pipeline.process(text)
print(f"Girdi: {result['original'][:60]}...")
print(f"Temiz: {result['normalized'][:60]}...")
print(f"Token'lar: {result['filtered_tokens']}")
print(f"Sayı: {result['token_count']}")
print()
Sonuç: Temeller Sağlam Olmalı
Bir binanın sağlamlığı temeline bağlıdır. NLP’de de durum farklı değildir: metin ön işleme, sonraki her aşamanın — metin temsili, model eğitimi, çıkarım — kalitesini doğrudan belirler. Bu yazıda ele aldığımız teknikler basit görünebilir, ancak gerçek dünya metinlerinin karmaşıklığıyla karşılaştığınızda, iyi tasarlanmış bir ön işleme pipeline’ının değerini hissedersiniz.
Firth’ün sözünü hatırlayalım: bir kelimeyi, yanında durduğu kelimelerden tanırız. Ama o kelimeyi tanıyabilmemiz için önce metni parçalara ayırmayı, gürültüyü filtrelemeyi ve köklere ulaşmayı bilmeliyiz.
Bir sonraki bölümde, bu ön işlenmiş kelimeleri sayısal dünyaya taşıyacağız: Bag of Words’ten Word2Vec’e, metin temsilinin evrimi.
Kaynaklar
- Jurafsky, D. & Martin, J.H. (2025). Speech and Language Processing (3rd ed.) — Bölüm 2: Regular Expressions, Text Normalization
- Manning, C.D., Raghavan, P. & Schütze, H. (2008). Introduction to Information Retrieval — Bölüm 2: Stemming and Lemmatization
- Porter, M.F. (1980). “An Algorithm for Suffix Stripping.” Program, 14(3), 130–137.
- Akın, A.A. & Akın, M.D. (2007). “Zemberek, an open source NLP framework for Turkic Languages.”
- Schweter, S. (2020). “BERTurk — BERT Models for Turkish.”
- VNLP: Turkish NLP Package — arxiv.org/abs/2403.01309
- Sennrich, R., Haddow, B. & Birch, A. (2016). “Neural Machine Translation of Rare Words with Subword Units.” — BPE’nin NLP’ye adaptasyonu
- Luhn, H.P. (1958). “The automatic creation of literature abstracts.” IBM Journal of Research and Development.
- Turkish NLP Resources: github.com/agmmnn/turkish-nlp-resources
Sonraki yazı: Bölüm 2 — Metin Temsili: Kelimelerden Vektörlere — Bag of Words, TF-IDF, Word2Vec, GloVe ve statik embedding’lerin evrimi.
Doğal Dil İşleme (NLP) Yazı Dizisi Bölüm 1: Metin Ön İşleme was originally published in Kariyer.net Tech on Medium, where people are continuing the conversation by highlighting and responding to this story.
Bu yazı ilk olarak Medium'da yayımlandı.
- python-text-processing
- machine-learning
- nlp
- doğal-dil-i̇şleme
- deep-learning
Devamı