{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Quickstart deduplication demo \n", "\n", "In this demo we de-duplicate a small dataset.\n", "\n", "The purpose is to demonstrate core Splink functionality as quickly as possible.\n", "\n", "A more comprehensive, end to end example is provided elsewhere" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 1: Imports and setup\n", "\n", "The following is just boilerplate code that sets up the Spark session and sets some other non-essential configuration options" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "RendererRegistry.enable('mimetype')" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd \n", "pd.options.display.max_columns = 500\n", "pd.options.display.max_rows = 100\n", "import altair as alt\n", "alt.renderers.enable('mimetype')" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import logging \n", "logging.basicConfig() # Means logs will print in Jupyter Lab\n", "\n", "# Set to DEBUG if you want splink to log the SQL statements it's executing under the hood\n", "logging.getLogger(\"splink\").setLevel(logging.INFO)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from utility_functions.demo_utils import get_spark\n", "spark = get_spark() # See utility_functions/demo_utils.py for how to set up Spark" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 2: Read in data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the `group` column is the truth - rows which share the same value refer to the same person. In the real world, we wouldn't have this field!" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+---------+----------+-------+----------+------+--------------------+-----+\n", "|unique_id|first_name|surname| dob| city| email|group|\n", "+---------+----------+-------+----------+------+--------------------+-----+\n", "| 0| Julia | null|2015-10-29|London| hannah88@powers.com| 0|\n", "| 1| Julia | Taylor|2015-07-31|London| hannah88@powers.com| 0|\n", "| 2| Julia | Taylor|2016-01-27|London| hannah88@powers.com| 0|\n", "| 3| Julia | Taylor|2015-10-29| null| hannah88opowersc@m| 0|\n", "| 4| oNah| Watson|2008-03-23|Bolton|matthew78@ballard...| 1|\n", "+---------+----------+-------+----------+------+--------------------+-----+\n", "only showing top 5 rows\n", "\n" ] } ], "source": [ "df = spark.read.parquet(\"data/fake_1000.parquet\")\n", "df.show(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 3: Configure splink using the `settings` object\n", "\n", "Most of `splink` configuration options are stored in a settings dictionary. This dictionary allows significant customisation, and can therefore get quite complex. \n", "\n", "💥 We provide an tool for helping to author valid settings dictionaries, which includes tooltips and autocomplete, which you can find [here](http://robinlinacre.com/splink_settings_editor/).\n", "\n", "Customisation overrides default values built into splink. For the purposes of this demo, we will specify a simple settings dictionary, which means we will be relying on these sensible defaults.\n", "\n", "To help with authoring and validation of the settings dictionary, we have written a [json schema](https://json-schema.org/), which can be found [here](https://github.com/moj-analytical-services/splink/blob/master/splink/files/settings_jsonschema.json). \n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "settings = {\n", " \"link_type\": \"dedupe_only\",\n", " \"blocking_rules\": [\n", " \"l.surname = r.surname\"\n", " ],\n", " \"comparison_columns\": [\n", " {\n", " \"col_name\": \"first_name\",\n", " \"num_levels\": 3,\n", " \"term_frequency_adjustments\": True\n", " },\n", " {\n", " \"col_name\": \"dob\"\n", " },\n", " {\n", " \"col_name\": \"city\"\n", " },\n", " {\n", " \"col_name\": \"email\"\n", " }\n", " ],\n", " \"additional_columns_to_retain\": [\"group\"],\n", " \"em_convergence\": 0.01\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In words, this setting dictionary says:\n", "- We are performing a deduplication task (the other options are `link_only`, or `link_and_dedupe`)\n", "- We are going generate comparisons subject to the blocking rules contained in the specified array\n", "- When comparing records, we will use information from the `first_name`, `surname`, `dob`, `city` and `email` columns to compute a match score.\n", "- For `first_name` and `surname`, string comparisons will have three levels:\n", " - Level 2: Strings are (almost) exactly the same\n", " - Level 1: Strings are similar \n", " - Level 0: No match\n", "- We will make adjustments for term frequencies on the `first_name` and `surname` columns\n", "- We will retain the `group` column in the results even though this is not used as part of comparisons. This is a labelled dataset and `group` contains the true match - i.e. where group matches, the records pertain to the same person\n", "- Consider the algorithm to have converged when no parameter changes by more than 0.01 between iterations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 4: Estimate match scores using the Expectation Maximisation algorithm\n", "Columns are assumed to be strings by default. See the 'comparison vector settings' notebook for details of configuration options." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:splink.iterate:Iteration 0 complete\n", "INFO:splink.model:The maximum change in parameters was 0.17303137779235844 for key first_name, level 0\n", "INFO:splink.iterate:Iteration 1 complete\n", "INFO:splink.model:The maximum change in parameters was 0.059999048709869385 for key city, level 1\n", "INFO:splink.iterate:Iteration 2 complete\n", "INFO:splink.model:The maximum change in parameters was 0.02698001265525818 for key email, level 0\n", "INFO:splink.iterate:Iteration 3 complete\n", "INFO:splink.model:The maximum change in parameters was 0.020812273025512695 for key email, level 1\n", "INFO:splink.iterate:Iteration 4 complete\n", "INFO:splink.model:The maximum change in parameters was 0.014915108680725098 for key email, level 0\n", "INFO:splink.iterate:Iteration 5 complete\n", "INFO:splink.model:The maximum change in parameters was 0.010272204875946045 for key email, level 0\n", "INFO:splink.iterate:Iteration 6 complete\n", "INFO:splink.model:The maximum change in parameters was 0.007032573223114014 for key email, level 1\n", "INFO:splink.iterate:EM algorithm has converged\n" ] } ], "source": [ "from splink import Splink\n", "\n", "linker = Splink(settings, df, spark)\n", "df_e = linker.get_scored_comparisons()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Step 5: Inspect results \n", "\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
match_probabilityunique_id_lunique_id_rgroup_lgroup_rfirst_name_lfirst_name_rdob_ldob_rcity_lcity_remail_lemail_r
390.9997831200JuliaJulia2015-07-312016-01-27LondonLondonhannah88@powers.comhannah88@powers.com
380.5006071300JuliaJulia2015-07-312015-10-29LondonNonehannah88@powers.comhannah88opowersc@m
370.035330189018JuliaChirla2015-07-312006-06-28LondonLondonhannah88@powers.commbrooks@booker.com
360.0353301142026JuliaHarry2015-07-312017-11-24LondonLondonhannah88@powers.comcoltonray@lee.com
350.0353301148026JuliaHarry2015-07-312017-09-01LondonLondonhannah88@powers.comcoltonray@lee.com
340.2026501362062JuliaNone2015-07-311989-07-25LondonLondonhannah88@powers.comwagnershane@landry.com
330.0353301363062JuliaNancy2015-07-311989-07-25LondonLondonhannah88@powers.comwagnershane@landry.com
320.0353301364062JuliaNancy2015-07-311989-07-25LondonLondonhannah88@powers.comwagnershane@landry.com
310.0353301365062JuliaNancy2015-07-311989-08-19LondonLondonhannah88@powers.comwagnershane@landry.com
300.0353301367062JuliaNacy2015-07-311989-07-25LondonLondonhannah88@powers.comwagnershane@landry.com
\n", "
" ], "text/plain": [ " match_probability unique_id_l unique_id_r group_l group_r \\\n", "39 0.999783 1 2 0 0 \n", "38 0.500607 1 3 0 0 \n", "37 0.035330 1 89 0 18 \n", "36 0.035330 1 142 0 26 \n", "35 0.035330 1 148 0 26 \n", "34 0.202650 1 362 0 62 \n", "33 0.035330 1 363 0 62 \n", "32 0.035330 1 364 0 62 \n", "31 0.035330 1 365 0 62 \n", "30 0.035330 1 367 0 62 \n", "\n", " first_name_l first_name_r dob_l dob_r city_l city_r \\\n", "39 Julia Julia 2015-07-31 2016-01-27 London London \n", "38 Julia Julia 2015-07-31 2015-10-29 London None \n", "37 Julia Chirla 2015-07-31 2006-06-28 London London \n", "36 Julia Harry 2015-07-31 2017-11-24 London London \n", "35 Julia Harry 2015-07-31 2017-09-01 London London \n", "34 Julia None 2015-07-31 1989-07-25 London London \n", "33 Julia Nancy 2015-07-31 1989-07-25 London London \n", "32 Julia Nancy 2015-07-31 1989-07-25 London London \n", "31 Julia Nancy 2015-07-31 1989-08-19 London London \n", "30 Julia Nacy 2015-07-31 1989-07-25 London London \n", "\n", " email_l email_r \n", "39 hannah88@powers.com hannah88@powers.com \n", "38 hannah88@powers.com hannah88opowersc@m \n", "37 hannah88@powers.com mbrooks@booker.com \n", "36 hannah88@powers.com coltonray@lee.com \n", "35 hannah88@powers.com coltonray@lee.com \n", "34 hannah88@powers.com wagnershane@landry.com \n", "33 hannah88@powers.com wagnershane@landry.com \n", "32 hannah88@powers.com wagnershane@landry.com \n", "31 hannah88@powers.com wagnershane@landry.com \n", "30 hannah88@powers.com wagnershane@landry.com " ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Inspect main dataframe that contains the match scores\n", "cols_to_inspect = [\"match_probability\",\"unique_id_l\",\"unique_id_r\",\"group_l\", \"group_r\", \"first_name_l\",\"first_name_r\",\"dob_l\",\"dob_r\",\"city_l\",\"city_r\",\"email_l\",\"email_r\",]\n", "df_e.toPandas()[cols_to_inspect].sort_values([\"unique_id_l\", \"unique_id_r\"]).head(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `model` property of the `linker` is an object that contains a lot of diagnostic information about how the match probability was computed. The following cells demonstrate some of its functionality" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "application/vnd.vegalite.v4+json": { "$schema": "https://vega.github.io/schema/vega-lite/v4.json", "config": { "header": { "title": null }, "mark": { "tooltip": null }, "title": { "anchor": "middle" }, "view": { "continuousHeight": 300, "continuousWidth": 400, "height": 300, "width": 400 } }, "data": { "name": "data-47c9cefec8b5a658fa5a4b0a9d932e84" }, "datasets": { "data-47c9cefec8b5a658fa5a4b0a9d932e84": [ { "bayes_factor": 0.14410147939944157, "column_name": "first_name", "gamma_column_name": "gamma_first_name", "gamma_index": 0, "level_name": "level_0", "level_proportion": 0.6928292622559145, "log2_bayes_factor": -2.7948429480542165, "m_probability": 0.13900859653949738, "max_gamma_index": 2, "num_levels": 3, "u_probability": 0.9646576642990112 }, { "bayes_factor": 85.44249913097882, "column_name": "first_name", "gamma_column_name": "gamma_first_name", "gamma_index": 1, "level_name": "level_1", "level_proportion": 0.0643744531961846, "log2_bayes_factor": 6.416881940311007, "m_probability": 0.19097650051116943, "max_gamma_index": 2, "num_levels": 3, "u_probability": 0.0022351464722305536 }, { "bayes_factor": 20.23774339228177, "column_name": "first_name", "gamma_column_name": "gamma_first_name", "gamma_index": 2, "level_name": "level_2", "level_proportion": 0.24279629335820507, "log2_bayes_factor": 4.338976526309651, "m_probability": 0.6700149178504944, "max_gamma_index": 2, "num_levels": 3, "u_probability": 0.03310719504952431 }, { "bayes_factor": 0.32617533306715446, "column_name": "dob", "gamma_column_name": "gamma_dob", "gamma_index": 0, "level_name": "level_0", "level_proportion": 0.775181580251985, "log2_bayes_factor": -1.6162804121854508, "m_probability": 0.32492825388908386, "max_gamma_index": 1, "num_levels": 2, "u_probability": 0.9961766600608826 }, { "bayes_factor": 176.5650430303353, "column_name": "dob", "gamma_column_name": "gamma_dob", "gamma_index": 1, "level_name": "level_1", "level_proportion": 0.22481842336731855, "log2_bayes_factor": 7.46405593118224, "m_probability": 0.6750717163085938, "max_gamma_index": 1, "num_levels": 2, "u_probability": 0.003823359962552786 }, { "bayes_factor": 0.3484559801833073, "column_name": "city", "gamma_column_name": "gamma_city", "gamma_index": 0, "level_name": "level_0", "level_proportion": 0.6784829603959892, "log2_bayes_factor": -1.5209516803501855, "m_probability": 0.30098509788513184, "max_gamma_index": 1, "num_levels": 2, "u_probability": 0.8637679219245911 }, { "bayes_factor": 5.131060088408061, "column_name": "city", "gamma_column_name": "gamma_city", "gamma_index": 1, "level_name": "level_1", "level_proportion": 0.32151702960875816, "log2_bayes_factor": 2.359256920625943, "m_probability": 0.6990149021148682, "max_gamma_index": 1, "num_levels": 2, "u_probability": 0.13623206317424774 }, { "bayes_factor": 0.3093960968730767, "column_name": "email", "gamma_column_name": "gamma_email", "gamma_index": 0, "level_name": "level_0", "level_proportion": 0.7707021748608618, "log2_bayes_factor": -1.692473098027287, "m_probability": 0.3086231052875519, "max_gamma_index": 1, "num_levels": 2, "u_probability": 0.9975016117095947 }, { "bayes_factor": 276.73051559940257, "column_name": "email", "gamma_column_name": "gamma_email", "gamma_index": 1, "level_name": "level_1", "level_proportion": 0.2292978070500025, "log2_bayes_factor": 8.11233793121625, "m_probability": 0.6913768649101257, "max_gamma_index": 1, "num_levels": 2, "u_probability": 0.0024983759503811598 } ] }, "encoding": { "color": { "field": "log2_bayes_factor", "scale": { "domain": [ -10, 0, 10 ], "range": [ "red", "orange", "green" ] }, "type": "quantitative" }, "row": { "field": "column_name", "header": { "labelAlign": "left", "labelAnchor": "middle", "labelAngle": 0 }, "sort": { "field": "gamma_index" }, "type": "nominal" }, "tooltip": [ { "field": "column_name", "type": "nominal" }, { "field": "level_name", "type": "ordinal" }, { "field": "m_probability", "format": ".4f", "type": "quantitative" }, { "field": "bayes_factor", "format": ".4f", "type": "quantitative" }, { "field": "level_proportion", "format": ".2%", "title": "Percentage of record comparisons in this level", "type": "nominal" }, { "field": "log2_bayes_factor", "format": ".4f", "title": "log2(Bayes factor, K = m/u)", "type": "quantitative" } ], "x": { "axis": { "title": "log2(Bayes factor, K = m/u)", "values": [ -10, -5, 0, 5, 10 ] }, "field": "log2_bayes_factor", "scale": { "domain": [ -10, 10 ] }, "type": "quantitative" }, "y": { "axis": { "title": null }, "field": "level_name", "type": "nominal" } }, "height": 50, "mark": { "clip": true, "type": "bar" }, "resolve": { "scale": { "y": "independent" } }, "title": "Influence of comparison vector values on match probability" }, "image/png": "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", "text/plain": [ "\n", "\n", "If you see this message, it means the renderer has not been properly enabled\n", "for the frontend that you are using. For more information, see\n", "https://altair-viz.github.io/user_guide/troubleshooting.html\n" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model = linker.model\n", "model.bayes_factor_chart()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "# If charts aren't displaying correctly in your notebook, you can write them to a file (by default splink_charts.html)\n", "model.all_charts_write_html_file(filename=\"splink_charts.html\", overwrite=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also generate a report which explains how the match probability was computed for an individual comparison row. \n", "\n", "Note that you need to convert the row to a dictionary for this to work" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Use graphframes to resolve links into groups" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
estimated_groupunique_idfirst_namesurnamedobcityemailgroup
012JuliaTaylor2016-01-27Londonhannah88@powers.com0
111JuliaTaylor2015-07-31Londonhannah88@powers.com0
233JuliaTaylor2015-10-29Nonehannah88opowersc@m0
347NoahWatson2008-02-05tolonmatthew78@ballard-mcdonald.net1
444oNahWatson2008-03-23Boltonmatthew78@ballard-mcdonald.net1
545NoahWatson2008-03-23Boltonmatthew78@ballard-mcdonald.net1
668WatsonNoah2008-06-15Boltonmatthew78@ballard-mcdonald.net1
766WatsonNoah2008-03-23Nonematthew78@ballard-mcdonald.net1
899NoahWatson2008-01-19BoltonNone1
91010WatsonNoah2008-03-23Boltonmatthbw78eallard-mcdonald.net1
101111WatsonNoah2008-01-21Bolnomatthea78@bwllar-mcdonald.net1
111314MolyBell2002-01-05Peterboroughlricsaunders@sievaadams.info2
121313MollyBell2002-01-05PeterboroughNone2
131515AlexanderAmelia1983-05-19Glasgowic-mpbell@allealewis.org3
141619lmeAiAlexander1983-05-19Glasgowicampbell@allen-lewis.org3
151616AmeliaAlexander1983-05-19GlaogwNone3
161618AmeliaAlexander1983-05-19Glasgowicampbell@allen-lewis.org3
171717AmeliaAlexander1983-04-30Glasgowicampbeal@lllen-lews.org3
182121OliverConnolly1972-03-08PlymouthNone4
192222NoneConnolly1972-03-08Plyohtuderekwilliams@norris.com4
202326OllieThompson1996-03-22Leedsjefferyduke@brown-alazar.org5
212323NoneThompson1996-03-22Leedsjefferyduke@brown-salazar.org5
222525NoneThompson1995-12-18LeedsNone5
232929HarrisMatilda1983-04-30Londonpatricia47@davis.com6
243030MatildaHarris1983-03-03Londonpatricia47@davis.com6
253131HarrisMatilda1983-05-24LondonNone6
263232BaxterAria1992-09-07Londonchristineshepherd@allen.com7
273234BaxterAria1992-09-30Londonchristineshepherd@allen.com7
283333AriaBaxter1992-09-07Londonchristineshepherd@allen.com7
293336AriaBaxter1992-09-07Londonchristineshepherd@allen.com7
\n", "
" ], "text/plain": [ " estimated_group unique_id first_name surname dob \\\n", "0 1 2 Julia Taylor 2016-01-27 \n", "1 1 1 Julia Taylor 2015-07-31 \n", "2 3 3 Julia Taylor 2015-10-29 \n", "3 4 7 Noah Watson 2008-02-05 \n", "4 4 4 oNah Watson 2008-03-23 \n", "5 4 5 Noah Watson 2008-03-23 \n", "6 6 8 Watson Noah 2008-06-15 \n", "7 6 6 Watson Noah 2008-03-23 \n", "8 9 9 Noah Watson 2008-01-19 \n", "9 10 10 Watson Noah 2008-03-23 \n", "10 11 11 Watson Noah 2008-01-21 \n", "11 13 14 Moly Bell 2002-01-05 \n", "12 13 13 Molly Bell 2002-01-05 \n", "13 15 15 Alexander Amelia 1983-05-19 \n", "14 16 19 lmeAi Alexander 1983-05-19 \n", "15 16 16 Amelia Alexander 1983-05-19 \n", "16 16 18 Amelia Alexander 1983-05-19 \n", "17 17 17 Amelia Alexander 1983-04-30 \n", "18 21 21 Oliver Connolly 1972-03-08 \n", "19 22 22 None Connolly 1972-03-08 \n", "20 23 26 Ollie Thompson 1996-03-22 \n", "21 23 23 None Thompson 1996-03-22 \n", "22 25 25 None Thompson 1995-12-18 \n", "23 29 29 Harris Matilda 1983-04-30 \n", "24 30 30 Matilda Harris 1983-03-03 \n", "25 31 31 Harris Matilda 1983-05-24 \n", "26 32 32 Baxter Aria 1992-09-07 \n", "27 32 34 Baxter Aria 1992-09-30 \n", "28 33 33 Aria Baxter 1992-09-07 \n", "29 33 36 Aria Baxter 1992-09-07 \n", "\n", " city email group \n", "0 London hannah88@powers.com 0 \n", "1 London hannah88@powers.com 0 \n", "2 None hannah88opowersc@m 0 \n", "3 tolon matthew78@ballard-mcdonald.net 1 \n", "4 Bolton matthew78@ballard-mcdonald.net 1 \n", "5 Bolton matthew78@ballard-mcdonald.net 1 \n", "6 Bolton matthew78@ballard-mcdonald.net 1 \n", "7 None matthew78@ballard-mcdonald.net 1 \n", "8 Bolton None 1 \n", "9 Bolton matthbw78eallard-mcdonald.net 1 \n", "10 Bolno matthea78@bwllar-mcdonald.net 1 \n", "11 Peterborough lricsaunders@sievaadams.info 2 \n", "12 Peterborough None 2 \n", "13 Glasgow ic-mpbell@allealewis.org 3 \n", "14 Glasgow icampbell@allen-lewis.org 3 \n", "15 Glaogw None 3 \n", "16 Glasgow icampbell@allen-lewis.org 3 \n", "17 Glasgow icampbeal@lllen-lews.org 3 \n", "18 Plymouth None 4 \n", "19 Plyohtu derekwilliams@norris.com 4 \n", "20 Leeds jefferyduke@brown-alazar.org 5 \n", "21 Leeds jefferyduke@brown-salazar.org 5 \n", "22 Leeds None 5 \n", "23 London patricia47@davis.com 6 \n", "24 London patricia47@davis.com 6 \n", "25 London None 6 \n", "26 London christineshepherd@allen.com 7 \n", "27 London christineshepherd@allen.com 7 \n", "28 London christineshepherd@allen.com 7 \n", "29 London christineshepherd@allen.com 7 " ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from graphframes import GraphFrame\n", "\n", "\n", "df_e.createOrReplaceTempView(\"df_e\")\n", "sql = \"\"\"\n", "select unique_id_l as id\n", "from df_e\n", "union\n", "select unique_id_r as id\n", "from df_e\n", "\"\"\"\n", "nodes = spark.sql(sql)\n", "\n", "sql = \"\"\"\n", "select\n", "unique_id_l as src,\n", "unique_id_r as dst,\n", "tf_adjusted_match_prob\n", "from df_e\n", "where tf_adjusted_match_prob > 0.99\n", "\"\"\"\n", "edges = spark.sql(sql)\n", "\n", "g = GraphFrame(nodes, edges)\n", "\n", "cc = g.connectedComponents()\n", "\n", "cc.createOrReplaceTempView(\"cc\")\n", "df.createOrReplaceTempView(\"df\")\n", "sql = \"\"\"\n", "select cc.component as estimated_group, df.*\n", "from cc\n", "left join\n", "df \n", "on cc.id = df.unique_id\n", "order by group, estimated_group\n", "\"\"\"\n", "results = spark.sql(sql)\n", "results.toPandas().head(30)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.3" } }, "nbformat": 4, "nbformat_minor": 4 }