Add robust similarity metrics and normalization to compare.text - #1144
Merged
ebhills merged 4 commits intoAug 26, 2026
Conversation
Contributor
Author
|
@ebhills @thomasstvr PR was trested in QA to test it you can use image: dev-1.20.0rc59 . test file |
thomasstvr
reviewed
Aug 25, 2026
…tric schema descriptions
ebhills
approved these changes
Aug 26, 2026
ebhills
deleted the
feature/1134-enhancement-add-robust-similarity-metrics-and-normalization-to-comparetext
branch
August 26, 2026 19:11
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add robust similarity metrics and normalization to
compare.textCloses #1134
Summary
Adds
method: similaritytocompare.text— a symmetric,0.0–1.0bounded similarity score for comparing product descriptions that may be reordered, differently punctuated, or contain typos. Also fixes several existing issues indifference/intersection/overlapalong the way: a real (not deprecated)case_sensitivetoggle defaulting to case-insensitive, a cleaner two-column output foroverlap'sinclude_ratio, a casing-preservation bug, and a crash on quoteddecimal_places.What's in this PR
New
method: similaritywith three metrics (wrangles/compare.py):token_sort(default) — ignores token order, keeps duplicates, penalizes missing/extra contenttoken_set— ignores token order and duplicates; a shorter description fully contained in a longer one can score1.0damerau_levenshtein— character edit distance where an adjacent transposition counts as one editfuzz.token_sort_ratio,fuzz.token_set_ratio,distance.DamerauLevenshtein.normalized_similarity) — new dependency:rapidfuzz>=3.0,<4.0normalize_similarity_text): NFKC Unicode normalization → Unicode-aware case folding → punctuation/separators converted to spaces (not concatenated) → whitespace collapsed. Deliberately does not equateAB-12/AB12, doesn't touch units/numbers, doesn't do synonym/acronym expansion.null, never stringified into"nan"/"None"— checked before anystr()conversion, unlike the legacy.astype(str)path.metricschema property usesoneOfwith aconst+descriptionper value instead of a flatenum, so IDE/schema tooltips show each metric's description individually instead of one wall of text under "Allowed Values".case_sensitivebehavior, changed twice over the life of this branch, landed as:false(case-insensitive) fordifference/intersection/overlap— previously defaulted totrue(case-sensitive). Passcase_sensitive: trueto restore exact-case matching.overlapwithinclude_ratio: truenow requires a two-columnoutput:outputmust be[mask_column, ratio_column]— the mask and ratio are written to separate columns instead of being packed into one cell as[mask, ratio], which was awkward for Excel filtering/numeric operations.ValueErrorifoutputisn't a two-item list wheninclude_ratiois true.overlapwithoutinclude_ratiostill accepts a singleoutputcolumn name as before.Bug fixes required to make the above correct, not scope creep:
contrast()/overlap()casing: case-insensitive matching was also lowercasing the output indifference/overlap. Matching is case-insensitive when requested, but original casing is now preserved in the output either way.decimal_placesbug (int(decimal_places)'s result was discarded, causing a laterTypeError).Tests
61 tests in
tests/recipes/wrangles/test_compare.py(35 pre-existing behavior preserved + new coverage added across the branch): symmetry, score bounds, exact-match, reordered/duplicate/subset tokens, conflicting attributes, each Damerau-Levenshtein edit type individually (insertion/deletion/substitution/transposition), anagram guard, punctuation (AB-12vsAB12), Unicode normalization, nulls (both library-levelNoneand recipe-level non-stringified), the quoted-decimal_placesand casing regression bugs,case_sensitivetrue/false/default equivalence and divergence, and the newinclude_ratiooutput-shape validation (both the error case and the still-works-without-include_ratiocase).Also updated
tests/recipes/test_recipes.py: the three tests that were hitting permission-restricted live models (test_recipe_by_production_version,test_recipe_by_version_latest,test_recipe_by_latest_version) now point at newly created replacement model IDs (e954717c-fb9c-4c47,1b41d016-7129-4b66) instead of being mocked, so they still exercise the real model-version-resolution path end-to-end.