PolyFuzz

MaartenGrMIT长期未更新

提供模糊字符串匹配、分组和评估的 Python 库,支持编辑距离、TF-IDF 和 BERT 嵌入等多种相似度算法,适合做实体对齐和文本去重。

Fuzzy string matching, grouping, and evaluation.

v0.4.3发布于 2025-05-06 11:58 UTC805star72fork同步于 2026-11-07 07:31 UTC

怎么上手

由 README 提炼,执行前请确认
pip install polyfuzz
硬件要求按 README 说明

README 未说明;使用 Transformers/Flair 等嵌入模型时需自行准备相应环境,README 未给出显存或 GPU 要求

下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

统一框架整合多种模糊字符串匹配方法,支持匹配、分组与效果评估

提供模糊字符串匹配、分组和评估的 Python 库,支持编辑距离、TF-IDF 和 BERT 嵌入等多种相似度算法,适合做实体对齐和文本去重。

核心能力

  • 集成 TF-IDF、编辑距离、FastText/GloVe 与 Transformers 多种匹配模型
  • 用 fit/transform 复用已拟合表示,加速生产环境匹配
  • 用 single linkage 对匹配结果聚类分组
  • 绘制 precision-recall 曲线对比不同模型效果
  • 继承 BaseMatcher 即可接入自定义匹配模型

容易踩的坑

