Beherrschen Sie die Kunst der Datenbereinigung in Python
So bereinigen Sie Ihre Daten in Python und bereiten sie für die Verwendung in einem Data-Science-Projekt vor.
Die Datenbereinigung ist ein wichtiger Bestandteil jedes Datenanalyseprozesses. In diesem Schritt beseitigen Sie Fehler, behandeln fehlende Daten und stellen sicher, dass Ihre Daten in einem Format vorliegen, mit dem Sie arbeiten können. Ohne einen gut bereinigten Datensatz können nachfolgende Analysen verzerrt oder falsch sein.
Dieser Artikel stellt Ihnen mehrere wichtige Techniken zur Datenbereinigung in Python vor, die leistungsstarke Bibliotheken wie Pandas, Numpy, Seaborn und Matplotlib verwenden.
Die Bedeutung der Datenbereinigung verstehen
Bevor wir uns mit den Mechanismen der Datenbereinigung befassen, wollen wir deren Bedeutung verstehen. Daten aus der realen Welt sind oft chaotisch. Es kann doppelte Einträge, falsche oder inkonsistente Datentypen, fehlende Werte, irrelevante Merkmale und Ausreißer enthalten. All diese Faktoren können bei der Datenanalyse zu irreführenden Schlussfolgerungen führen. Dies macht die Datenbereinigung zu einem unverzichtbaren Bestandteil des Data Science-Lebenszyklus.
Wir werden die folgenden Datenbereinigungsaufgaben behandeln.
Setup für die Datenbereinigung in Python
Bevor wir beginnen, importieren wir die erforderlichen Bibliotheken. Wir werden Pandas für die Datenmanipulation und Seaborn und Matplotlib für Visualisierungen verwenden.
Wir werden auch das Python-Modul „datetime“ importieren, um die Daten zu manipulieren.
import pandas as pd
import seaborn as sns
import datetime as dt
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
Laden und Überprüfen Ihrer Daten
Zuerst müssen wir unsere Daten laden. In diesem Beispiel laden wir eine CSV-Datei mit Pandas. Wir fügen auch das Trennzeichenargument hinzu.
df = pd.read_csv('F:\\KDNuggets\\KDN Mastering the Art of Data Cleaning in Python\\property.csv', delimiter= ';')
Als nächstes ist es wichtig, die Daten zu untersuchen, um ihre Struktur zu verstehen, mit welchen Variablen wir arbeiten und ob Werte fehlen. Da die von uns importierten Daten nicht riesig sind, werfen wir einen Blick auf den gesamten Datensatz.
# Look at all the rows of the dataframe
display(df)
So sieht der Datensatz aus.
Sie können sofort erkennen, dass einige Werte fehlen. Außerdem sind die Datumsformate inkonsistent.
Schauen wir uns nun die DataFrame-Zusammenfassung mit der Methode info() an.
# Get a concise summary of the dataframe
print(df.info())
Hier ist die Codeausgabe.
Wir können sehen, dass nur die Spalte „square_feet“ keine NULL-Werte hat, also müssen wir das irgendwie in den Griff bekommen. Auch die Spalten „advertisement_date“ und „sale_date“ sind Objektdatentypen, auch wenn es sich hierbei um ein Datum handeln sollte.
Der Spaltenstandort ist vollständig leer. Brauchen wir es?
Wir zeigen Ihnen, wie Sie mit diesen Problemen umgehen. Wir beginnen damit, zu lernen, wie man unnötige Spalten löscht.
Löschen nicht benötigter Spalten
Es gibt zwei Spalten im Datensatz, die wir in unserer Datenanalyse nicht benötigen, daher werden wir sie entfernen.
Die erste Spalte ist Käufer. Wir brauchen es nicht, da der Name des Käufers keinen Einfluss auf die Analyse hat.
Wir verwenden die Methode drop() mit dem angegebenen Spaltennamen. Wir setzen die Achse auf 1, um anzugeben, dass wir eine Spalte löschen möchten. Außerdem wird das Inplace-Argument auf True gesetzt, sodass wir den vorhandenen DataFrame ändern und keinen neuen DataFrame ohne die entfernte Spalte erstellen.
df.drop('buyer', axis = 1, inplace = True)
Die zweite Spalte, die wir entfernen möchten, ist „Standort“. Obwohl es nützlich sein könnte, diese Informationen zu haben, handelt es sich hierbei um eine völlig leere Spalte, also entfernen wir sie einfach.
Wir gehen dabei genauso vor wie bei der ersten Spalte.
df.drop('location', axis = 1, inplace = True)
Natürlich können Sie diese beiden Spalten gleichzeitig entfernen.
df = df.drop(['buyer', 'location'], axis=1)
Beide Ansätze geben den folgenden Datenrahmen zurück.
Umgang mit doppelten Daten
Doppelte Daten können aus verschiedenen Gründen in Ihrem Datensatz auftreten und Ihre Analyse verfälschen.
Lassen Sie uns die Duplikate in unserem Datensatz erkennen. Hier erfahren Sie, wie es geht.
Der folgende Code verwendet die Methode duplicated() , um Duplikate im gesamten Datensatz zu berücksichtigen. Die Standardeinstellung besteht darin, das erste Vorkommen eines Werts als eindeutig und die nachfolgenden Vorkommen als Duplikate zu betrachten. Sie können dieses Verhalten mit dem Parameter keep ändern. Beispielsweise würde df.duplicated(keep=False) alle Duplikate als wahr markieren, einschließlich des ersten Vorkommens.
# Detecting duplicates
duplicates = df[df.duplicated()]
duplicates
Hier ist die Ausgabe.
Die Zeile mit Index 3 wurde als Duplikat markiert, da Zeile 2 mit denselben Werten zum ersten Mal vorkommt.
Jetzt müssen wir Duplikate entfernen, was wir mit dem folgenden Code tun.
# Detecting duplicates
duplicates = df[df.duplicated()]
duplicates
Die Funktion drop_duplicates() berücksichtigt alle Spalten bei der Identifizierung von Duplikaten. Wenn Sie nur bestimmte Spalten berücksichtigen möchten, können Sie diese wie folgt als Liste an diese Funktion übergeben: df.drop_duplicates(subset=['column1', 'column2']).
Wie Sie sehen können, wurde die doppelte Zeile gelöscht. Allerdings blieb die Indizierung gleich, Index 3 fehlte. Wir werden das bereinigen, indem wir die Indizes zurücksetzen.
df = df.reset_index(drop=True)
Diese Aufgabe wird mithilfe der Funktion reset_index() ausgeführt. Das Argument drop=True wird verwendet, um den ursprünglichen Index zu verwerfen. Wenn Sie dieses Argument nicht angeben, wird der alte Index als neue Spalte in Ihrem DataFrame hinzugefügt. Indem Sie drop=True festlegen, weisen Sie Pandas an, den alten Index zu vergessen und ihn auf den Standard-Integer-Index zurückzusetzen.
Versuchen Sie zur Übung, Duplikate aus diesem Microsoft-Datensatz zu entfernen.
Datentypkonvertierung
Manchmal sind Datentypen möglicherweise falsch eingestellt. Beispielsweise könnte eine Datumsspalte als Zeichenfolge interpretiert werden. Sie müssen diese in die entsprechenden Typen konvertieren.
In unserem Datensatz machen wir das für die Spalten „advertisement_date“ und „sale_date“, da diese als Objektdatentyp angezeigt werden. Außerdem sind die Datumsangaben in den einzelnen Zeilen unterschiedlich formatiert. Wir müssen es konsistent machen und es auf den neuesten Stand bringen.
Der einfachste Weg ist die Verwendung der Methode to_datetime(). Auch hier können Sie dies Spalte für Spalte tun, wie unten gezeigt.
Dabei setzen wir das Argument „dayfirst“ auf „True“, da einige Datumsangaben mit dem ersten Tag beginnen.
# Converting advertisement_date column to datetime
df['advertisement_date'] = pd.to_datetime(df['advertisement_date'], dayfirst = True)
# Converting sale_date column to datetime
df['sale_date'] = pd.to_datetime(df['sale_date'], dayfirst = True)
Sie können auch beide Spalten gleichzeitig konvertieren, indem Sie die Methode apply() mit to_datetime() verwenden.
# Converting advertisement_date and sale_date columns to datetime
df[['advertisement_date', 'sale_date']] = df[['advertisement_date', 'sale_date']].apply(pd.to_datetime, dayfirst = True)
Beide Ansätze führen zum gleichen Ergebnis.
Jetzt haben die Daten ein einheitliches Format. Wir sehen, dass nicht alle Daten konvertiert wurden. Es gibt einen NaT-Wert in „advertisement_date“ und zwei in „sale_date“. Das bedeutet, dass das Datum fehlt.
Überprüfen wir mithilfe der Methode info(), ob die Spalten in Datumsangaben konvertiert werden.
# Get a concise summary of the dataframe
print(df.info())
Wie Sie sehen, haben beide Spalten nicht das Format datetime64[ns].
Versuchen Sie nun, die Daten in diesem Airbnb-Datensatz von TEXT in NUMERIC zu konvertieren.
Umgang mit fehlenden Daten
In realen Datensätzen fehlen häufig Werte. Der Umgang mit fehlenden Daten ist von entscheidender Bedeutung, da bestimmte Algorithmen mit solchen Werten nicht umgehen können.
In unserem Beispiel fehlen auch einige Werte. Schauen wir uns also die beiden gängigsten Ansätze zum Umgang mit fehlenden Daten an.
Zeilen mit fehlenden Werten löschen
Wenn die Anzahl der Zeilen mit fehlenden Daten im Vergleich zur Gesamtzahl der Beobachtungen unbedeutend ist, können Sie erwägen, diese Zeilen zu löschen.
In unserem Beispiel enthält die letzte Zeile außer den Quadratfuß und dem Anzeigendatum keine Werte. Da wir solche Daten nicht verwenden können, entfernen wir diese Zeile.
Hier ist der Code, in dem wir den Index der Zeile angeben.
df = df.drop(8)
Der DataFrame sieht jetzt so aus.
Die letzte Zeile wurde gelöscht und unser DataFrame sieht jetzt besser aus. Es fehlen jedoch noch einige Daten, die wir mit einem anderen Ansatz bearbeiten werden.
Fehlende Werte imputieren
Wenn erhebliche Datenmengen fehlen, könnte die Imputation eine bessere Strategie als das Löschen sein. Bei diesem Vorgang werden fehlende Werte anhand anderer Daten ergänzt. Bei numerischen Daten umfassen gängige Imputationsmethoden die Verwendung eines Maßes für die zentrale Tendenz (Mittelwert, Median, Modus).
In unserem bereits geänderten DataFrame haben wir NaT-Werte (Not a Time) in den Spalten „advertisement_date“ und „sale_date“. Wir imputieren diese fehlenden Werte mit der Methode mean().
Der Code verwendet die Methode fillna(), um die Nullwerte zu finden und mit dem Mittelwert zu füllen.
# Imputing values for numerical columns
df['advertisement_date'] = df['advertisement_date'].fillna(df['advertisement_date'].mean())
df['sale_date'] = df['sale_date'].fillna(df['sale_date'].mean())
Sie können dasselbe auch in einer Codezeile tun. Wir verwenden apply(), um die mit Lambda definierte Funktion anzuwenden. Wie oben verwendet diese Funktion die Methoden fillna() und mean(), um die fehlenden Werte auszufüllen.
# Imputing values for multiple numerical columns
df[['advertisement_date', 'sale_date']] = df[['advertisement_date', 'sale_date']].apply(lambda x: x.fillna(x.mean()))
Die Ausgabe sieht in beiden Fällen so aus.
Unsere Spalte „sale_date“ enthält jetzt Zeiten, die wir nicht benötigen. Entfernen wir sie.
Wir verwenden die Methode strftime(), die die Datumsangaben in ihre Zeichenfolgendarstellung und ein bestimmtes Format konvertiert.
df['sale_date'] = df['sale_date'].dt.strftime('%Y-%m-%d')
Die Daten sehen jetzt alle aufgeräumt aus.
Wenn Sie strftime() für mehrere Spalten verwenden müssen, können Sie lambda erneut wie folgt verwenden.
df[['date1_formatted', 'date2_formatted']] = df[['date1', 'date2']].apply(lambda x: x.dt.strftime('%Y-%m-%d'))
Sehen wir uns nun an, wie wir fehlende kategoriale Werte unterstellen können.
Bei kategorialen Daten handelt es sich um einen Datentyp, der zum Gruppieren von Informationen mit ähnlichen Merkmalen verwendet wird. Jede dieser Gruppen ist eine Kategorie. Kategoriale Daten können numerische Werte annehmen (z. B. „1“ für „männlich“ und „2“ für „weiblich“), diese Zahlen haben jedoch keine mathematische Bedeutung. Sie können sie beispielsweise nicht addieren.
Kategoriale Daten werden normalerweise in zwei Kategorien unterteilt:
Nominale Daten: Dabei werden die Kategorien nur beschriftet und können nicht in einer bestimmten Reihenfolge angeordnet werden. Beispiele hierfür sind Geschlecht (männlich, weiblich), Blutgruppe (A, B, AB, O) oder Farbe (rot, grün, blau).
Ordinaldaten: Hier können die Kategorien geordnet oder geordnet werden. Obwohl die Abstände zwischen den Kategorien nicht gleichmäßig verteilt sind, hat die Reihenfolge der Kategorien eine Bedeutung. Beispiele hierfür sind Bewertungsskalen (1 bis 5 Bewertung eines Films), ein Bildungsniveau (High School, Bachelor, Graduate) oder Krebsstadien (Stadium I, Stadium II, Stadium III).
Für die Imputation fehlender kategorialer Daten wird typischerweise der Modus verwendet. In unserem Beispiel handelt es sich bei der Spalte property_category um kategoriale (nominale) Daten, und in zwei Zeilen fehlen Daten.
Ersetzen wir die fehlenden Werte durch mode.
# For categorical columns
df['property_category'] = df['property_category'].fillna(df['property_category'].mode()[0])
Dieser Code verwendet die Funktion fillna(), um alle NaN-Werte in der Spalte property_category zu ersetzen. Es ersetzt es durch mode.
Darüber hinaus wird der Teil [0] verwendet, um den ersten Wert aus dieser Reihe zu extrahieren. Wenn mehrere Modi vorhanden sind, wird hierdurch der erste ausgewählt. Wenn es nur einen Modus gibt, funktioniert es immer noch einwandfrei.
Hier ist die Ausgabe.
Die Daten sehen jetzt ziemlich gut aus. Es bleibt nur noch zu prüfen, ob es Ausreißer gibt.
Sie können den Umgang mit Nullen bei dieser Meta-Interviewfrage üben, bei der Sie NULL-Werte durch Nullen ersetzen müssen.
Umgang mit Ausreißern
Ausreißer sind Datenpunkte in einem Datensatz, die sich deutlich von den anderen Beobachtungen unterscheiden. Sie können außergewöhnlich weit von den anderen Werten im Datensatz entfernt sein und sich außerhalb eines Gesamtmusters befinden. Sie gelten als ungewöhnlich, da ihre Werte im Vergleich zu den übrigen Daten entweder deutlich höher oder niedriger sind.
Ausreißer können aus verschiedenen Gründen auftreten, wie zum Beispiel:
Mess- oder Eingabefehler
- Datenbeschädigung
- Echte statistische Anomalien
Ausreißer können die Ergebnisse Ihrer Datenanalyse und statistischen Modellierung erheblich beeinflussen. Sie können zu einer verzerrten Verteilung oder Verzerrung führen oder die zugrunde liegenden statistischen Annahmen ungültig machen, die geschätzte Modellanpassung verzerren, die Vorhersagegenauigkeit von Vorhersagemodellen verringern und zu falschen Schlussfolgerungen führen.
Einige häufig verwendete Methoden zur Erkennung von Ausreißern sind Z-Score, IQR (Interquartilbereich), Boxplots, Streudiagramme und Datenvisualisierungstechniken. In einigen fortgeschrittenen Fällen kommen auch Methoden des maschinellen Lernens zum Einsatz.
Die Visualisierung von Daten kann dabei helfen, Ausreißer zu erkennen. Der Boxplot von Seaborn ist hierfür praktisch.
plt.figure(figsize=(10, 6))
sns.boxplot(data=df[['advertised_price', 'sale_price']])
Wir verwenden plt.figure(), um die Breite und Höhe der Figur in Zoll festzulegen.
Dann erstellen wir den Boxplot für die Spalten beworbener_Preis und Verkaufspreis, der so aussieht.
Der Plot kann zur einfacheren Verwendung verbessert werden, indem dies zum obigen Code hinzugefügt wird.
plt.xlabel('Prices')
plt.ylabel('USD')
plt.ticklabel_format(style='plain', axis='y')
formatter = ticker.FuncFormatter(lambda x, p: format(x, ',.2f'))
plt.gca().yaxis.set_major_formatter(formatter)
Wir verwenden den obigen Code, um die Beschriftungen für beide Achsen festzulegen. Wir bemerken auch, dass die Werte auf der y-Achse in der wissenschaftlichen Notation vorliegen und wir diese nicht für die Preiswerte verwenden können. Also ändern wir dies mit der Funktion plt.ticklabel_format() in einen einfachen Stil.
Dann erstellen wir den Formatierer, der die Werte auf der y-Achse mit Kommas als Tausendertrennzeichen und Dezimalpunkten anzeigt. Die letzte Codezeile wendet dies auf die Achse an.
Die Ausgabe sieht nun so aus.
Wie identifizieren und entfernen wir nun den Ausreißer?
Eine Möglichkeit ist die Verwendung der IQR-Methode.
IQR oder Interquartile Range ist eine statistische Methode zur Messung der Variabilität durch Aufteilung eines Datensatzes in Quartile. Quartile unterteilen einen nach Rang geordneten Datensatz in vier gleiche Teile, und Werte im Bereich des ersten Quartils (25. Perzentil) und des dritten Quartils (75. Perzentil) bilden den Interquartilbereich.
Der Interquartilbereich wird verwendet, um Ausreißer in den Daten zu identifizieren. So funktioniert es:
Berechnen Sie zunächst das erste Quartil (Q1) und das dritte Quartil (Q3) und bestimmen Sie dann den IQR. Der IQR wird als Q3 – Q1 berechnet.
- Jeder Wert unter Q1 – 1,5 IQR oder über Q3 + 1,5 IQR gilt als Ausreißer.
In unserem Boxplot stellt die Box tatsächlich den IQR dar. Die Linie innerhalb der Box ist der Median (oder das zweite Quartil). Die „Whisker“ des Boxplots stellen den Bereich innerhalb von 1,5*IQR von Q1 und Q3 dar.
Alle Datenpunkte außerhalb dieser Whiskers können als Ausreißer betrachtet werden. In unserem Fall ist es der Wert von 12.000.000 $. Wenn Sie sich das Boxplot ansehen, werden Sie sehen, wie klar dies dargestellt ist, was zeigt, warum die Datenvisualisierung für die Erkennung von Ausreißern wichtig ist.
Lassen Sie uns nun die Ausreißer entfernen, indem wir die IQR-Methode im Python-Code verwenden. Zunächst entfernen wir die beworbenen Preisausreißer.
Q1 = df['advertised_price'].quantile(0.25)
Q3 = df['advertised_price'].quantile(0.75)
IQR = Q3 - Q1
df = df[~((df['advertised_price'] < (Q1 - 1.5 * IQR)) |(df['advertised_price'] > (Q3 + 1.5 * IQR)))]
Wir berechnen zunächst das erste Quartil (oder das 25. Perzentil) mit der Funktion quantile(). Dasselbe machen wir für das dritte Quartil bzw. das 75. Perzentil.
Sie zeigen die Werte an, unter denen 25 % bzw. 75 % der Daten liegen.
Dann berechnen wir die Differenz zwischen den Quartilen. Bisher geht es nur darum, die IQR-Schritte in Python-Code zu übersetzen.
Als letzten Schritt entfernen wir die Ausreißer. Mit anderen Worten, alle Daten kleiner als Q1 – 1,5 * IQR oder mehr als Q3 + 1,5 * IQR.
Der Operator „~“ negiert die Bedingung, sodass nur die Daten übrig bleiben, die keine Ausreißer sind.
Dann können wir das Gleiche mit dem Verkaufspreis tun.
Q1 = df['sale_price'].quantile(0.25)
Q3 = df['sale_price'].quantile(0.75)
IQR = Q3 - Q1
df = df[~((df['sale_price'] < (Q1 - 1.5 * IQR)) |(df['sale_price'] > (Q3 + 1.5 * IQR)))]
Natürlich können Sie es auch prägnanter machen, indem Sie die for-Schleife verwenden.
for column in ['advertised_price', 'sale_price']:
Q1 = df[column].quantile(0.25)
Q3 = df[column].quantile(0.75)
IQR = Q3 - Q1
df = df[~((df[column] < (Q1 - 1.5 * IQR)) |(df[column] > (Q3 + 1.5 * IQR)))]
Die Schleife durchläuft die beiden Spalten. Für jede Spalte berechnet es den IQR und entfernt dann die Zeilen im DataFrame.
Bitte beachten Sie, dass dieser Vorgang nacheinander ausgeführt wird, zuerst für beworbener_Preis und dann für Verkaufspreis. Dadurch wird der DataFrame für jede Spalte direkt geändert und Zeilen können entfernt werden, da sie in einer Spalte einen Ausreißer darstellen. Daher führt dieser Vorgang möglicherweise zu weniger Zeilen, als wenn Ausreißer für beworbener_Preis und Verkaufspreis unabhängig voneinander entfernt würden und die Ergebnisse anschließend kombiniert würden.
In unserem Beispiel ist die Ausgabe in beiden Fällen gleich. Um zu sehen, wie sich das Boxplot verändert hat, müssen wir es erneut mit demselben Code wie zuvor plotten.
plt.figure(figsize=(10, 6))
sns.boxplot(data=df[['advertised_price', 'sale_price']])
plt.xlabel('Prices')
plt.ylabel('USD')
plt.ticklabel_format(style='plain', axis='y')
formatter = ticker.FuncFormatter(lambda x, p: format(x, ',.2f'))
plt.gca().yaxis.set_major_formatter(formatter)
Hier ist die Ausgabe.
Sie können die Berechnung von Perzentilen in Python üben, indem Sie die Interviewfrage zur Generalversammlung lösen.
Abschluss
Die Datenbereinigung ist ein entscheidender Schritt im Datenanalyseprozess. Obwohl es zeitaufwändig sein kann, ist es wichtig, die Genauigkeit Ihrer Ergebnisse sicherzustellen.
Glücklicherweise macht das umfangreiche Python-Ökosystem an Bibliotheken diesen Prozess einfacher zu handhaben. Wir haben gelernt, wie man unnötige Zeilen und Spalten entfernt, Daten neu formatiert und mit fehlenden Werten und Ausreißern umgeht. Dies sind die üblichen Schritte, die für die meisten Daten ausgeführt werden müssen. Manchmal müssen Sie jedoch auch zwei Spalten zu einer zusammenfassen, die vorhandenen Daten überprüfen, ihnen Beschriftungen zuweisen oder die Leerzeichen entfernen.
All dies ist eine Datenbereinigung, da es Ihnen ermöglicht, chaotische, reale Daten in einen gut strukturierten Datensatz umzuwandeln, den Sie sicher analysieren können. Vergleichen Sie einfach den Datensatz, mit dem wir begonnen haben, mit dem, mit dem wir am Ende gelandet sind.
Wenn Sie in diesem Ergebnis keine Genugtuung sehen und die sauberen Daten Sie nicht seltsam begeistern, was zum Teufel machen Sie dann in der Datenwissenschaft?