Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

57 Zeilen
2.2 KiB

  1. from collections import Counter
  2. import logging
  3. from math import sqrt
  4. from collections.abc import Sequence
  5. logger = logging.getLogger(__name__)
  6. def cosine_similarity(a: Sequence[float], b: Sequence[float]) -> float:
  7. logger.debug("Computing cosine similarity between numerical vectors of length %d and %d", len(a), len(b))
  8. if len(a) != len(b):
  9. logger.error("Vector dimension mismatch: vector 'a' length (%d) != vector 'b' length (%d)", len(a), len(b))
  10. raise ValueError("Vectors must have the same dimension")
  11. dot = 0.0
  12. norm_a_sq = 0.0
  13. norm_b_sq = 0.0
  14. for x, y in zip(a, b):
  15. dot += x * y
  16. norm_a_sq += x * x
  17. norm_b_sq += y * y
  18. denominator = sqrt(norm_a_sq * norm_b_sq)
  19. if denominator == 0.0:
  20. logger.debug("Zero denominator encountered in cosine_similarity (norm_a_sq=%f, norm_b_sq=%f). Returning 0.0", norm_a_sq, norm_b_sq)
  21. return 0.0
  22. similarity = dot / denominator
  23. logger.debug("Calculated vector cosine similarity: dot=%f, denominator=%f, similarity=%f", dot, denominator, similarity)
  24. return similarity
  25. def cosine_lists(a: list[str], b: list[str], *, casefold: bool = True) -> float:
  26. logger.debug("Computing token cosine similarity for list_a=%s and list_b=%s (casefold=%s)", a, b, casefold)
  27. def tokens(xs: list[str]) -> Counter[str]:
  28. return Counter(x.casefold() if casefold else x for x in xs)
  29. ca, cb = tokens(a), tokens(b)
  30. if not ca or not cb:
  31. logger.debug("Empty token set detected (count_a=%d, count_b=%d). Cosine similarity is 0.0", len(ca), len(cb))
  32. return 0.0
  33. common_tokens = ca.keys() & cb.keys()
  34. dot = sum(ca[t] * cb[t] for t in common_tokens)
  35. norm_a = sqrt(sum(v * v for v in ca.values()))
  36. norm_b = sqrt(sum(v * v for v in cb.values()))
  37. if norm_a == 0.0 or norm_b == 0.0:
  38. logger.debug("Zero norm detected (norm_a=%f, norm_b=%f). Cosine similarity is 0.0", norm_a, norm_b)
  39. return 0.0
  40. similarity = dot / (norm_a * norm_b)
  41. logger.debug("Token similarity calculation: common_tokens=%s, dot=%f, norm_a=%f, norm_b=%f -> similarity=%.4f",
  42. list(common_tokens), dot, norm_a, norm_b, similarity)
  43. return similarity