使用 BERT、Flair、Gensim、spaCy 等后端需额外安装对应 extras,如 pip install polyfuzz[sbert];sparse_dot_topn 可能安装失败,可先用 conda install -c conda-forge sparse_dot_topn 再装;嵌入模型首次运行需下载预训练权重

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v0.4.3
  1. v0.4.3最新正式版2025-05-06 · 2025-05-06 11:58 UTC
  2. v0.4.22023-09-03 · 2023-09-03 07:52 UTC
    查看更新说明

    Removed restrictive pytorch dependencies for Flair

  3. v0.4.12023-09-03 · 2023-09-03 07:32 UTC
    查看更新说明
  4. v0.4.02022-05-07 · 2022-05-07 07:12 UTC
    查看更新说明
    • Added new models (SentenceTransformers, Gensim, USE, Spacy)
    • Added .fit, .transform, and .fit_transform methods
    • Added .save and PolyFuzz.load()

    SentenceTransformers, Gensim, USE, and Spacy

    SentenceTransformers
    from polyfuzz.models import SentenceEmbeddings
    distance_model = SentenceEmbeddings("all-MiniLM-L6-v2")
    model = PolyFuzz(distance_model)
    
    Gensim
    from polyfuzz.models import GensimEmbeddings
    distance_model = GensimEmbeddings("glove-twitter-25")
    model = PolyFuzz(distance_model)
    
    USE
    from polyfuzz.models import USEEmbeddings
    distance_model = USEEmbeddings("https://tfhub.dev/google/universal-sentence-encoder/4")
    model = PolyFuzz(distance_model)
    
    Spacy
    from polyfuzz.models import SpacyEmbeddings
    distance_model = SpacyEmbeddings("en_core_web_md")
    model = PolyFuzz(distance_model)
    

    fit, transform, fit_transform

    Add fit, transform, and fit_transform in order to use PolyFuzz in production (#34)

    from sklearn.datasets import fetch_20newsgroups
    from sklearn.feature_extraction.text import CountVectorizer
    from polyfuzz import PolyFuzz
    
    train_words = ["apple", "apples", "appl", "recal", "house", "similarity"]
    unseen_words = ["apple", "apples", "mouse"]
    
    # Fit
    model = PolyFuzz("TF-IDF")
    model.fit(train_words)
    
    # Transform
    results = model.transform(unseen_words)
    

    In the code above, we fit our TF-IDF model on train_words and use .transform() to match the words in unseen_words to the words that we trained on in train_words.

    After fitting our model, we can save it as follows:

    model.save("my_model")
    

    Then, we can load our model to be used elsewhere:

    from polyfuzz import PolyFuzz
    
    model = PolyFuzz.load("my_model")
    
  5. v0.3.42021-11-05 · 2021-11-05 10:41 UTC
    查看更新说明
    • Make sure that when you use two lists that are exactly the same, it will return 1 for identical terms:
    from polyfuzz import PolyFuzz
    from_list = ["apple", "house"]
    model = PolyFuzz("TF-IDF")
    model.match(from_list, from_list)
    

    This will match each word in from_list to itself and give it a score of 1. Thus, apple will be matched to apple and house will be mapped to house. However, if you input just a single list, it will try to map them within the list without mapping to itself:

    from polyfuzz import PolyFuzz
    from_list = ["apple", "apples"]
    model = PolyFuzz("TF-IDF")
    model.match(from_list)
    

    In the example above, apple will be mapped to apples and not to apple. Here, we assume that the user wants to find the most similar words within a list without mapping to itself.

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    PyPI Downloads PyPI - Python PyPI - License PyPI - PyPi Build docs
    PolyFuzz performs fuzzy string matching, string grouping, and contains extensive evaluation functions. PolyFuzz is meant to bring fuzzy string matching techniques together within a single framework.

    Currently, methods include a variety of edit distance measures, a character-based n-gram TF-IDF, word embedding techniques such as FastText and GloVe, and 🤗 transformers embeddings.

    Corresponding medium post can be found here.

    Installation

    You can install PolyFuzz via pip:

    pip install polyfuzz
    

    You may want to install more depending on the transformers and language backends that you will be using. The possible installations are:

    pip install polyfuzz[sbert]
    pip install polyfuzz[flair]
    pip install polyfuzz[gensim]
    pip install polyfuzz[spacy]
    pip install polyfuzz[use]
    

    If you want to speed up the cosine similarity comparison and decrease memory usage when using embedding models, you can use sparse_dot_topn which is installed via:

    pip install polyfuzz[fast]
    

    You might run into installation issues with sparse_dot_topn. If so, one solution that has worked for many is by installing it via conda first before installing PolyFuzz:

    conda install -c conda-forge sparse_dot_topn
    

    If that does not work, I would advise you to look through their issues](https://github.com/ing-bank/sparse_dot_topn/issues) page or continue to use PolyFuzz without sparse_dot_topn.

    Getting Started

    For an in-depth overview of the possibilities of PolyFuzz you can check the full documentation here or you can follow along with the notebook here.

    Quick Start

    The main goal of PolyFuzz is to allow the user to perform different methods for matching strings. We start by defining two lists, one to map from and one to map to. We are going to be using TF-IDF to create n-grams on a character level in order to compare similarity between strings. Then, we calculate the similarity between strings by calculating the cosine similarity between vector representations.

    We only have to instantiate PolyFuzz with TF-IDF and match the lists:

    from polyfuzz import PolyFuzz
    
    from_list = ["apple", "apples", "appl", "recal", "house", "similarity"]
    to_list = ["apple", "apples", "mouse"]
    
    model = PolyFuzz("TF-IDF")
    model.match(from_list, to_list)
    

    The resulting matches can be accessed through model.get_matches():

    >>> model.get_matches()
             From      To    Similarity
    0       apple   apple    1.000000
    1      apples  apples    1.000000
    2        appl   apple    0.783751
    3       recal    None    0.000000
    4       house   mouse    0.587927
    5  similarity    None    0.000000
    
    

    NOTE 1: If you want to compare distances within a single list, you can simply pass that list as such: model.match(from_list)

    NOTE 2: When instantiating PolyFuzz we also could have used "EditDistance" or "Embeddings" to quickly access Levenshtein and FastText (English) respectively.

    Production

    The .match function allows you to quickly extract similar strings. However, after selecting the right models to be used, you may want to use PolyFuzz in production to match incoming strings. To do so, we can make use of the familiar fit, transform, and fit_transform functions.

    Let's say that we have a list of words that we know to be correct called train_words. We want to any incoming word to mapped to one of the words in train_words. In other words, we fit on train_words and we use transform on any incoming words:

    from sklearn.datasets import fetch_20newsgroups
    from sklearn.feature_extraction.text import CountVectorizer
    from polyfuzz import PolyFuzz
    
    train_words = ["apple", "apples", "appl", "recal", "house", "similarity"]
    unseen_words = ["apple", "apples", "mouse"]
    
    # Fit
    model = PolyFuzz("TF-IDF")
    model.fit(train_words)
    
    # Transform
    results = model.transform(unseen_words)
    

    In the above example, we are using fit on train_words to calculate the TF-IDF representation of those words which are saved to be used again in transform. This speeds up transform quite a bit since all TF-IDF representations are stored when applying fit.

    Then, we apply save and load the model as follows to be used in production:

    # Save the model
    model.save("my_model")
    
    # Load the model
    loaded_model = PolyFuzz.load("my_model")
    

    Group Matches

    We can group the matches To as there might be significant overlap in strings in our to_list. To do this, we calculate the similarity within strings in to_list and use single linkage to then group the strings with a high similarity.

    When we extract the new matches, we can see an additional column Group in which all the To matches were grouped to:

    >>> model.group(link_min_similarity=0.75)
    >>> model.get_matches()
    	      From	To		Similarity	Group
    0	     apple	apple	1.000000	apples
    1	    apples	apples	1.000000	apples
    2	      appl	apple	0.783751	apples
    3	     recal	None	0.000000	None
    4	     house	mouse	0.587927	mouse
    5	similarity	None	0.000000	None
    

    As can be seen above, we grouped apple and apples together to apple such that when a string is mapped to apple it will fall in the cluster of [apples, apple] and will be mapped to the first instance in the cluster which is apples.

    Precision-Recall Curve

    Next, we would like to see how well our model is doing on our data. We express our results as precision and recall where precision is defined as the minimum similarity score before a match is correct and recall the percentage of matches found at a certain minimum similarity score.

    Creating the visualizations is as simple as:

    model.visualize_precision_recall()
    

    Models

    Currently, the following models are implemented in PolyFuzz:

    • TF-IDF
    • EditDistance (you can use any distance measure, see documentation)
    • FastText and GloVe
    • 🤗 Transformers

    With Flair, we can use all 🤗 Transformers models. We simply have to instantiate any Flair WordEmbedding method and pass it through PolyFuzzy.

    All models listed above can be found in polyfuzz.models and can be used to create and compare different models:

    from polyfuzz.models import EditDistance, TFIDF, Embeddings
    from flair.embeddings import TransformerWordEmbeddings
    
    embeddings = TransformerWordEmbeddings('bert-base-multilingual-cased')
    bert = Embeddings(embeddings, min_similarity=0, model_id="BERT")
    tfidf = TFIDF(min_similarity=0)
    edit = EditDistance()
    
    string_models = [bert, tfidf, edit]
    model = PolyFuzz(string_models)
    model.match(from_list, to_list)
    

    To access the results, we again can call get_matches but since we have multiple models we get back a dictionary of dataframes back.

    In order to access the results of a specific model, call get_matches with the correct id:

    >>> model.get_matches("BERT")
            From	    To          Similarity
    0	apple	    apple	1.000000
    1	apples	    apples	1.000000
    2	appl	    apple	0.928045
    3	recal	    apples	0.825268
    4	house	    mouse	0.887524
    5	similarity  mouse	0.791548
    

    Finally, visualize the results to compare the models:

    model.visualize_precision_recall(kde=True)
    

    Custom Grouper

    We can even use one of the polyfuzz.models to be used as the grouper in case you would like to use something else than the standard TF-IDF model:

    model = PolyFuzz("TF-IDF")
    model.match(from_list, to_list)
    
    edit_grouper = EditDistance(n_jobs=1)
    model.group(edit_grouper)
    

    Custom Models

    Although the options above are a great solution for comparing different models, what if you have developed your own? If you follow the structure of PolyFuzz's BaseMatcher
    you can quickly implement any model you would like.

    Below, we are implementing the ratio similarity measure from RapidFuzz.

    import numpy as np
    import pandas as pd
    from rapidfuzz import fuzz
    from polyfuzz.models import BaseMatcher
    
    
    class MyModel(BaseMatcher):
        def match(self, from_list, to_list, **kwargs):
            # Calculate distances
            matches = [[fuzz.ratio(from_string, to_string) / 100 for to_string in to_list] 
                        for from_string in from_list]
            
            # Get best matches
            mappings = [to_list[index] for index in np.argmax(matches, axis=1)]
            scores = np.max(matches, axis=1)
            
            # Prepare dataframe
            matches = pd.DataFrame({'From': from_list,'To': mappings, 'Similarity': scores})
            return matches
    

    Then, we can simply create an instance of MyModel and pass it through PolyFuzz:

    custom_model = MyModel()
    model = PolyFuzz(custom_model)
    

    Citation

    To cite PolyFuzz in your work, please use the following bibtex reference:

    @misc{grootendorst2020polyfuzz,
      author       = {Maarten Grootendorst},
      title        = {PolyFuzz: Fuzzy string matching, grouping, and evaluation.},
      year         = 2020,
      publisher    = {Zenodo},
      version      = {v0.2.2},
      doi          = {10.5281/zenodo.4461050},
      url          = {https://doi.org/10.5281/zenodo.4461050}
    }
    

    References

    Below, you can find several resources that were used for or inspired by when developing PolyFuzz:

    Edit distance algorithms:
    These algorithms focus primarily on edit distance measures and can be used in polyfuzz.models.EditDistance:

    Other interesting repos: