Skip to main content

An efficient Python package for all-to-all comparisons of large datasets of names

Project description

COMPARE-ALL-THE-NAMES

An efficient Python package for all-to-all comparisons of large datasets of names

The Why

Sometimes you have a lot of different records and you want to identify which names could correlate to the same individual across multiple records.

The Problem

Names are really tricky. Sometimes the words are in a different order. Sometimes words are shortened to initials. Other times, they are replaced by nicknames that are non intuitive (e.g. William and Bill). Sometimes a word is just spelled really weird. These are normal, daily occurances in historic data that make life frustrating.

The Second Problem

Even if you could take into account all this, there is still the issue that you have potentially hundreds of thousands of records, and comparing every single name to every other name is stupid. You could easily compute til the end of time.

The Solution: compare-all-the-names

This package solves both those problems. Name comparison is now easy and really really fast for large datasets. By bucketing the names, we are able to efficiently identify which ones could potentially be a match, and validate from there.

All of this is done for you. You just need to pip install compare-all-the-names and use a script similar to this.

from compare_all_the_names import compare_all_names

my_list = [
    'john c weymouth',
    'christian weymouth',
    'weymouth jean',
    'weymouth jeanette',
    'bobby weymouth',
    'robert w',
    'charles weymouth',
    'charlie w',
    'charlie c w',
    'charlie james',
    'charlie james c weymouth',
]

compare_all_names(my_list)

The function compare_all_names takes an input of list[str]. It runs and creates an output file in your temp dir, printing its location out for you. This is required, given you are likely going to run this on massive lists where many names will correlate to one another. Due to current system memory constraints, this is the best solution.

Expected Performance

A lot went into making this fast and somewhat memory efficient (Golang bin under the hood, interesting inverted bucketing algorithm, etc). A modern computer should be able to take a dataset of a million names and find all the matches in under a day. I was able to do so on a laptop in 4 hours, but your mileage will heavily vary on how generic your names are, how common certain words are, and how many words exist per name on average.

Your output will be names that at least share two words that match, or three if both names contain at least three words.

Refining output

I have also included a couple of functions to refine the output. Use add_scrutiny and a scoring function like simple_scoring_func to enable taking your results and limiting them to what you find is ideal.

raw_matches_filepath = compare_all_names(all_names)
print(f"Raw matches saved to: {raw_matches_filepath}")

print("\nApplying scoring and filtering...")
filtered_filepath = add_scrutiny(
    original_filepath=raw_matches_filepath,
    scoring_func=simple_scoring_func,
    threshold=70.0  # Only keep matches with score >= 70
)
print(f"Filtered matches saved to: {filtered_filepath}")

Caveats

Just because two names match does not mean they are the same person represented in two different records. Use other record data and understand that some names are generic. Refining output in some way should probably be part of your data pipeline.

If all the names are really really similar, the bucketing that is done under the hood won't help much. It will be very very slow.

The simple_scoring_func I created is not yet optimized. It isn't the worst, but it is still pretty bad. I am planning on making it better.

Another thing to note- running compare_all_names and other functions currently prints a lot of output, especially loading bars and such for good time estimates. I should probably add an arg that removes output, but I don't want to touch the Go/Python integration again, so I don't know when I'll get to it.

The output is also currently just tuples in a .txt file, which isn't ideal. I'll consider doing something smarter, like .jsonl, as each match output could represent a lot of not a lot of data using a future version of add_scrutiny, but we'll get there when we get there.

ENJOY!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

compare_all_the_names-0.1.3-py3-none-win_amd64.whl (1.4 MB view details)

Uploaded Python 3Windows x86-64

compare_all_the_names-0.1.3-py3-none-manylinux_2_17_x86_64.whl (1.4 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

compare_all_the_names-0.1.3-py3-none-manylinux_2_17_aarch64.whl (1.3 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

compare_all_the_names-0.1.3-py3-none-macosx_11_0_arm64.whl (1.3 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

compare_all_the_names-0.1.3-py3-none-macosx_10_9_x86_64.whl (1.4 MB view details)

Uploaded Python 3macOS 10.9+ x86-64

File details

Details for the file compare_all_the_names-0.1.3-py3-none-win_amd64.whl.

File metadata

File hashes

Hashes for compare_all_the_names-0.1.3-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 7096d8fea99e4df99fc632fa4001ce0e8317e1f1c33b2b5fe00dd27921a450fc
MD5 9fea01953de77699f5f0b46d9185c7eb
BLAKE2b-256 c0927625690061ba36398f930f31f7b340fb094ff02f77b7a7c8a2ba1850f79e

See more details on using hashes here.

File details

Details for the file compare_all_the_names-0.1.3-py3-none-manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for compare_all_the_names-0.1.3-py3-none-manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 e43da78760fcce5a6a04bc07a3bd42648a1071815299a740a12d8d79a5c27b67
MD5 e553cdd05bff89bb7350ae10ae0a423c
BLAKE2b-256 1f897ad35d4eb0d347f13323512d1c543bf4c259ba8758557e26635e0e21b789

See more details on using hashes here.

File details

Details for the file compare_all_the_names-0.1.3-py3-none-manylinux_2_17_aarch64.whl.

File metadata

File hashes

Hashes for compare_all_the_names-0.1.3-py3-none-manylinux_2_17_aarch64.whl
Algorithm Hash digest
SHA256 087d7557d10d6b7563180a0df04193fd835f3b809fff806c89b6da281d52753a
MD5 87fd12d7ed519d6c3235883b6e7f66f5
BLAKE2b-256 cc0350d7d257cbbeeecd7e5e741c43965575692256f2d7af9075bcf509c88a4e

See more details on using hashes here.

File details

Details for the file compare_all_the_names-0.1.3-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for compare_all_the_names-0.1.3-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 4f2c0cc008883fc8f369fe887394094c9640992cbcd573653284553d3df321ae
MD5 22125051b78623573446bc46546959db
BLAKE2b-256 e4b7fc1e9f3ccf121714dfca741babde8a7da20d298b24c2906f50f37f548a17

See more details on using hashes here.

File details

Details for the file compare_all_the_names-0.1.3-py3-none-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for compare_all_the_names-0.1.3-py3-none-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 8289a7703c2aca9a1040fb5d15027654cc88ed759811ee974619b9302c2536c3
MD5 f805bff4cba924b0f0a535c6a07d1616
BLAKE2b-256 e8bca957cb2de50230648f66e50c1af9c9f776f5fa78901142c4701983890563

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page