Dies ist Teil zwei von zwei in einer Reihe zum Bereinigen von Daten mit Go. Im ersten Teil haben wir die grundlegenden Textfunktionen von Go und die Arbeit mit CSV-Dateien behandelt. In diesem Tutorial beschäftigen wir uns mit der eigentlichen Datenbereinigung.
Wir beginnen damit, das Problem der unordentlichen Daten zu verstehen und eine Strategie auszuarbeiten. Anschließend werden wir die einzelnen Felder überprüfen, die Daten nach Möglichkeit korrigieren und entscheiden, was bei fehlenden Werten zu tun ist.
Eine Strategie zum Bereinigen von Daten sollte festlegen, was bei ungültigen, unordentlichen, unvollständigen oder fehlenden Daten zu tun ist. Außerdem sollte festgelegt werden, welche Berichtsebene für den Bereinigungsprozess erforderlich ist.
Die Daten, auf die wir uns hier konzentrieren, sind Tabellendaten, wobei jede Zeile unabhängig ist. Es gibt keine verschachtelten Hierarchien oder Verbindungen zwischen verschiedenen Datenzeilen. Viele reale Datensätze haben diese schöne Eigenschaft.
Der einfachste Ansatz für den Umgang mit ungültigen Daten besteht darin, diese zu entfernen. Wenn ein Feld fehlt oder ungültige Daten enthält, entfernen Sie einfach die gesamte Zeile. Das ist sehr einfach und manchmal ist es das Richtige. Wenn das problematische Feld kritisch ist und Sie keine Möglichkeit zur Wiederherstellung haben, können Sie nur den gesamten Datensatz löschen.
Die beste Lösung besteht darin, das schlechte Feld zu korrigieren. In einigen Fällen ist es einfach, das Problem zu erkennen und zu beheben. Im UFO-Sichtungsdatensatz kann das Zustandsfeld einer der 52 Bundesstaaten der USA sein.
Wenn der Wert nur aus Großbuchstaben bestehen muss und einige Zeilen Kleinbuchstaben enthalten, können Sie sie einfach in Großbuchstaben setzen.
Das Melden ungültiger Zeilen, entweder gelöscht oder korrigiert, ist wichtig. Die Organisation kann entscheiden, dass die Benutzer versuchen, abgelegte Daten zu reparieren. Möglicherweise müssen von QA feste Daten ausgeführt werden, um sicherzustellen, dass die automatischen Korrekturen keine ungültigen Daten enthalten.
Das Sammeln von Statistiken zum Bereinigungsprozess ist notwendig, um die Qualität der Quelldaten zu bewerten und manchmal zu bestimmen, ob die bereinigten Daten überhaupt eine Verarbeitung wert sind. Die Statistiken können die Anzahl der abgelegten und festen Zeilen sowie die Anzahl der fehlerhaften und fehlenden Felder für jede Spalte enthalten.
Bisher habe ich einen Vorverarbeitungsansatz für die Datenbereinigung beschrieben. Es ist jedoch möglich, die Bereinigung während der Verarbeitung durchzuführen. Jede Zeile wird kurz vor der Verarbeitung geprüft. Dies ist manchmal nützlich, wenn die Vorverarbeitung keinen Sinn macht, weil schlechte Daten nicht rechtzeitig für eine spätere Analyse korrigiert werden können oder wenn die Verarbeitung zeitabhängig ist.
In diesem Szenario besteht der Hauptzweck der Bereinigung darin, sicherzustellen, dass fehlerhafte Datenzeilen nicht die gesamte Verarbeitungspipeline beschädigen und nach Bedarf übersprungen oder behoben werden können.
Wie gehen Sie bei der Überprüfung der Felder vor? Sie müssen genau wissen, welche Art von Daten dort vorhanden sein sollen und manchmal welche Werte. Hier einige Beispiele.
Numerische Felder sind in Datensätzen sehr häufig. Abgesehen von der Art der Zahl (Ganzzahl, Real, Komplex) sind einige Felder spezialisierter. Beispielsweise kann ein Preisfeld genau zwei Dezimalstellen erfordern und positiv sein. Hier ist eine Funktion, die prüft, ob eine Zeichenfolge einen Preis darstellt:
func validate_price (s string) bool parts: = strings.Split (s, ".") if len (parts)! = 2 return false US-Dollar, err: = strconv.Atoi (parts [0]) if err! = null return false wenn Dollar < 0 return false cents, err := strconv.Atoi(parts[1]) if err != nil return false if cents < 0 || cents > 99 return false return true
Manchmal müssen Sie darüber hinausgehen. Wenn Sie überprüfen müssen, ob eine URL gültig ist, gibt es zwei Ansätze:
Wenn Sie nur darauf achten, ob die URL gut geformt ist, funktioniert der erste Ansatz. Wenn Sie jedoch sicherstellen möchten, dass die URL tatsächlich auf ein echtes Ziel verweist, müssen Sie den zweiten Ansatz verwenden. Da der zweite Ansatz eine Obermenge des ersten Ansatzes ist, verwenden wir ihn einfach:
func validate_url (url string) bool _, err: = http.Head (url) return err == nil
Wenn die Werte ein benutzerdefiniertes Format einhalten müssen, können Sie sie normalerweise mithilfe von einfachen Zeichenfolgenfunktionen wie anpassen Teilt()
oder verwenden Sie in komplexeren Fällen reguläre Ausdrücke. Wenn Ihr Datensatz beispielsweise Sozialversicherungsnummern (ich hoffe nicht) im Format enthält XXX-XX-XXXX
Dann können Sie durch "-" aufteilen und sicherstellen, dass es drei Token gibt, bei denen der erste dreistellig ist, der zweite zweistellig ist und der dritte vierstellig ist. Aber es ist knapper, eine Regex wie ^ \ d 3 -? \ d 2 -? \ d 4 $
.
Das Festlegen ungültiger Werte ist keine triviale Sache. Wenn Ihre Fixierungsmethode nicht korrekt ist, können Sie beschädigte Daten erhalten. Sie sollten die Wichtigkeit des Feldes, den Bereich möglicher gültiger Werte und die Gewissheit, dass Sie einen ungültigen Wert wirklich automatisch korrigieren können, sorgfältig überlegen.
Dies ist eine ziemlich sichere Lösung. Wenn ein Textfeld nur aus Großbuchstaben bestehen soll, können Sie es korrigieren, ohne viel zu riskieren, da die ursprünglich Kleinbuchstaben keine wichtige Information sind. Es ist nicht erforderlich, speziellen Code zu schreiben, da das Paket mit den Zeichenfolgen eine enthält ToOpper ()
Funktion. Es gibt auch Zu senken()
und selbst ToTitle ()
und ToTitleSpecific ()
Funktionen, um Text richtig zu schreiben.
Eine andere häufige einfache Lösung ist das Entfernen von führenden und nachgestellten Leerzeichen. Sie werden überrascht sein, wie viele Personen bei der Dateneingabe Leerzeichen oder neue Zeilen hinzufügen. Das String-Paket hat eine Auswahl von TrimXXX ()
Funktionen, die den meisten Situationen gerecht werden:
In einigen Fällen können ungültige Zeichen gelöscht werden. Ich empfehle es nur für unkritische und optionale Felder. Beispielsweise haben Sie möglicherweise ein Beschreibungs- oder Notizfeld, das Freitext enthält, und Sie möchten sicherstellen, dass es keine bestimmten Symbole wie Anführungszeichen oder Anführungszeichen enthält. So wird's gemacht:
func remove_quotes (s Zeichenfolge) string var b bytes.Buffer für _, r: = range (s) if r! = '"' && r! = '\" b.WriteRune (r) return b. String () func main () original: = "Anführungszeichen" und "doppelte Anführungszeichen". ' clean: = remove_quotes (original) fmt.Println (original) fmt.Println (clean) Ausgabe: "Anführungszeichen" und "doppelte Anführungszeichen". Anführungszeichen und doppelte Anführungszeichen.
Numerische Werte sind oft leicht zu korrigieren. Wenn Sie eine Genauigkeit von zwei Dezimalstellen benötigen, können Sie zusätzliche Ziffern abschneiden oder abrunden. Auf dieselbe Weise können Ganzzahlen leicht in Gleitkommazahlen umgewandelt werden.
In einigen Fällen gibt es einen Bereich gültiger Werte, und Sie können zu große oder zu kleine Werte eingeben, um in den Bereich zu passen. Die folgende Funktion akzeptiert einen String und einen Bereich von ganzen Zahlen und gibt einen String zurück, der eine ganze Zahl innerhalb des Bereichs darstellt. Zu große Werte werden zum Maximalwert und zu klein zum Minimalwert.
func fit_into_range (s string, min int, max int) string n, _: = strconv.Atoi (s) wenn n < min n = min else if n > max n = max else return s return strconv.Itoa (n) func main () fmt.Println (fit_into_range ("15", 10, 20)) fmt.Println (fit_into_range ("- 15", 10, 20)) fmt.Println (fit_into_range ("55", 10, 20)) Ausgabe: 15 10 20
URLs können häufig sicher behoben werden, indem Sie verschiedene Schemas ("http" oder "https") ausprobieren oder "www" -Domänen hinzufügen oder löschen. Durch das Kombinieren der Optionen mit dem Versuch, die Kandidaten abzurufen, können Sie sicher sein, dass der Fix richtig war.
Fehlende Werte treten häufig auf, wenn Daten aus der realen Welt aufgenommen werden. Wenn der fehlende Wert erforderlich ist, gibt es zwei Hauptmethoden, um damit umzugehen (ohne die Zeile insgesamt zu verwerfen). Verwenden Sie die Standardwerte oder stellen Sie den Wert aus einer alternativen Quelle wieder her.
Standardwerte sind hilfreich, da der Verarbeitungscode nicht prüfen muss, ob ein Wert vorhanden ist oder nicht. Der Datenbereinigungscode stellt sicher, dass immer ein Wert vorhanden ist. In vielen Fällen ist der Standard so üblich, dass er auch bei der Dateneingabe hilfreich ist, wenn Sie nicht immer denselben Standardwert eingeben müssen.
Dieser Ansatz ist etwas komplizierter. Die Idee ist, eine andere Datenquelle abzurufen, die die angeforderten Informationen enthält. Wenn Sie beispielsweise eine E-Mail eines Benutzers haben, der Vor- und Nachname nicht vorhanden ist, können Sie Ihre Benutzerdatenbank abfragen und den Namen des Benutzers extrahieren. Dadurch kann der Verarbeitungscode nicht auf die Datenbank zugreifen oder sich dieser Abhängigkeit bewusst sein.
Bereinigen wir einen kleinen Datensatz von Produkten. Die Felder sind:
Spaltenname | Spaltenbeschreibung |
---|---|
Ich würde | PRD-XXXX-XXXX (wobei X eine Ziffer ist) |
Name | bis zu 40 Zeichen lang |
Preis | Zahlenfeld mit fester Genauigkeit (zwei Dezimalpunkte) |
Beschreibung | bis zu 500 Zeichen (optional) |
Hier ist der Datensatz in einer lesbaren Form (Leerzeichen werden während der Bereinigung abgeschnitten):
const data = 'ID, Name, Preis, Beschreibung PRD-1234-0000, Airzooka, 9.99, Schießt Menschen in Luft PRD-1234-0017, Rosa Onesie, 34.55, PRD-1234-666, Oh, 18.18, Ungültige Produkt-ID PRD-1234-7777, oh oh 2,, fehlender Preis prd-1234-8888, PostIt !, 13.13, Fixierbar: Kleinbuchstaben-ID '
Die ersten beiden Produkte sind gültig. Dem dritten Produkt "PRD-1234-666" fehlt eine Ziffer in seiner ID. Das nächste Produkt, "PRD-1234-7777", hat keinen Preis. Das letzte Produkt, "prd-1234-8888", hat eine ungültige Produkt-ID. Es kann jedoch sicher behoben werden (Großbuchstaben machen)..
Der folgende Code bereinigt die Daten, behebt, was behoben werden kann, löscht die Zeilen, die nicht korrigiert werden können, und erstellt ein sauberes Dataset und einen Bericht, mit dem die ungültigen Daten manuell korrigiert werden können.
Um die Produkt-ID und den Preis zu überprüfen, verwende ich reguläre Ausdrücke. Hier sind die zwei Hilfsfunktionen:
func verifyProductId (s string) bool stimmt überein, _: = regexp.MatchString ('^ PRD- \ d 4 - \ d 4 $', s) gibt übereinstimmend func verifyProductPrice (s string) bool ab, _: = regexp.MatchString ('^ \ d + \. \ d \ d $', s) zurückgegeben
Wenn die Daten bereinigt und alle ungültigen Datenzeilen gelöscht wurden, schreibt die folgende Funktion die bereinigten Daten in eine neue CSV-Datei mit dem Namen "clean.csv" und druckt sie auf den Bildschirm.
func writeCleanData (cleanData [] string) f, _: = os.Create ("clean.csv") w: = bufio.NewWriter (f) fmt.Println ("Clean data:") schiebt w.Flush () für auf _, Zeile: = Bereich cleanData fmt.Println (Zeile) mit.WriteString (Zeile) mit.WriteString ("\ n")
Das Main()
Funktion erledigt die meiste Arbeit. Es iteriert über das ursprüngliche Dataset, eliminiert redundante Leerzeichen, behebt, was möglich ist, verfolgt verworfene Datenzeilen, schreibt die bereinigten Daten in die Datei und meldet schließlich die abgelegten Zeilen.
func main () cleanData: = [] Zeichenfolge "Id, Name, Preis, Beschreibung" wurde fallen gelassen: = [] Zeichenfolge // Bereinigen Sie die Daten all_lines: = Zeichenfolgen.Split (Daten, "\ n") für _, Zeile: = Bereich all_lines Felder: = Zeichenfolgen.Split (Zeile, ",") if len (Felder)! = 4 continue // Entferne alle führenden und nachfolgenden Leerzeichen aus jedem Feld für i, f: = range Felder Felder [i] = Zeichenfolgen.TrimSpace (f) // Automatische Korrektur (keine Prüfung erforderlich) ID: = Zeichenfolgen.ToUpper (Felder [0]) if! verifyProductId (id) drop = anhängen (Zeile) ) continue Name: = Felder [1] // Produktnamen dürfen nicht leer sein, wenn Name == "" Drop = Anfügen (Ablegen, Zeile) Continue // Name auf 40 Zeichen (Runen) abschneiden, wenn len ([ ] rune (name))> 40 name = string ([] rune (name) [: 40]) price: = Felder [2] if! verifyProductPrice (price) drop = anhängen (drop, line) fortsetzen beschreibung : = Felder [3] // Beschreibung auf 500 Zeichen abschneiden (Runen), wenn len ([] Rune (Name))> 500 Name = String ([] Rune (Name) [: 500]) cleanLine: = Zeichenfolgen. Join ([] Zeichenfolge ID, Name, Preis, description, ",") cleanData = Anhängen (cleanData, cleanLine) writeCleanData (cleanData) // fmt.Println ("Gelöschte Zeilen:") für _, s: = Bereich wurde gelöscht fmt.Println (s)
Go verfügt über gut konzipierte Pakete für die Textverarbeitung. Im Gegensatz zu den meisten Sprachen ist das String-Objekt nur ein Teil von Bytes. Die gesamte String-Verarbeitungslogik befindet sich in separaten Paketen wie "strings" und "strconv"..
Im zweiten Teil des Tutorials haben wir viele Konzepte verwendet, um eine allgemeine Aufgabe zu lösen, einen CSV-formatierten Datensatz vor der Analyse zu bereinigen.