|
|
|
|
| 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 |