Skip to main content

EntiPy is a Python library that implements an incremental clustering approach to entity resolution.

Project description

EntiPy

EntiPy is a Python library that implements an incremental clustering approach to entity resolution.

Motivation

Entity resolution (ER, also known as identity resolution, data deduplication, data matching, record linkage, merge-purge, and more) is the field concerned with grouping data records that are determined to point to the same real-world thing. The broad concept of ER has uses in master data management, customer data integration, and fraud detection.

ER is a difficult data problem. It is only necessary when matching data records do not share a common identifier, and if implemented naïvely, it is inherently quadratic in time complexity. Modern approaches to ER tend to be divided into three general phases:

  • First, data preprocessing. Records from one or more data sources are transformed into a shape that later stages can consume.
  • Second, blocking. If possible, any given record is tagged as possibly belonging to one or more subsets, or blocks, of records to avoid the need to compare each record against every other record. For example, ER on customers might be blocked by ZIP code.
  • Third, resolution. Records within each block are compared against one another and are clustered based on their similarity to other records. Each cluster aims to be as close as possible to a real-world entity.

This library, EntiPy, implements resolution based on research done by Tauer et al. and Ilagan and Ilagan.

Prerequisites

  • Python 3.11 or higher.
    • We built and tested this version of EntiPy with Python 3.11.2.

Installation

You can install EntiPy with pip. We recommend installing EntiPy in a virtual environment.

pip install entipy

Getting Started

EntiPy's primary focus is on implementing the resolution algorithm, which means that you will need to model your data upfront. We provide tools and documentation to help you with this data modeling.

In this tutorial, a data record will be a potentially-misspelled product name that was read from an OCR scan. To cluster these records is thus to resolve them to the real, underlying products behind the observed product name.

Modeling your data with References and Fields

We first need to define a data record type. We will call the overall shape of a data record a Reference. A Reference will have one or more field properties.

from entipy import Reference, Field

class ProductNameReference(Reference):
    observed_name: Field

Fields represent the different properties of a data record. A field class inherits from the generic Field class. Your custom field class will need to implement one method, compare, which will return whether or not a field instance should be considered to match with another field instance. You can use the value property of the generic Field class as the basis for this comparison.

from entipy import Reference, Field
from rapidfuzz import fuzz

class ProductNameReference(Reference):
    observed_name: Field

class ObservedNameField(Field):
    value: str
    def compare(self, other) -> bool:
        return fuzz.ratio(self.value, other.value) >= 70

A field class also has two additional properties. The float true_match_probability represents the probability that two coreferential References will match on the field. The float false_match_probability represents the probability that two non-coreferential References will match on the field. The default value for true_match_probability is 0.9, and the default value for false_match_probability is 0.1. It is likely that you will need to change these values for each field, which you can do as such:

from entipy import Reference, Field
from rapidfuzz import fuzz

class ProductNameReference(Reference):
    observed_name: Field

class ObservedNameField(Field):
    value: str
    true_match_probability = 0.85
    false_match_probability = 0.15
    def compare(self, other) -> bool:
        return fuzz.ratio(self.value, other.value) >= 70

Once you have modeled your field class, you can replace the type annotation in your ProductNameReference class with your custom ObservedNameField class.

from entipy import Reference, Field
from rapidfuzz import fuzz

# Note that we placed the field class first to satisfy the Python interpreter
class ObservedNameField(Field):
    value: str # This line is optional. It indicates that Field inheritors are expected to have a `value` property.
    true_match_probability = 0.85
    false_match_probability = 0.15
    def compare(self, other) -> bool:
        return fuzz.ratio(self.value, other.value) >= 70

class ProductNameReference(Reference):
    # Please note that you must assign the class of a Field model itself to a property name on your Reference model.
    observed_name = ObservedNameField

Once you have modeled your reference class, you can use it to create Reference objects like so:

ref_1 = ProductNameReference(observed_name="PrimeHarvestCheese10Qg")
ref_2 = ProductNameReference(observed_name="PureGourCetYogurt2.4kg")
ref_3 = ProductNameReference(observed_name="PrimeHarvLstCheese1F0g")

Your reference objects can then be used with the SerialResolver entity resolution engine, which we will discuss next.

Implementing entity resolution with the SerialResolver

The central building block of EntiPy is the SerialResolver. This class is a stateful and thread-unsafe agent that clusters data records.

At a basic level, the SerialResolver accepts a sequence (a list or a set) of references when first instantiated.

from entipy import Reference, Field, SerialResolver

...

resolver = SerialResolver([r1, r2, r3])

You can then call the .resolve() method of the SerialResolver to begin entity resolution. This will make the SerialResolver process the Reference inheritors inplace.

resolver.resolve()

When resolution is complete, you can retrieve the generated clusters with .retrieve_clusters(), which returns a dictionary whose keys are arbitrary cluster IDs and whose values are lists of your Reference instances.

clusters = resolver.retrieve_clusters()

A working demonstration

from entipy import Field, Reference, SerialResolver
from rapidfuzz import fuzz


class ObservedNameField(Field):
    true_match_probability = 0.85
    false_match_probability = 0.15
    def compare(self, other):
        return fuzz.ratio(self.value, other.value) >= 70


class ProductNameReference(Reference):
    observed_name = ObservedNameField


r1 = ProductNameReference(observed_name='PrimeHarvestCheese10Qg')
r2 = ProductNameReference(observed_name='PureGourCetYogurt2.4kg')
r3 = ProductNameReference(observed_name='PrimeHarvLstCheese1F0g')
r4 = ProductNameReference(observed_name='NutSaFusionBakingSoda200g')
r5 = ProductNameReference(observed_name='PrimeIarvestCh~ose100g')
r6 = ProductNameReference(observed_name='PureGotrmetYogurt2_4kg')

sr = SerialResolver([r1, r2, r3, r4, r5, r6])

sr.resolve()

clusters = sr.retrieve_clusters()

The clusters variable should look something like this:

{10: [{'observed_name': 'NutSaFusionBakingSoda200g'}],
 12: [{'observed_name': 'PrimeHarvestCheese10Qg'},
  {'observed_name': 'PrimeHarvLstCheese1F0g'},
  {'observed_name': 'PrimeIarvestCh~ose100g'}],
 14: [{'observed_name': 'PureGourCetYogurt2.4kg'},
  {'observed_name': 'PureGotrmetYogurt2_4kg'}]}

License

By default, EntiPy is licensed under the GNU General Public License version 3 (GPLv3). If you would like to use EntiPy for a project that cannot abide by the terms of GPLv3, please contact us to purchase a commercial license, payable to Archmob Pte. Ltd.

Contact

The principal author and maintainer of this library is Joe Ilagan. He can be reached at joe@archmob.com.

Project details


Download files

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

Source Distribution

entipy-0.0.1.tar.gz (19.2 kB view details)

Uploaded Source

Built Distribution

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

entipy-0.0.1-py3-none-any.whl (20.0 kB view details)

Uploaded Python 3

File details

Details for the file entipy-0.0.1.tar.gz.

File metadata

  • Download URL: entipy-0.0.1.tar.gz
  • Upload date:
  • Size: 19.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.11.2

File hashes

Hashes for entipy-0.0.1.tar.gz
Algorithm Hash digest
SHA256 08738cd13f61ccdb9e0caf2bda61ec84f992a4d0f4fd0ad6acc48b4142538f81
MD5 9ebd27dbc4ff90ecf469311d236fac66
BLAKE2b-256 abf732be007376924f5b9053369ed444e620298ea909fd2d28ee583d0115efe4

See more details on using hashes here.

File details

Details for the file entipy-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: entipy-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 20.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.11.2

File hashes

Hashes for entipy-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0abde674e24eb5d23758d1892b48e967cadcfa7d11e36a8f6687d649b1b2fdd3
MD5 e3cd7eb64c90038e1b682ddd094ce7eb
BLAKE2b-256 9e06f8830df4e41d829f77487e66e3a3734e1a985316f06228a578ffac43db74

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