In case you're interested in a quick visual comparison of Levenshtein and Difflib similarity, I calculated both for ~2.3 million book titles:

import codecs, difflib, Levenshtein, distance

with codecs.open("titles.tsv","r","utf-8") as f:
    title_list = f.read().split("\n")[:-1]

    for row in title_list:

        sr      = row.lower().split("\t")

        diffl   = difflib.SequenceMatcher(None, sr[3], sr[4]).ratio()
        lev     = Levenshtein.ratio(sr[3], sr[4]) 
        sor     = 1 - distance.sorensen(sr[3], sr[4])
        jac     = 1 - distance.jaccard(sr[3], sr[4])

        print diffl, lev, sor, jac

I then plotted the results with R:

Strictly for the curious, I also compared the Difflib, Levenshtein, Sørensen, and Jaccard similarity values:

library(ggplot2)
require(GGally)

difflib <- read.table("similarity_measures.txt", sep = " ")
colnames(difflib) <- c("difflib", "levenshtein", "sorensen", "jaccard")

ggpairs(difflib)

Result:

The Difflib / Levenshtein similarity really is quite interesting.

2018 edit: If you're working on identifying similar strings, you could also check out minhashing--there's a great overview here. Minhashing is amazing at finding similarities in large text collections in linear time. My lab put together an app that detects and visualizes text reuse using minhashing here: https://github.com/YaleDHLab/intertext

Answer from duhaime on Stack Overflow
Top answer
1 of 2
242

In case you're interested in a quick visual comparison of Levenshtein and Difflib similarity, I calculated both for ~2.3 million book titles:

import codecs, difflib, Levenshtein, distance

with codecs.open("titles.tsv","r","utf-8") as f:
    title_list = f.read().split("\n")[:-1]

    for row in title_list:

        sr      = row.lower().split("\t")

        diffl   = difflib.SequenceMatcher(None, sr[3], sr[4]).ratio()
        lev     = Levenshtein.ratio(sr[3], sr[4]) 
        sor     = 1 - distance.sorensen(sr[3], sr[4])
        jac     = 1 - distance.jaccard(sr[3], sr[4])

        print diffl, lev, sor, jac

I then plotted the results with R:

Strictly for the curious, I also compared the Difflib, Levenshtein, Sørensen, and Jaccard similarity values:

library(ggplot2)
require(GGally)

difflib <- read.table("similarity_measures.txt", sep = " ")
colnames(difflib) <- c("difflib", "levenshtein", "sorensen", "jaccard")

ggpairs(difflib)

Result:

The Difflib / Levenshtein similarity really is quite interesting.

2018 edit: If you're working on identifying similar strings, you could also check out minhashing--there's a great overview here. Minhashing is amazing at finding similarities in large text collections in linear time. My lab put together an app that detects and visualizes text reuse using minhashing here: https://github.com/YaleDHLab/intertext

2 of 2
137
  • difflib.SequenceMatcher uses the Ratcliff/Obershelp algorithm it computes the doubled number of matching characters divided by the total number of characters in the two strings.

  • Levenshtein uses Levenshtein algorithm it computes the minimum number of edits needed to transform one string into the other

Complexity

SequenceMatcher is quadratic time for the worst case and has expected-case behavior dependent in a complicated way on how many elements the sequences have in common. (from here)

Levenshtein is O(m*n), where n and m are the length of the two input strings.

Performance

According to the source code of the Levenshtein module : Levenshtein has a some overlap with difflib (SequenceMatcher). It supports only strings, not arbitrary sequence types, but on the other hand it's much faster.

🌐
Typesense
typesense.org › posts › fuzzy string matching in python (with examples)
Fuzzy string matching in Python (with examples) | Typesense
It uses the Ratcliff/Obershelp ... between two strings as: Twice the number of matching (overlapping) characters between the two strings divided by the total number of characters in the two strings. from difflib import ...
Discussions

'Fuzzy' string match

Yes, that is fine. Just return the result though, no need for the if: True else: False since the result will be truthy or falsy

