skills/matchms/references/similarity.md
Use this reference to select a similarity class, interpret its output, extract
top hits, or scale a comparison. The authoritative API is
matchms.similarity.
from matchms import calculate_scores
from matchms.similarity import CosineGreedy
metric = CosineGreedy(tolerance=0.02)
scores = calculate_scores(
references=reference_spectra,
queries=query_spectra,
similarity_function=metric,
array_type="numpy",
is_symmetric=False,
)
Set is_symmetric=True only when references and queries are the same collection
in the same order and the metric is symmetric.
Scores.scores is a sparsestack.StackedSparseArray, not a plain two-dimensional
NumPy array. Its shape is (n_references, n_queries, n_score_fields).
Cosine-family methods produce two fields:
print(scores.score_names)
# ('CosineGreedy_score', 'CosineGreedy_matches')
similarities = scores.to_array("CosineGreedy_score")
matched_peaks = scores.to_array("CosineGreedy_matches")
Scalar methods such as FlashSimilarity, PrecursorMzMatch, and
FingerprintSimilarity produce one field named after the class.
score_name = "CosineGreedy_score"
matches_name = "CosineGreedy_matches"
ranked = scores.scores_by_query(query_spectrum, name=score_name, sort=True)
for reference, value in ranked[:10]:
print(
reference.get("spectrum_id"),
float(value[score_name]),
int(value[matches_name]),
)
The first tuple item is the actual reference Spectrum, not an integer index.
The second item can be a structured NumPy record containing every score field.
for reference, query, values in scores:
print(reference.get("id"), query.get("id"), values)
Iteration covers stored coordinates. After sparse filtering, that may be only a subset of the Cartesian product.
All cosine classes below use:
tolerance=0.1, mz_power=0.0, intensity_power=1.0
unless noted otherwise. Tolerance is in daltons for these classes.
CosineGreedyGreedily assigns candidate peak pairs within tolerance.
Use for:
Output fields: CosineGreedy_score, CosineGreedy_matches.
CosineHungarianUses optimal assignment rather than greedy assignment.
Use for:
It is computationally more expensive than CosineGreedy.
CosineLinearAdded in 0.33.0 as a linear-scaling cosine implementation.
Use when:
Output fields: CosineLinear_score, CosineLinear_matches.
Modified cosine allows unshifted peak matches and matches shifted by the
difference in precursor m/z. Both spectra need valid precursor_mz.
ModifiedCosineGreedyfrom matchms.similarity import ModifiedCosineGreedy
metric = ModifiedCosineGreedy(tolerance=0.02)
This is the current name for the implementation formerly called
ModifiedCosine. It uses greedy assignment.
ModifiedCosineHungarianfrom matchms.similarity import ModifiedCosineHungarian
metric = ModifiedCosineHungarian(tolerance=0.02)
Use for exact modified-cosine assignment in benchmarks or method development. It is slower than the greedy variant.
Do not infer that a shifted match proves a specific chemical transformation. Inspect precursor delta, adduct/charge compatibility, shifted peaks, and orthogonal annotations.
from matchms.similarity import NeutralLossesCosine
metric = NeutralLossesCosine(
tolerance=0.02,
ignore_peaks_above_precursor=True,
)
NeutralLossesCosine computes losses from precursor_mz - fragment_mz.
Both spectra require precursor m/z. Do not call the removed add_losses()
filter; losses are computed on demand in current matchms.
Output fields: NeutralLossesCosine_score,
NeutralLossesCosine_matches.
BlinkCosineBLINK-style approximate cosine:
from matchms.similarity import BlinkCosine
metric = BlinkCosine(
tolerance=0.01,
bin_width=0.001,
min_relative_intensity=0.01,
top_k=None,
batch_size=1024,
sparse_score_min=0.0,
)
Important parameters include peak preprocessing, precursor cropping, batch
size, and sparse score minimum. Output contains a float32 score and matched-peak
count. Validate approximation behavior against CosineGreedy on a subset
before changing production workflows.
FlashSimilarityFast matrix scoring based on the Flash Entropy approach:
from matchms.similarity import FlashSimilarity
entropy = FlashSimilarity(
score_type="spectral_entropy",
matching_mode="fragment",
tolerance=0.02,
)
fast_modified_cosine = FlashSimilarity(
score_type="cosine",
matching_mode="hybrid",
tolerance=0.02,
)
Current choices:
score_type: spectral_entropy or cosinematching_mode: fragment, neutral_loss, or hybridpair() exists but emits a warning because it is not the optimized use. Call
calculate_scores() so matchms uses the matrix path. Flash output is a scalar
field named FlashSimilarity, not a score/matches pair.
BinnedEmbeddingSimilarityfrom matchms.similarity import BinnedEmbeddingSimilarity
metric = BinnedEmbeddingSimilarity(
similarity="cosine",
max_mz=1005,
bin_width=1.0,
intensity_power=1.0,
)
This creates fixed-width binned spectral embeddings. Bin width controls both resolution and dimensionality. The class also supports approximate-neighbor indexing through the current PyNNDescent backend; use it only after checking recall against exact neighbors.
These methods are useful as gates or additional evidence. They are not substitutes for peak-pattern similarity.
PrecursorMzMatchfrom matchms.similarity import PrecursorMzMatch
absolute = PrecursorMzMatch(tolerance=0.02, tolerance_type="Dalton")
relative = PrecursorMzMatch(tolerance=10, tolerance_type="ppm")
Output field: PrecursorMzMatch (boolean).
ParentMassMatchfrom matchms.similarity import ParentMassMatch
metric = ParentMassMatch(tolerance=0.02)
Requires parent_mass. Output field: ParentMassMatch (boolean). The current
constructor does not expose a ppm mode.
MetadataMatchfrom matchms.similarity import MetadataMatch
same_mode = MetadataMatch(field="ionmode", matching_type="equal_match")
near_rt = MetadataMatch(
field="retention_time",
matching_type="difference",
tolerance=0.2,
)
Current matching types are equal_match and difference. Older examples that
use matching_type="exact" are invalid.
IntersectMzIntersectMz(scaling=1.0) is a simple m/z-intersection score useful in tests or
specialized workflows. It is not a drop-in replacement for tolerance-aware,
intensity-weighted spectral scoring.
FingerprintSimilarity compares molecular fingerprints derived from known
structures. It therefore measures structure similarity, not spectral
similarity.
from matchms import Fingerprints, calculate_scores
from matchms.similarity import FingerprintSimilarity
fp_store = Fingerprints(
fingerprint_algorithm="morgan2",
fingerprint_method="bit",
nbits=2048,
)
fp_store.compute_fingerprints(spectra)
usable = []
for spectrum in spectra:
fingerprint = fp_store.get_fingerprint_by_spectrum(spectrum)
if fingerprint is not None:
spectrum.set("fingerprint", fingerprint)
usable.append(spectrum)
scores = calculate_scores(
usable,
usable,
FingerprintSimilarity(similarity_measure="jaccard"),
is_symmetric=True,
)
Similarity measures are jaccard, dice, and cosine.
The old add_fingerprint() filter still satisfies the 0.33.1
FingerprintSimilarity interface, but it is marked for removal in matchms 1.0.
The Fingerprints bridge above avoids calling that deprecated filter while
remaining compatible with the current similarity class.
Filter score coordinates before calculating an expensive spectral metric:
from matchms import calculate_scores
from matchms.similarity import ModifiedCosineGreedy, PrecursorMzMatch
scores = calculate_scores(
references,
queries,
PrecursorMzMatch(tolerance=10, tolerance_type="ppm"),
array_type="sparse",
)
scores.filter_by_range(name="PrecursorMzMatch", low=0.5)
scores.calculate(
ModifiedCosineGreedy(tolerance=0.02),
array_type="sparse",
join_type="left",
)
After filter_by_range, the second calculation can operate on retained
coordinates. Confirm scores.score_names and stored-coordinate counts after
each stage. An overly narrow precursor gate can remove valid analogs or
different adducts.
The Pipeline class formalizes the same pattern and can persist a YAML
workflow. See workflows.md.
print(scores.score_names)
scores.filter_by_range(
name="ModifiedCosineGreedy_score",
low=0.6,
above_operator=">=",
)
dense = scores.to_array("ModifiedCosineGreedy_score")
coo = scores.to_coo("ModifiedCosineGreedy_score")
scores.to_json("scores.json")
filter_by_range() mutates the stored score coordinates. Preserve an unfiltered
copy or serialize first when alternative thresholds must be compared.
Dense arrays require memory proportional to
n_references * n_queries. A sparse container is most useful only when a mask
or score threshold leaves relatively few stored pairs.
Do not directly index scores.scores[j, i] and assume a scalar. Extract named
layers:
cosine = scores.to_array("CosineGreedy_score")
matches = scores.to_array("CosineGreedy_matches")
If combining metrics:
A high score ranks a candidate under a chosen metric. It does not, by itself, establish compound identity.