Daten deduplizieren#

1. Beispieldaten laden#

[1]:
import pandas as pd
[2]:
customers = pd.read_csv(
    "https://raw.githubusercontent.com/kjam/data-cleaning-101/master/data/customer_data_duped.csv",
    encoding="utf-8",
)

2. Deduplizieren mit pandas#

2.1 Überblick#

[3]:
customers
[3]:
name job company street_address city state email user_name
0 Patricia Schaefer Programmer, systems Estrada-Best 398 Paul Drive Christianview Delaware lambdavid@gmail.com ndavidson
1 Olivie Dubois Ingénieur recherche et développement en agroal... Moreno rue Lucas Benard Saint Anastasie-les-Bains AR berthelotjacqueline@mahe.fr manonallain
2 Mary Davies-Kirk Public affairs consultant Baker Ltd Flat 3\nPugh mews Stanleyfurt ZA middletonconor@hotmail.com colemanmichael
3 Miroslawa Eckbauer Dispensing optician Ladeck GmbH Mijo-Lübs-Straße 12 Neubrandenburg Berlin sophia01@yahoo.de romanjunitz
4 Richard Bauer Accountant, chartered certified Hoffman-Rocha 6541 Rodriguez Wall Carlosmouth Texas tross@jensen-ware.org adam78
... ... ... ... ... ... ... ... ...
2075 Maurice Stey Systems developer Linke Margraf GmbH & Co. OHG Laila-Scheibe-Allee 2/0 Luckenwalde Hamburg gutknechtevelyn@niemeier.com dkreusel
2076 Linda Alexander Commrcil horiculuri Webb, Ballald and Vasquel 5594 Persn Ciff Mooneybury Maryland ahleythoa@ail.co kennethrchn
2077 Diane Bailly Pharmacien Voisin 527, rue Dijoux Duval-les-Bains CH aruiz@reynaud.fr dorothee41
2078 Jorge Riba Cerdán Hotel manager Amador-Diego Rambla de Adriana Barceló 854 Puerta 3 Huesca Asturias manuelamosquera@yahoo.com eugenia17
2079 Ryan Thompson Brewing technologist Smith-Sullivan 136 Rodriguez Point Bradfordborough North Dakota lcruz@gmail.com cnewton

2080 rows × 8 columns

2.2 Datentypen anzeigen#

Hierfür verwenden wir pandas.DataFrame.dtypes:

[4]:
customers.dtypes
[4]:
name              object
job               object
company           object
street_address    object
city              object
state             object
email             object
user_name         object
dtype: object

2.3 Fehlende Werte ermitteln#

pandas.isnull zeigt für ein array-ähnliches Objekt an, ob Werte fehlen:

  • NaN in numerischen Arrays

  • None oder NaN in Objekt-Arrays

  • NaT in datetimelike

Siehe auch:

[5]:
for col in customers.columns:
    print(col, customers[col].isnull().sum())
name 0
job 0
company 0
street_address 0
city 0
state 0
email 0
user_name 0

2.4 Duplizierte Datensätze ermitteln#

[6]:
customers.duplicated()
[6]:
0       False
1       False
2       False
3       False
4       False
        ...
2075    False
2076    False
2077    False
2078    False
2079    False
Length: 2080, dtype: bool

customers.duplicated() gibt uns noch nicht den gewünschten Hinweis, ob es doppelte Datensätze gibt. Im Folgenden lassen wir uns alle Datensätze ausgeben, für die True zurückgegeben wird:

[7]:
customers[customers.duplicated()]
[7]:
name job company street_address city state email user_name

Offenbar gibt es keine duplizierten Datensätze.

2.5 Duplizierte Daten löschen#

Das Löschen duplizierter Datensätze mit drop_duplicates sollte demnach nichts ändern und die Anzahl der Datensätze bei 2080 belassen:

[7]:
customers.drop_duplicates()
[7]:
name job company street_address city state email user_name
0 Patricia Schaefer Programmer, systems Estrada-Best 398 Paul Drive Christianview Delaware lambdavid@gmail.com ndavidson
1 Olivie Dubois Ingénieur recherche et développement en agroal... Moreno rue Lucas Benard Saint Anastasie-les-Bains AR berthelotjacqueline@mahe.fr manonallain
2 Mary Davies-Kirk Public affairs consultant Baker Ltd Flat 3\nPugh mews Stanleyfurt ZA middletonconor@hotmail.com colemanmichael
3 Miroslawa Eckbauer Dispensing optician Ladeck GmbH Mijo-Lübs-Straße 12 Neubrandenburg Berlin sophia01@yahoo.de romanjunitz
4 Richard Bauer Accountant, chartered certified Hoffman-Rocha 6541 Rodriguez Wall Carlosmouth Texas tross@jensen-ware.org adam78
... ... ... ... ... ... ... ... ...
2075 Maurice Stey Systems developer Linke Margraf GmbH & Co. OHG Laila-Scheibe-Allee 2/0 Luckenwalde Hamburg gutknechtevelyn@niemeier.com dkreusel
2076 Linda Alexander Commrcil horiculuri Webb, Ballald and Vasquel 5594 Persn Ciff Mooneybury Maryland ahleythoa@ail.co kennethrchn
2077 Diane Bailly Pharmacien Voisin 527, rue Dijoux Duval-les-Bains CH aruiz@reynaud.fr dorothee41
2078 Jorge Riba Cerdán Hotel manager Amador-Diego Rambla de Adriana Barceló 854 Puerta 3 Huesca Asturias manuelamosquera@yahoo.com eugenia17
2079 Ryan Thompson Brewing technologist Smith-Sullivan 136 Rodriguez Point Bradfordborough North Dakota lcruz@gmail.com cnewton

2080 rows × 8 columns

Nun wollen wir nur diejenigen Datensätze löschen, deren user_name identisch ist:

[8]:
customers.drop_duplicates(["user_name"])
[8]:
name job company street_address city state email user_name
0 Patricia Schaefer Programmer, systems Estrada-Best 398 Paul Drive Christianview Delaware lambdavid@gmail.com ndavidson
1 Olivie Dubois Ingénieur recherche et développement en agroal... Moreno rue Lucas Benard Saint Anastasie-les-Bains AR berthelotjacqueline@mahe.fr manonallain
2 Mary Davies-Kirk Public affairs consultant Baker Ltd Flat 3\nPugh mews Stanleyfurt ZA middletonconor@hotmail.com colemanmichael
3 Miroslawa Eckbauer Dispensing optician Ladeck GmbH Mijo-Lübs-Straße 12 Neubrandenburg Berlin sophia01@yahoo.de romanjunitz
4 Richard Bauer Accountant, chartered certified Hoffman-Rocha 6541 Rodriguez Wall Carlosmouth Texas tross@jensen-ware.org adam78
... ... ... ... ... ... ... ... ...
2074 Rhonda James Recruitment consultant Turner, Bradley and Scott 28382 Stokes Expressway Port Gabrielaport New Hampshire zroberts@hotmail.com heathscott
2076 Linda Alexander Commrcil horiculuri Webb, Ballald and Vasquel 5594 Persn Ciff Mooneybury Maryland ahleythoa@ail.co kennethrchn
2077 Diane Bailly Pharmacien Voisin 527, rue Dijoux Duval-les-Bains CH aruiz@reynaud.fr dorothee41
2078 Jorge Riba Cerdán Hotel manager Amador-Diego Rambla de Adriana Barceló 854 Puerta 3 Huesca Asturias manuelamosquera@yahoo.com eugenia17
2079 Ryan Thompson Brewing technologist Smith-Sullivan 136 Rodriguez Point Bradfordborough North Dakota lcruz@gmail.com cnewton

2029 rows × 8 columns

Dies löschte 51 Datensätze.

3. Dedupe#

Alternativ können wir die duplizierte Daten mit der Dedupe-Bibliothek erkennen, die ein flaches neuronales Netzwerk verwendet, um aus einem kleinen Training zu lernen.

Siehe auch

csvdedupe bietet ein Kommandozeilenwerkzeug für Dedupe.

