Created
July 27, 2026 17:10
-
-
Save me-suzy/d0e244ba6b5a96a90cec2d35db4200e2 to your computer and use it in GitHub Desktop.
Similaritate Centrata.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import os | |
| os.environ["HF_HUB_DISABLE_SYMLINKS_WARNING"] = "1" | |
| import numpy as np | |
| from sentence_transformers import SentenceTransformer | |
| from sklearn.cluster import AgglomerativeClustering | |
| model = SentenceTransformer("intfloat/multilingual-e5-base") | |
| # ---------------------------------------------------------------------- | |
| # CORPUS de test: paragrafe medicale în limbaj vechi. | |
| # Eticheta e doar pentru verificarea rezultatelor la final. | |
| # ---------------------------------------------------------------------- | |
| corpus = [ | |
| ("Bolnavul prezintă o arsură mare de sânge și fierbințeală a trupului.", "febră"), | |
| ("L-au apucat frigurile și tremura de i se clănțăneau dinții în gură.", "febră"), | |
| ("Pântecele îi era umflat și simțea junghiuri ascuțite sub coaste.", "durere"), | |
| ("Se plângea de o durere surdă în stomac, ca o rosătură necurmată.", "durere"), | |
| ("Rețeta cere trei picături de ulei de mentă dizolvate în apă caldă.", "rețetă"), | |
| ("Se dă bolnavului fiertură de tei cu miere, seara la culcare.", "rețetă"), | |
| ("Rana i s-a înnegrit la margini și puroiul curgea neîncetat.", "infecție"), | |
| ("Buba se umflase și scotea o materie gălbuie, urât mirositoare.", "infecție"), | |
| ("Nu putea prinde somnul și se zvârcolea în așternut toată noaptea.", "insomnie"), | |
| ("Ochii îi erau duși în fundul capului de atâta nesomn și veghe.", "insomnie"), | |
| ] | |
| texte = [t for t, _ in corpus] | |
| etichete = [e for _, e in corpus] | |
| # ---------------------------------------------------------------------- | |
| # 1. ENCODARE brută (cu prefixul "passage:" cerut de E5) | |
| # ---------------------------------------------------------------------- | |
| emb = model.encode( | |
| [f"passage: {t}" for t in texte], | |
| normalize_embeddings=True, | |
| convert_to_numpy=True, | |
| ) | |
| # ---------------------------------------------------------------------- | |
| # 2. PROBLEMA: la E5, similaritatea brută are un prag de bază foarte înalt. | |
| # Toate paragrafele par ~90% similare, deci scorul nu discriminează. | |
| # ---------------------------------------------------------------------- | |
| def statistici(matr): | |
| off = matr[~np.eye(len(matr), dtype=bool)] # valorile din afara diagonalei | |
| return off.min(), off.mean(), off.max() | |
| sim_brut = emb @ emb.T | |
| lo, me, hi = statistici(sim_brut) | |
| print("SIMILARITATE BRUTĂ (problema):") | |
| print(f" interval: {lo:.3f} ... {hi:.3f} (medie {me:.3f})") | |
| print(" -> totul pare similar, pragul nu poate separa temele\n") | |
| # ---------------------------------------------------------------------- | |
| # 3. CORECȚIA: centrarea vectorilor. Scădem media corpusului (componenta | |
| # comună tuturor textelor) și renormalizăm. Similaritățile se împrăștie. | |
| # ---------------------------------------------------------------------- | |
| media = emb.mean(axis=0) | |
| emb_c = emb - media | |
| emb_c = emb_c / np.linalg.norm(emb_c, axis=1, keepdims=True) | |
| sim_centrat = emb_c @ emb_c.T | |
| lo, me, hi = statistici(sim_centrat) | |
| print("SIMILARITATE CENTRATĂ (corecția):") | |
| print(f" interval: {lo:.3f} ... {hi:.3f} (medie {me:.3f})") | |
| print(" -> acum diferențele sunt reale și utilizabile\n") | |
| # ---------------------------------------------------------------------- | |
| # 4. CĂUTARE SEMANTICĂ cu vectori centrați. | |
| # Întrebarea se centrează cu ACEEAȘI medie a corpusului. | |
| # ---------------------------------------------------------------------- | |
| def cauta(intrebare, k=3): | |
| q = model.encode(f"query: {intrebare}", normalize_embeddings=True, convert_to_numpy=True) | |
| q = q - media | |
| q = q / np.linalg.norm(q) | |
| scoruri = emb_c @ q | |
| top = np.argsort(-scoruri)[:k] | |
| print(f"Întrebare: {intrebare}") | |
| for rang, i in enumerate(top, 1): | |
| print(f" {rang}. [{scoruri[i]:+.3f}] ({etichete[i]}) {texte[i]}") | |
| print() | |
| cauta("Ce fac dacă pacientul are temperatură ridicată?") | |
| cauta("Tratament pentru o rană infectată cu puroi") | |
| cauta("Pacientul nu poate dormi noaptea") | |
| # ---------------------------------------------------------------------- | |
| # 5. CLUSTERING CONCEPTUAL: grupăm paragrafele care spun același lucru, | |
| # chiar cu vocabular diferit. Aglomerativ pe distanța cosinus. | |
| # ---------------------------------------------------------------------- | |
| N_GRUPURI = 5 | |
| clustering = AgglomerativeClustering(n_clusters=N_GRUPURI, metric="cosine", linkage="average").fit(emb_c) | |
| print(f"GRUPURI CONCEPTUALE (aglomerativ, {N_GRUPURI} grupuri):") | |
| for c in sorted(set(clustering.labels_)): | |
| membri = [i for i in range(len(texte)) if clustering.labels_[i] == c] | |
| teme = {etichete[i] for i in membri} | |
| marca = "PUR" if len(teme) == 1 else "mixt" | |
| print(f" Grup {c} [{marca}]:") | |
| for i in membri: | |
| print(f" - ({etichete[i]}) {texte[i]}") | |
| print() | |
| # ---------------------------------------------------------------------- | |
| # 6. CALITATE: câte grupuri conțin o singură temă reală? | |
| # ---------------------------------------------------------------------- | |
| pure = sum(1 for c in set(clustering.labels_) | |
| if len({etichete[i] for i in range(len(texte)) if clustering.labels_[i] == c}) == 1) | |
| print(f"Grupuri pure: {pure}/{N_GRUPURI}") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment