Skip to content

Real time record linkage

Real time linkage

In this notebook, we demonstrate splink's incremental and real time linkage capabilities - specifically:

  • the linker.inference.score_pair function, that allows you to interactively explore the results of a linkage model

Open In Colab

Step 1: Load a pre-trained linkage model

import urllib.request
from pathlib import Path


def get_settings_text() -> str:
    # assumes cwd is repo root
    local_path = Path.cwd() / "docs" / "demos" / "demo_settings" / "real_time_settings.json"

    if local_path.exists():
        return local_path.read_text()

    # fallback location for settings - the file as it is on master, for e.g. colab use
    # TODO: update ref
    url = "https://raw.githubusercontent.com/moj-analytical-services/splink/master/docs/demos/demo_settings/real_time_settings.json"
    with urllib.request.urlopen(url) as u:
        return u.read().decode()
import json

from splink import DuckDBAPI, Linker, splink_datasets

df = splink_datasets.fake_1000

settings = json.loads(get_settings_text())

db_api = DuckDBAPI()
df_sdf = db_api.register(df)
linker = Linker(df_sdf, settings)

Step 2: Comparing two records

It's now possible to compute a match weight for any two records using linker.inference.score_pair()

record_1 = {
    "unique_id": 1,
    "first_name": "Lucas",
    "surname": "Smith",
    "dob": "1984-01-02",
    "city": "London",
    "email": "lucas.smith@hotmail.com",
    "tf_first_name": 0.0012,
    "tf_surname": 0.0134,
    "tf_city": 0.21,

}

record_2 = {
    "unique_id": 2,
    "first_name": "Lucas",
    "surname": "Smith",
    "dob": "1983-02-12",
    "city": "Machester",
    "email": "lucas.smith@hotmail.com",
    "tf_first_name": 0.0012,
    "tf_surname": 0.0134,
    "tf_city": 0.01,

}

linker._settings_obj._retain_intermediate_calculation_columns = True


# Term frequency values should be provided for columns that use term frequency
# adjustments. If they are omitted, Splink falls back to registered term frequency
# lookup tables.


df_two = linker.inference.score_pair(record_1, record_2)
df_two.as_duckdbpyrelation().show(max_width=10000)

linker.visualisations.waterfall_chart(df_two.as_record_list())
┌────────────────────┬────────────────────┬─────────────┬─────────────┬──────────────┬──────────────┬──────────────────┬─────────────────┬─────────────────┬───────────────────┬──────────────────────┬───────────┬───────────┬───────────────┬──────────────┬──────────────┬───────────────────┬─────────────────────┬────────────┬────────────┬───────────┬──────────┬──────────┬────────────────────┬───────────────┬─────────┬───────────┬────────────┬───────────┬───────────┬─────────────────────┬────────────────┬─────────────────────────┬─────────────────────────┬─────────────┬────────────┬────────────┬──────────────────┬─────────────────┬───────────┐
│    match_weight    │ match_probability  │ unique_id_l │ unique_id_r │ first_name_l │ first_name_r │ gamma_first_name │ tf_first_name_l │ tf_first_name_r │   mw_first_name   │ mw_tf_adj_first_name │ surname_l │ surname_r │ gamma_surname │ tf_surname_l │ tf_surname_r │    mw_surname     │  mw_tf_adj_surname  │   dob_l    │   dob_r    │ gamma_dob │ tf_dob_l │ tf_dob_r │       mw_dob       │ mw_tf_adj_dob │ city_l  │  city_r   │ gamma_city │ tf_city_l │ tf_city_r │       mw_city       │ mw_tf_adj_city │         email_l         │         email_r         │ gamma_email │ tf_email_l │ tf_email_r │     mw_email     │ mw_tf_adj_email │ match_key │
│       double       │       double       │    int64    │    int64    │   varchar    │   varchar    │      int32       │     double      │     double      │      double       │        double        │  varchar  │  varchar  │     int32     │    double    │    double    │      double       │       double        │  varchar   │  varchar   │   int32   │  double  │  double  │       double       │    double     │ varchar │  varchar  │   int32    │  double   │  double   │       double        │     double     │         varchar         │         varchar         │    int32    │   double   │   double   │      double      │     double      │   int32   │
├────────────────────┼────────────────────┼─────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼─────────────────┼─────────────────┼───────────────────┼──────────────────────┼───────────┼───────────┼───────────────┼──────────────┼──────────────┼───────────────────┼─────────────────────┼────────────┼────────────┼───────────┼──────────┼──────────┼────────────────────┼───────────────┼─────────┼───────────┼────────────┼───────────┼───────────┼─────────────────────┼────────────────┼─────────────────────────┼─────────────────────────┼─────────────┼────────────┼────────────┼──────────────────┼─────────────────┼───────────┤
│ 13.169052230417613 │ 0.9998914391801992 │           1 │           2 │ Lucas        │ Lucas        │                2 │          0.0012 │          0.0012 │ 6.452385051922501 │    2.271418553616079 │ Smith     │ Smith     │             2 │       0.0134 │       0.0134 │ 6.529599913880287 │ -1.4543338438500726 │ 1984-01-02 │ 1983-02-12 │         0 │     NULL │     NULL │ -2.114723717091652 │           0.0 │ London  │ Machester │          0 │      0.21 │      0.01 │ -1.1635794871398053 │            0.0 │ lucas.smith@hotmail.com │ lucas.smith@hotmail.com │           1 │       NULL │       NULL │ 8.04017554864013 │             0.0 │         0 │
└────────────────────┴────────────────────┴─────────────┴─────────────┴──────────────┴──────────────┴──────────────────┴─────────────────┴─────────────────┴───────────────────┴──────────────────────┴───────────┴───────────┴───────────────┴──────────────┴──────────────┴───────────────────┴─────────────────────┴────────────┴────────────┴───────────┴──────────┴──────────┴────────────────────┴───────────────┴─────────┴───────────┴────────────┴───────────┴───────────┴─────────────────────┴────────────────┴─────────────────────────┴─────────────────────────┴─────────────┴────────────┴────────────┴──────────────────┴─────────────────┴───────────┘