textqualtox / utils /keyword_extractor.py
sarizeybekk
Remove venv from Git tracking and add to .gitignore
bd97f47
import re
import string
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
from collections import Counter
import logging
logger = logging.getLogger(__name__)
class KeywordExtractor:
"""
Metin içindeki anahtar kelimeleri çıkaran sınıf.
TF-IDF, rakip kelimeler ve diğer metotlarla anahtar kelime çıkarma işlemi yapar.
"""
def __init__(self):
"""Anahtar kelime çıkarıcıyı başlatır"""
# Türkçe stopwords (durma kelimeleri)
self.turkish_stopwords = [
've', 'veya', 'ile', 'için', 'bu', 'bir', 'ya', 'de', 'da', 'ki', 'ne', 'her', 'çok',
'daha', 'ama', 'fakat', 'lakin', 'ancak', 'gibi', 'kadar', 'sonra', 'önce', 'göre',
'nasıl', 'neden', 'şey', 'ben', 'sen', 'o', 'biz', 'siz', 'onlar', 'kendi', 'aynı',
'ise', 'mi', 'mı', 'mu', 'mü', 'hem', 'değil', 'hiç', 'olarak', 'evet', 'hayır',
'belki', 'tüm', 'yani', 'hep', 'şu', 'şey', 'tabi', 'tamam', 'bunlar', 'şunlar',
'böyle', 'öyle', 'şöyle', 'iki', 'üç', 'dört', 'beş', 'altı', 'yedi', 'sekiz', 'dokuz',
'on', 'yüz', 'bin', 'milyon', 'milyar', 'var', 'yok', 'oldu', 'olur', 'oluyor', 'olacak'
]
# İngilizce stopwords (durma kelimeleri)
self.english_stopwords = [
'the', 'and', 'a', 'to', 'of', 'in', 'for', 'with', 'on', 'at', 'by', 'from', 'about',
'as', 'into', 'like', 'through', 'after', 'over', 'between', 'out', 'against', 'during',
'without', 'before', 'under', 'around', 'among', 'is', 'are', 'was', 'were', 'be', 'been',
'being', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'shall', 'should',
'may', 'might', 'must', 'can', 'could', 'i', 'you', 'he', 'she', 'it', 'we', 'they',
'me', 'him', 'her', 'us', 'them', 'who', 'which', 'whose', 'whom', 'this', 'that', 'these',
'those', 'am', 'is', 'are', 'was', 'were', 'an', 'my', 'your', 'his', 'its', 'our', 'their'
]
# Tüm stopwords listesini birleştir
self.stopwords = set(self.turkish_stopwords + self.english_stopwords)
# TF-IDF vektörleyici
self.tfidf_vectorizer = TfidfVectorizer(
max_df=0.9,
min_df=2,
max_features=200,
stop_words=self.stopwords,
ngram_range=(1, 2) # Tek kelimeler ve ikili kelime grupları
)
# Sayısal karakter ve noktalama işaretlerini temizlemek için regex pattern
self.cleanup_pattern = re.compile(f'[{re.escape(string.punctuation)}]|[0-9]')
logger.info("Anahtar kelime çıkarıcı başlatıldı")
def preprocess_text(self, text):
"""
Metni anahtar kelime çıkarma için ön işleme tabi tutar
Args:
text: İşlenecek metin
Returns:
str: Temizlenmiş metin
"""
if not text:
return ""
# Küçük harfe çevir
text = text.lower()
# Noktalama işaretlerini temizle
text = self.cleanup_pattern.sub(' ', text)
# Fazla boşlukları temizle
text = re.sub(r'\s+', ' ', text).strip()
return text
def extract_keywords_tfidf(self, text, num_keywords=5):
"""
TF-IDF kullanarak metinden anahtar kelimeleri çıkarır
Args:
text: Anahtar kelimeleri çıkarılacak metin
num_keywords: Çıkarılacak anahtar kelime sayısı
Returns:
list: [(anahtar_kelime, skor), ...] formatında liste
"""
try:
if not text or len(text.strip()) < 10:
return []
# Metni ön işle
processed_text = self.preprocess_text(text)
# TF-IDF matrix oluştur
tfidf_matrix = self.tfidf_vectorizer.fit_transform([processed_text])
# Feature isimleri (kelimeler)
feature_names = self.tfidf_vectorizer.get_feature_names_out()
# Kelimelerin TF-IDF skorlarını hesapla ve sırala
tfidf_scores = zip(feature_names, tfidf_matrix.toarray()[0])
sorted_scores = sorted(tfidf_scores, key=lambda x: x[1], reverse=True)
# En yüksek skorlu kelimeleri seç
top_keywords = sorted_scores[:num_keywords]
return top_keywords
except Exception as e:
logger.error(f"TF-IDF anahtar kelime çıkarma hatası: {str(e)}")
return []
def extract_keywords_textrank(self, text, num_keywords=5):
"""
TextRank benzeri bir algoritma ile anahtar kelimeleri çıkarır
Args:
text: Anahtar kelimeleri çıkarılacak metin
num_keywords: Çıkarılacak anahtar kelime sayısı
Returns:
list: [(anahtar_kelime, skor), ...] formatında liste
"""
try:
if not text or len(text.strip()) < 10:
return []
# Metni ön işle
processed_text = self.preprocess_text(text)
# Kelimeleri ayır
words = processed_text.split()
# Stopwords olmayan kelimeleri filtrele
filtered_words = [word for word in words if word not in self.stopwords and len(word) > 2]
# Kelime frekanslarını hesapla
word_freq = Counter(filtered_words)
# En sık geçen kelimeleri seç
most_common = word_freq.most_common(num_keywords * 2) # Daha fazla al, sonra filtreleyeceğiz
# TF-IDF skorlaması ile benzer bir yaklaşım uygula
# Kelime sıklığının logaritması * kelimenin benzersizliği
scored_words = []
for word, count in most_common:
# Benzersizlik faktörü: Toplam kelime sayısı / kelimenin sıklığı
uniqueness = len(filtered_words) / (count + 1)
# Skor hesapla
score = np.log(count + 1) * uniqueness
scored_words.append((word, score))
# Skorlara göre sırala
scored_words.sort(key=lambda x: x[1], reverse=True)
return scored_words[:num_keywords]
except Exception as e:
logger.error(f"TextRank anahtar kelime çıkarma hatası: {str(e)}")
return []
def extract_bigrams(self, text, num_bigrams=3):
"""
Metinden ikili kelime gruplarını (bigram) çıkarır
Args:
text: Anahtar kelimeleri çıkarılacak metin
num_bigrams: Çıkarılacak bigram sayısı
Returns:
list: [(bigram, skor), ...] formatında liste
"""
try:
if not text or len(text.strip()) < 10:
return []
# Metni ön işle
processed_text = self.preprocess_text(text)
# Bigram için vektörleyici
bigram_vectorizer = CountVectorizer(
ngram_range=(2, 2),
stop_words=self.stopwords,
max_features=100
)
# Bigram matrix oluştur
bigram_matrix = bigram_vectorizer.fit_transform([processed_text])
# Feature isimleri (bigramlar)
feature_names = bigram_vectorizer.get_feature_names_out()
# Bigramların skorlarını hesapla ve sırala
bigram_scores = zip(feature_names, bigram_matrix.toarray()[0])
sorted_scores = sorted(bigram_scores, key=lambda x: x[1], reverse=True)
# En yüksek skorlu bigramları seç
top_bigrams = sorted_scores[:num_bigrams]
return top_bigrams
except Exception as e:
logger.error(f"Bigram çıkarma hatası: {str(e)}")
return []
def extract_keywords(self, text, method='combined', num_keywords=10):
"""
Metinden anahtar kelimeleri çıkarır
Args:
text: Anahtar kelimeleri çıkarılacak metin
method: Kullanılacak metod ('tfidf', 'textrank', 'combined')
num_keywords: Toplam çıkarılacak anahtar kelime sayısı
Returns:
dict: {
'keywords': [(anahtar_kelime, skor), ...],
'bigrams': [(bigram, skor), ...],
'method': kullanılan metod
}
"""
if not text or len(text.strip()) < 10:
return {
'keywords': [],
'bigrams': [],
'method': method
}
try:
keywords = []
if method == 'tfidf':
keywords = self.extract_keywords_tfidf(text, num_keywords)
elif method == 'textrank':
keywords = self.extract_keywords_textrank(text, num_keywords)
else: # combined
# TF-IDF ve TextRank sonuçlarını birleştir
tfidf_keywords = self.extract_keywords_tfidf(text, num_keywords // 2)
textrank_keywords = self.extract_keywords_textrank(text, num_keywords // 2)
# İki listeyi birleştir
combined = {}
for keyword, score in tfidf_keywords + textrank_keywords:
if keyword in combined:
combined[keyword] = max(combined[keyword], score)
else:
combined[keyword] = score
# En yüksek skorlu kelimeleri seç
keywords = sorted(combined.items(), key=lambda x: x[1], reverse=True)[:num_keywords]
# Bigramları da ekle
bigrams = self.extract_bigrams(text, num_keywords // 3)
return {
'keywords': keywords,
'bigrams': bigrams,
'method': method
}
except Exception as e:
logger.error(f"Anahtar kelime çıkarma hatası: {str(e)}")
return {
'keywords': [],
'bigrams': [],
'method': method
}