Zudem haben dieselben Entwickler*innen parserator erstellt, mit dem ihr Textfunktionen extrahieren und eure eigenen Textextraktion trainieren könnt.

3.1 Dedupe konfigurieren#

Nun definieren wir die Felder, auf die bei der Deduplizierung geachtet werden soll und erstellen ein neues deduper-Objekt:

[9]:
import os

import dedupe


customers = pd.read_csv(
    "https://raw.githubusercontent.com/kjam/data-cleaning-101/master/data/customer_data_duped.csv",
    encoding="utf-8",
)
[10]:
variables = [
    {"field": "name", "type": "String"},
    {"field": "job", "type": "String"},
    {"field": "company", "type": "String"},
    {"field": "street_address", "type": "String"},
    {"field": "city", "type": "String"},
    {"field": "state", "type": "String", "has_missing": True},
    {"field": "email", "type": "String", "has_missing": True},
    {"field": "user_name", "type": "String"},
]

deduper = dedupe.Dedupe(variables)

Wenn der Wert eines Feldes fehlt, sollte dieser fehlende Wert als None-Objekt dargestellt werden. Durch 'has_missing': True wird jedoch ein neues, zusätzliches Feld erstellt, das angibt, ob die Daten vorhanden waren oder nicht, und die fehlenden Daten werden mit Null versehen.

Siehe auch

[11]:
deduper
[11]:
<dedupe.api.Dedupe at 0x7f03b6d92610>
[12]:
customers.shape
[12]:
(2080, 8)

4. Trainingsdaten erstellen#

[13]:
deduper.prepare_training(customers.T.to_dict())

prepare_training initialisiert das aktive Lernen mit unseren Daten und, optional, mit vorhandenen Trainingsdaten.

T spiegelt den DataFrame über seine Diagonale, indem Zeilen als Spalten geschrieben werden und umgekehrt. Hierfür wird pandas.DataFrame.transpose verwendet.

5. Aktives Lernen#

Mit dedupe.console_label könnt ihr eure Dedupe-Instanz trainieren. Wenn Dedupe ein Datensatzpaar findet, werdet ihr gebeten, es als Duplikat zu kennzeichnen. Ihr könnt hierfür die Tasten y, n und u, um Duplikate zu kennzeichnen. Drückt f, wenn ihr fertig seid.

[14]:
dedupe.console_label(deduper)
name : Kenneth Moore
job : Magazine journalist
company : Cross, Bell and Diaz
street_address : 75443 Lindsey Pine
city : Thompsonshire
state : Colorado
email : ashley28@rice.com
user_name : todd72

name : Kenneth Moore
job : Magazine journalist
company : Cross, Bfll anf Diaz
street_address : 753 Lindsey Pine
city : Thompsonshe
state : Colorao
email : ashey28@rice.co
user_name : todd72

0/10 positive, 0/10 negative
Do these records refer to the same thing?
(y)es / (n)o / (u)nsure / (f)inished
y
name : Frédérique Lejeune-Daniel
job : Technicien chimiste
company : Schmitt
street_address : chemin Denise Ferrand
city : Saint CharlotteVille
state : IE
email : jchretien@costa.com
user_name : joseph60

name : Frédérique Lejeune-Daniel
job : Tecce cse
company : Sctmitt
street_address : chemin Denise Ferrand
city : Saint ChalotteVille
state : IE
email : jchretien@costacom
user_name : joseph60

1/10 positive, 0/10 negative
Do these records refer to the same thing?
(y)es / (n)o / (u)nsure / (f)inished / (p)revious
y
name : Herr Johann Eigenwillig
job : Immigrtion officer
company : Süßebuer Hänel GmbH
street_address : Lanernplatz 0
city : Stadtsteinach
state : Thürinen
email : hemieluie@nock.com
user_name : istoll

name : Herr Johann Eigenwillig
job : Immigration officer
company : Süßebier Hänel GmbH
street_address : Langernplatz 0
city : Stadtsteinach
state : Thüringen
email : haasemarieluise@noack.com
user_name : istoll

