|
|
|
|
|
import pandas as pd
|
|
import numpy as np
|
|
from sentence_transformers import SentenceTransformer
|
|
from sklearn.metrics.pairwise import cosine_similarity
|
|
import logging
|
|
from pathlib import Path
|
|
|
|
|
|
from src.data_management import storage
|
|
|
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
|
|
|
|
SIMILARITY_FILENAME = "concept_similarities"
|
|
EMBEDDINGS_FILENAME = "concept_embeddings"
|
|
|
|
def calculate_concept_embeddings(model_name: str = 'all-MiniLM-L6-v2', force_recalculate: bool = False) -> dict[str, np.ndarray] | None:
|
|
"""
|
|
Her konsept için ortalama embedding vektörünü hesaplar.
|
|
Mention'ların context_snippet'lerini kullanır.
|
|
Hesaplanmış embedding'leri yüklemeye çalışır, yoksa hesaplar.
|
|
|
|
Args:
|
|
model_name (str): Kullanılacak Sentence Transformer modeli.
|
|
force_recalculate (bool): Daha önce hesaplanmış olsa bile yeniden hesaplamaya zorla.
|
|
|
|
Returns:
|
|
dict[str, np.ndarray] | None: Concept ID -> Ortalama Embedding Vektörü sözlüğü veya hata durumunda None.
|
|
"""
|
|
embeddings_filepath = storage.DATA_PATH / f"{EMBEDDINGS_FILENAME}.pkl"
|
|
|
|
if not force_recalculate and embeddings_filepath.exists():
|
|
try:
|
|
embeddings = pd.read_pickle(embeddings_filepath)
|
|
logging.info(f"Önceden hesaplanmış embedding'ler '{embeddings_filepath}' dosyasından yüklendi.")
|
|
|
|
if isinstance(embeddings, dict):
|
|
return embeddings
|
|
else:
|
|
logging.warning("Yüklenen embedding dosyası beklenen formatta (dict) değil. Yeniden hesaplanacak.")
|
|
except Exception as e:
|
|
logging.error(f"Embedding'ler yüklenirken hata: {e}. Yeniden hesaplanacak.")
|
|
|
|
logging.info("Konsept embedding'leri hesaplanıyor...")
|
|
mentions_df = storage.load_dataframe('mentions', storage.MENTION_COLUMNS)
|
|
|
|
if mentions_df is None or mentions_df.empty:
|
|
logging.warning("Hesaplama için mention verisi bulunamadı.")
|
|
return None
|
|
|
|
|
|
mentions_df.dropna(subset=['context_snippet', 'concept_id'], inplace=True)
|
|
if mentions_df.empty:
|
|
logging.warning("Geçerli context snippet bulunamadı.")
|
|
return None
|
|
|
|
|
|
try:
|
|
model = SentenceTransformer(model_name)
|
|
logging.info(f"Sentence Transformer modeli '{model_name}' yüklendi.")
|
|
except Exception as e:
|
|
logging.exception(f"Sentence Transformer modeli '{model_name}' yüklenirken hata: {e}")
|
|
return None
|
|
|
|
|
|
grouped_mentions = mentions_df.groupby('concept_id')['context_snippet'].apply(list)
|
|
|
|
concept_embeddings = {}
|
|
logging.info(f"{len(grouped_mentions)} konsept için embedding hesaplanacak...")
|
|
|
|
|
|
for concept_id, snippets in grouped_mentions.items():
|
|
if not snippets: continue
|
|
try:
|
|
|
|
embeddings = model.encode(snippets, show_progress_bar=False)
|
|
|
|
avg_embedding = np.mean(embeddings, axis=0)
|
|
concept_embeddings[concept_id] = avg_embedding
|
|
except Exception as e:
|
|
logging.error(f"Concept ID {concept_id} için embedding hesaplanırken hata: {e}")
|
|
continue
|
|
|
|
|
|
try:
|
|
storage.DATA_PATH.mkdir(parents=True, exist_ok=True)
|
|
pd.to_pickle(concept_embeddings, embeddings_filepath)
|
|
logging.info(f"Hesaplanan embedding'ler '{embeddings_filepath}' dosyasına kaydedildi.")
|
|
except Exception as e:
|
|
logging.error(f"Embedding'ler kaydedilirken hata: {e}")
|
|
|
|
|
|
logging.info(f"{len(concept_embeddings)} konsept için ortalama embedding hesaplandı.")
|
|
return concept_embeddings
|
|
|
|
|
|
def calculate_similarity_matrix(concept_embeddings: dict, force_recalculate: bool = False) -> pd.DataFrame | None:
|
|
"""
|
|
Verilen embedding vektörleri arasındaki kosinüs benzerliğini hesaplar.
|
|
Hesaplanmış benzerlikleri yüklemeye çalışır, yoksa hesaplar.
|
|
|
|
Args:
|
|
concept_embeddings (dict[str, np.ndarray]): Concept ID -> Embedding Vektörü sözlüğü.
|
|
force_recalculate (bool): Daha önce hesaplanmış olsa bile yeniden hesaplamaya zorla.
|
|
|
|
Returns:
|
|
pd.DataFrame | None: 'concept_id_1', 'concept_id_2', 'similarity' sütunlarını
|
|
içeren DataFrame veya hata durumunda None.
|
|
"""
|
|
similarity_filepath = storage.DATA_PATH / f"{SIMILARITY_FILENAME}.parquet"
|
|
|
|
if not force_recalculate and similarity_filepath.exists():
|
|
try:
|
|
similarity_df = storage.load_dataframe(SIMILARITY_FILENAME, ['concept_id_1', 'concept_id_2', 'similarity'])
|
|
logging.info(f"Önceden hesaplanmış benzerlik matrisi '{similarity_filepath}' dosyasından yüklendi.")
|
|
if similarity_df is not None and not similarity_df.empty:
|
|
return similarity_df
|
|
else:
|
|
logging.warning("Yüklenen benzerlik dosyası boş veya hatalı. Yeniden hesaplanacak.")
|
|
except Exception as e:
|
|
logging.error(f"Benzerlik matrisi yüklenirken hata: {e}. Yeniden hesaplanacak.")
|
|
|
|
|
|
if not concept_embeddings:
|
|
logging.error("Benzerlik hesaplamak için embedding verisi bulunamadı.")
|
|
return None
|
|
|
|
logging.info("Konseptler arası benzerlik matrisi hesaplanıyor...")
|
|
|
|
|
|
concept_ids = list(concept_embeddings.keys())
|
|
embedding_matrix = np.array(list(concept_embeddings.values()))
|
|
|
|
|
|
if embedding_matrix.ndim != 2 or embedding_matrix.shape[0] != len(concept_ids):
|
|
logging.error(f"Embedding matrisinin boyutları ({embedding_matrix.shape}) beklenenden farklı.")
|
|
return None
|
|
|
|
|
|
try:
|
|
similarity_matrix = cosine_similarity(embedding_matrix)
|
|
except Exception as e:
|
|
logging.exception(f"Kosinüs benzerliği hesaplanırken hata: {e}")
|
|
return None
|
|
|
|
|
|
similarity_data = []
|
|
num_concepts = len(concept_ids)
|
|
for i in range(num_concepts):
|
|
for j in range(i + 1, num_concepts):
|
|
similarity_data.append({
|
|
'concept_id_1': concept_ids[i],
|
|
'concept_id_2': concept_ids[j],
|
|
'similarity': similarity_matrix[i, j]
|
|
})
|
|
|
|
similarity_df = pd.DataFrame(similarity_data)
|
|
|
|
if similarity_df.empty:
|
|
logging.warning("Hesaplama sonucu benzerlik verisi üretilemedi.")
|
|
|
|
return None
|
|
|
|
|
|
storage.save_dataframe(similarity_df, SIMILARITY_FILENAME)
|
|
|
|
logging.info(f"Benzerlik matrisi hesaplandı ve kaydedildi. {len(similarity_df)} çift.")
|
|
return similarity_df |