← Về thư mục
📄 / / profiles / r-and-d / raw_evidence / scientific-agent-skills / skills / matchms / references / similarity.md

Similarity and Scores (matchms 0.33.1)

Use this reference to select a similarity class, interpret its output, extract top hits, or scale a comparison. The authoritative API is matchms.similarity.

Core Calculation

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.

Understand the Output Before Indexing

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.

Top hits for one query

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.

Iterate stored pairs

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.

Peak-Based Cosine Methods

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.

CosineGreedy

Greedily assigns candidate peak pairs within tolerance.

Use for:

Output fields: CosineGreedy_score, CosineGreedy_matches.

CosineHungarian

Uses optimal assignment rather than greedy assignment.

Use for:

It is computationally more expensive than CosineGreedy.

CosineLinear

Added in 0.33.0 as a linear-scaling cosine implementation.

Use when:

Output fields: CosineLinear_score, CosineLinear_matches.

Modified Cosine

Modified cosine allows unshifted peak matches and matches shifted by the difference in precursor m/z. Both spectra need valid precursor_mz.

ModifiedCosineGreedy

from matchms.similarity import ModifiedCosineGreedy

metric = ModifiedCosineGreedy(tolerance=0.02)

This is the current name for the implementation formerly called ModifiedCosine. It uses greedy assignment.

ModifiedCosineHungarian

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

Neutral-Loss Cosine

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.

Fast Matrix-Oriented Methods

BlinkCosine

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

FlashSimilarity

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

pair() 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.

BinnedEmbeddingSimilarity

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

Candidate and Metadata Matches

These methods are useful as gates or additional evidence. They are not substitutes for peak-pattern similarity.

PrecursorMzMatch

from matchms.similarity import PrecursorMzMatch

absolute = PrecursorMzMatch(tolerance=0.02, tolerance_type="Dalton")
relative = PrecursorMzMatch(tolerance=10, tolerance_type="ppm")

Output field: PrecursorMzMatch (boolean).

ParentMassMatch

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

MetadataMatch

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

IntersectMz

IntersectMz(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.

Molecular Fingerprint Similarity

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.

Filtering and Exporting Scores

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.

Combining Metrics

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:

Interpretation Checklist

A high score ranks a candidate under a chosen metric. It does not, by itself, establish compound identity.