Download utils/sequence_metrics.py from pswap/phew: direct link, hf CLI and curl.
- Browser
- Download file 2.41 kB
-
https://huggingface.co/spaces/pswap/phew/resolve/main/utils/sequence_metrics.py
- Command line
-
hf download hf://spaces/pswap/phew/utils/sequence_metrics.py
-
curl -L -o sequence_metrics.py https://huggingface.co/spaces/pswap/phew/resolve/main/utils/sequence_metrics.py
2.41 kB
| """Pairwise similarity matrices for a set of genes: ESM-2 embedding cosine | |
| similarity, and protein sequence identity from a real alignment. | |
| The identity matrix used to come from a naive zip()-based position-wise | |
| comparison of the two raw (unaligned) sequences -- correct only when both | |
| proteins happen to start in frame with no indels between them. A single | |
| insertion/deletion shifts every downstream residue out of register and | |
| craters the score even for genuinely homologous proteins. This module | |
| replaces that with an actual Smith-Waterman local alignment (BLOSUM62, | |
| affine gaps) via parasail, a SIMD-accelerated (striped) alignment library -- | |
| ~26x faster than Biopython's Bio.Align.PairwiseAligner in an all-pairs | |
| benchmark (1770 pairs of length ~100-400aa: 0.12s vs 3.2s), which matters | |
| here since this is an O(n^2) all-pairs computation. | |
| """ | |
| import numpy as np | |
| import parasail | |
| from sklearn.metrics.pairwise import cosine_similarity | |
| GAP_OPEN = 10 | |
| GAP_EXTEND = 1 | |
| def _sequence_identity(s1: str, s2: str) -> float: | |
| """Identity from a real local alignment, normalized by the longer | |
| sequence's length (kept consistent with the previous naive metric's | |
| denominator, so scores remain comparable to before -- only how | |
| `matches` is counted has changed: aligned non-gap matches instead of | |
| same-position character equality).""" | |
| max_len = max(len(s1), len(s2)) | |
| if max_len == 0: | |
| return 0.0 | |
| result = parasail.sw_trace_striped_16(s1, s2, GAP_OPEN, GAP_EXTEND, parasail.blosum62) | |
| traceback = result.traceback | |
| matches = sum(1 for a, b in zip(traceback.query, traceback.ref) if a == b and a != "-") | |
| return matches / max_len | |
| def calculate_matrices(all_genes): | |
| """Pairwise ESM-2 cosine similarity and protein sequence identity, both in [0, 1].""" | |
| n = len(all_genes) | |
| esm_cosine_sim = np.zeros((n, n)) | |
| align_matrix = np.zeros((n, n)) | |
| embeddings = np.array([g["embedding"] for g in all_genes if "embedding" in g]) | |
| if len(embeddings) > 0: | |
| esm_cosine_sim = cosine_similarity(embeddings) | |
| for i in range(n): | |
| for j in range(i, n): | |
| if i == j: | |
| identity = 1.0 | |
| else: | |
| identity = _sequence_identity(all_genes[i]["protein"], all_genes[j]["protein"]) | |
| align_matrix[i][j] = identity | |
| align_matrix[j][i] = identity | |
| return esm_cosine_sim, align_matrix | |