2/10 positive, 0/10 negative
Do these records refer to the same thing?
(y)es / (n)o / (u)nsure / (f)inished / (p)revious
y
name : Dr. Catherine Sutton
job : Engineer, maintenance
company : Ross LLC
street_address : 13689 Morales Centers
city : North Sarah
state : New Mexico
email : lewisnicole@yahoo.com
user_name : clittle

name : Dr. Catherine Sutton
job : Enginee maintenance
company : Ross LLC
street_address : 13689 Morales Centers
city : North Sarah
state : New Mexico
email : ewinicoe@yaoo.com
user_name : little

3/10 positive, 0/10 negative
Do these records refer to the same thing?
(y)es / (n)o / (u)nsure / (f)inished / (p)revious
y
name : Andrés Franco Bravo
job : Photographer
company : Pareja-Fábregas
street_address : Cuesta Margarita Robledo 251 Piso 1
city : Granada
state : Alicante
email : fátimazamora@batlle.com
user_name : losasebastian

name : Andrés Franco Bravo
job : Photographer
company : Pare8a8Fábre8as
street_address : Cuesta Magaita Robledo 251 Piso 1
city : Granada
state : Alicante
email : fáimazamra@balle.cm
user_name : lsasebastian

4/10 positive, 0/10 negative
Do these records refer to the same thing?
(y)es / (n)o / (u)nsure / (f)inished / (p)revious
f
Finished labeling

Die letzten beiden verglichenen Trainingsdatensätze machen deutlich, dass wir dieses Duplikat mit unserem obigen drop_duplicates-Beispiel nicht gelöscht haben – clittle und little wurden als unterschiedlich erkannt.

Mit Dedupe.train werden die von euch markierten Datensatzpaare zu den Trainingsdaten hinzugefügt und das Matching-Modell aktualisiert.

Mit index_predicates=True berücksichtigt die Deduplizierung auch Prädikate, die auf der Indizierung der Daten beruhen.

Wenn ihr fertig seid, speichert eure Trainingsdaten mit Dedupe.write_settings.

[15]:
settings_file = "csv_example_learned_settings"

if os.path.exists(settings_file):
    print("reading from", settings_file)
    with open(settings_file, "rb") as f:
        deduper = dedupe.StaticDedupe(f)
else:
    deduper.train(index_predicates=True)
    with open(settings_file, "wb") as sf:
        deduper.write_settings(sf)
reading from csv_example_learned_settings

Mit dedupe.Dedupe.partition werden Datensätze identifiziert, die sich alle auf dieselbe Entität beziehen, und als Tupel zurückgegeben, die eine Folge von Datensatz-IDs und Konfidenzwerten sind. Weitere Einzelheiten zum Konfidenzwert findet ihr unter dedupe.Dedupe.cluster.

[16]:
dupes = deduper.partition(customers.T.to_dict())
[17]:
dupes
[17]:
[((136, 1360), (1.0, 1.0)),
 ((298, 1026), (1.0, 1.0)),
 ((354, 858), (1.0, 1.0)),
 ((478, 1119), (1.0, 1.0)),
 ((938, 1890), (1.0, 1.0)),
 ((1785, 1939), (1.0, 1.0)),
 ((0,), (1.0,)),
 ((1,), (1.0,)),
 ((2,), (1.0,)),
 ((3,), (1.0,)),
 ((4,), (1.0,)),
 ...]

Wir können uns auch nur einzelne Einträge ausgeben lassen:

[18]:
dupes[0]
[18]:
((136, 1360), (1.0, 1.0))

Diese können wir uns dann mit pandas.DataFrame.iloc anzeigen lassen:

[19]:
customers.iloc[[136,1360]]
[19]:
name job company street_address city state email user_name
136 Frédérique Lejeune-Daniel Technicien chimiste Schmitt chemin Denise Ferrand Saint CharlotteVille IE jchretien@costa.com joseph60
1360 Frédérique Lejeune-Daniel Tecce cse Sctmitt chemin Denise Ferrand Saint ChalotteVille IE jchretien@costacom joseph60