More on reddit.com
🌐 r/learnpython
10
2
May 7, 2014
python - Better fuzzy matching performance? - Stack Overflow
Copya=['blah','pie','apple'...] ... in a: difflib.get_close_matches(value,b,n=1,cutoff=.85) It takes .58 seconds per value which means it will take 8,714 seconds or 145 minutes to finish the loop. Is there another library/method that might be faster or a way to improve the speed for this method? I've already tried converting both arrays to lower case, but it only resulted in a slight speed increase. ... Save this answer. ... Show activity on this post. fuzzyset indexes strings ... More on stackoverflow.com
🌐 stackoverflow.com
Difflib and python-Levenshtein give different ratios in some cases
To show this, if we change the second sequence to "abaaaa", difflib will also score 67 (since it matches the first two characters of each sequence then recurses to the right). See as follows: >>> fuzz.ratio("ababab", "abaaaa") 67 #And switching pack to python-Levenshtein, no change: >>> ... More on github.com
🌐 github.com
2
August 12, 2016
Fuzzy Match values to list of list python - Stack Overflow
Struggling with how to do this in a pythonic way. I have a list of list which we can call names · [('Jimmy', 'Smith'), ('James', 'Wilson'), ('Hugh' "Laurie')] ... I want to iterate through this list of list, of first and last names to fuzzy match these values and return the list that is the closest to the specified First_name and Last_name ... Take a look on difflib... More on stackoverflow.com
🌐 stackoverflow.com
🌐
Fabiangunzinger
fabiangunzinger.github.io › python-fuzzy-matching
Fuzzy matching in Python - Fabian Gunzinger
October 2, 2023 - difflib Docs here 1 import difflib Most simple use case 1 2 m = difflib.SequenceMatcher(None, 'NEW YORK METS', 'NEW YORK MEATS') m.ratio() 0.9629629629629629 Create helper function so we don’t need to specify None each time. 1 2 3 4 from functools import partial matcher = partial(difflib.SequenceMatcher, None) matcher('NEW YORK METS', 'NEW YORK MEATS').ratio() 0.9629629629629629 Compare one sequence to multiple other sequences (SequenceMatcher caches second sequence) 1 2 3 4 5 6 7 m = difflib.
🌐
UCL
homepages.ucl.ac.uk › ~ucahmto › python › 2023 › 02 › 05 › fuzzy-text-matching.html
Fuzzy text matching in Python | Matthew Towers’ homepage
February 5, 2023 - For example, they might omit parts ... got 300+ students, you don’t want to do the name-email matching by hand. You can do this in Python using the csv module for accessing spreadsheets and the difflib module for fuzzy matching....
🌐
Auditboardanalytics
docs.auditboardanalytics.com › tools › code › pythoncode › fuzzy-match
Fuzzy Match - Hello Analytics!
This example code creates a fuzzy match from a tool input and only returns those matches with a similarity score above .5 via def fuzzy_match(list1, list2, threshold=0.5):. It matches the first two columns provided, so you will need to rearrange your data to be matched as the first two columns. ... #import Libraries import pandas as pd import difflib # Function to perform fuzzy matching def fuzzy_match(list1, list2, threshold=0.5): # Lowering the threshold to 0.5 matches = [] for item in list1: match = difflib.get_close_matches(item, list2, n=1, cutoff=threshold) if match: similarity = difflib
🌐
Reddit
reddit.com › r/learnpython › 'fuzzy' string match
r/learnpython on Reddit: 'Fuzzy' string match
May 7, 2014 -

I found difflib.get_close_matches() while searching for a way to 'fuzzy match' strings. The matching algorithm seems good for my data, but I only want to check one string against one other and know if they 'match'. So:

def fuzzy_match(test_string, possible_match):
    if difflib.get_close_matches(test_string, [possible_match]):
        return True
    else:
        return False

Does that seem like a decent solution? Any suggestions? FWIW, I'd prefer to stick within the standard library.

Edit: updated version per indosauros:

def fuzzy_match(test_string, possible_match):
    return difflib.get_close_matches(test_string, [possible_match])

Edit 2: Or maybe do it right? (basically a stripped down version of get_close_matches):

def fuzzy_match(test_string, possible_match, cutoff=0.6):

    s = difflib.SequenceMatcher()

    s.set_seq2(test_string)
    s.set_seq1(possible_match)

    if s.real_quick_ratio() >= cutoff and \
       s.quick_ratio() >= cutoff and \
       s.ratio() >= cutoff:
        return True
    else:
        return False
🌐
Gree2
gree2.github.io › python › 2017 › 03 › 07 › string-comparison-in-python
string comparison in python
from difflib import SequenceMatcher m = SequenceMatcher(None, 'new york mets', 'new york meats') m.ratio() => 0.9626... fuzz.ratio('new york mets', 'new york meats') => 96 ... fuzz.ratio('yankees', 'new york yankees') => 60 fuzz.ratio('new york mets', 'new york yankees') => 75 fuzz.ratio('yankees', 'new york yankees') => 100 fuzz.ratio('new york mets', 'new york yankees') => 69
Find elsewhere
🌐
Statology
statology.org › home › how to perform fuzzy matching in pandas (with example)
How to Perform Fuzzy Matching in Pandas (With Example)
March 13, 2022 - import difflib #create duplicate column to retain team name from df2 df2['team_match'] = df2['team'] #convert team name in df2 to team name it most closely matches in df1 df2['team'] = df2['team'].apply(lambda x: difflib.get_close_matches(x, df1['team'])[0]) #merge the DataFrames into one df3 = df1.merge(df2) #view final DataFrame print(df3) team points assists team_match 0 Mavericks 99 22 Mavricks 1 Nets 90 40 Netts 2 Warriors 104 29 Warrors 3 Heat 117 17 Heat 4 Lakers 100 32 Lakes
🌐
Python
docs.python.org › 3 › library › difflib.html
difflib — Helpers for computing deltas
Source code: Lib/difflib.py This module provides classes and functions for comparing sequences. It can be used for example, for comparing files, and can produce information about file differences i...
🌐
Karangoyal
karangoyal.cc › home › blog › web development › finding the closest matching string in python using difflib
Python Difflib: Finding Closest Matching String - Karan Goyal
December 3, 2025 - In this post, we've seen how to use Python's difflib library to find the closest matching string from a list of strings. By leveraging the get_close_matches() function and SequenceMatcher.ratio() method, you can efficiently implement fuzzy matching ...
🌐
GitHub
github.com › seatgeek › fuzzywuzzy › issues › 128
Difflib and python-Levenshtein give different ratios in some cases · Issue #128 · seatgeek/fuzzywuzzy
August 12, 2016 - >>> from fuzzywuzzy import fuzz, StringMatcher >>> import difflib #As long as python-Levenshtein is available, that will be used for the following: >>> fuzz.ratio("ababab", "aaaaab") 67 #Switch to difflib: >>> fuzz.SequenceMatcher = difflib.SequenceMatcher >>> fuzz.ratio("ababab", "aaaaab") 33 · I don't know how python-Levenshtein works, but difflib first chooses the left-most longest block in the first sequence that matches any block in the second sequence.
Author   seatgeek
Top answer
1 of 2
2

To eliminate the possibility of low-score matches as a result of case-differences, I'd suggest applying .upper() or .lower() to the columns you're matching. After adjusting the case, you could compile a list of all titles into ThisList and apply the following function (relying, as you suggested, on SequenceMatcher) with a given tolerance.

def fuzzy_group_list_elements(ThisList,Tolerance):
    from difflib import SequenceMatcher
    Groups = {}
    TempList = ThisList.copy()
    for Elmt in TempList:
        if Elmt not in Groups.keys():
            Groups[Elmt] = []
        for OtherElmt in TempList:
            if SequenceMatcher(None,Elmt,OtherElmt).quick_ratio() > Tolerance:
                Groups[Elmt] = Groups[Elmt] + [OtherElmt]
                TempList.remove(OtherElmt)
    Groups[Elmt] = list(set(Groups[Elmt]))
    return dict((v,k) for k in Groups for v in Groups[k])

You can then apply the above function to the dataframe columns containing the movie titles:

Mapping = fuzzy_group_list_elements(ThisList,0.85)
df['Matched Title'] = df['Title'].replace(Mapping)
2 of 2
1

I have written a Python package which aims to solve this problem. Amongst other things, it addresses the n^2 complexity of the problem (e.g. with two datasets of length 100, your code needs 10,000 comparisons).

You can install it using pip install fuzzymatcher

You can find the repo here and docs here.

Basic usage:

Given two dataframes df_left and df_right, which you want to fuzzy join, you can write the following:

from fuzzymatcher import link_table, left join

# Columns to match on from df_left
left_on = ["fname", "mname", "lname",  "dob"]

# Columns to match on from df_right
right_on = ["name", "middlename", "surname", "date"]

# The link table potentially contains several matches for each record
fuzzymatcher.link_table(df_left, df_right, left_on, right_on)

Or if you just want to link on the closest match:

fuzzymatcher.fuzzy_left_join(df_left, df_right, left_on, right_on)
🌐
Seatgeek
chairnerd.seatgeek.com › fuzzywuzzy-fuzzy-string-matching-in-python
FuzzyWuzzy: Fuzzy String Matching in Python - ChairNerd
July 8, 2011 - Using python’s difflib, that’s pretty easy · from difflib import SequenceMatcher m = SequenceMatcher(None, "NEW YORK METS", "NEW YORK MEATS") m.ratio() ⇒ 0.962962962963 · So it looks like these two strings are about 96% the same. Pretty good! We use this pattern so frequently, we wrote a helper method to encapsulate it · fuzz.ratio("NEW YORK METS", "NEW YORK MEATS") ⇒ 96
🌐
Medium
medium.com › @bravekjh › unlocking-the-power-of-fuzzy-matching-in-python-a-practical-guide-ec37ebd8f3eb
Unlocking the Power of Fuzzy Matching in Python: A Practical Guide | by Jay Kim | Medium
June 26, 2025 - Fuzzy matching is a powerful technique for comparing text strings that may be imprecise or slightly different — whether due to typos, inconsistent formatting, or variant spellings.
🌐
Mark III Systems
markiiisys.com › home › mark iii systems blog › phrase comparison in python
Phrase Comparison in Python - Mark III Systems
May 3, 2021 - These techniques can be useful in a variety of problems, in my case natural language processing. ... One can use the SequenceMatcher function in the difflib python library to do simple string comparisons.
🌐
DataCamp
datacamp.com › tutorial › fuzzy-string-python
Fuzzy String Matching in Python Tutorial | DataCamp
January 15, 2026 - We can determine the simple ratio between two strings using the ratio() method on the fuzz object. This simply calculates the edit distance based on the ordering of both input strings difflib.ratio() – see the difflib documentation to learn more.
🌐
Stack Overflow
stackoverflow.com › questions › 62112310 › fuzzy-string-matching-using-difflib-get-matching-blocks-not-detecting-all-substr
python - Fuzzy string matching using Difflib get_matching_blocks not detecting all substrings - Stack Overflow
May 31, 2020 - to_search="caterpillar" search_here= "caterpillar are awesome animal catterpillar who like other humans but not other caterpilar" #search_here has the word caterpillar repeated but with spelling mistakes s= SequenceMatcher(None, to_search, search_here).get_matching_blocks() print(s) #Output : [Match(a=0, b=0, size=11), Match(a=3, b=69, size=0)] #Expected: [Match(a=0, b=0, size=11), Match(a=0, b=32, size=11), Match(a=0, b=81, size=11)] Difflib get_matching_blocks only detects the first instance of "caterpillar" in the search_here string.
🌐
DEV Community
dev.to › mrquite › smart-text-matching-rapidfuzz-vs-difflib-ge5
🧠 Smart Text Matching: RapidFuzz vs Difflib - DEV Community
November 4, 2025 - In this article, we’ll explore how to build a simple but powerful fuzzy matching system for restaurant names, using two different Python approaches: Part 1: Using RapidFuzz for lightning-fast, token-based similarity · Part 2: Using Difflib, Python’s built-in (but slower) alternative