Aceasta este partea a doua din două dintr-o serie despre curățarea datelor utilizând Go. În prima parte, am abordat facilitățile de bază ale programului Go și lucrul cu fișierele CSV. În acest tutorial, ne vom arunca cu capul în curățarea reală a datelor.
Vom începe prin înțelegerea problemei datelor dezordonate și a unei strategii, iar apoi vom examina verificarea câmpurilor individuale, stabilirea datelor acolo unde este posibil și decizia ce trebuie făcută cu privire la valorile lipsă.
O strategie de curățare a datelor ar trebui să dicteze ce trebuie făcut atunci când întâmpinăm date nevalide, dezordonate, parțiale sau lipsite de date. De asemenea, ar trebui să determine nivelul de raportare necesar în procesul de curățare.
Datele la care ne concentrăm aici sunt date tabulare, în care fiecare rând este independent. Nu există ierarhii imbricate sau conexiuni între diferite rânduri de date. Multe seturi de date din lumea reală au această proprietate frumoasă.
Cea mai simplă abordare pentru tratarea datelor nevalide este eliminarea acestora. Dacă orice câmp lipsește sau conține date nevalide, trebuie doar să scăpați de întregul rând. Acest lucru este foarte ușor și, uneori, este bine să faceți acest lucru. Dacă câmpul problematic este critic și nu aveți nicio modalitate de ao recupera, atunci tot ce puteți face este să renunțați la întreaga înregistrare.
Cea mai bună soluție este fixarea câmpului rău. În unele cazuri, este ușor să detectați problema și să o remediați. În setul de date privind observarea OZN, câmpul de stat poate fi unul dintre cele 52 de state din SUA.
Dacă valoarea trebuie să fie toate majuscule și unele rânduri conțin litere mici, le puteți face doar majuscule.
Raportarea rândurilor nevalide, fie abandonate, fie fixe, este importantă. Organizația poate decide să permită oamenilor să încerce să corecteze datele pierdute. Poate fi necesar să rulați date fixe de către QA pentru a vă asigura că remedierile automate nu au introdus date nevalide.
Este necesară colectarea statisticilor privind procesul de curățare pentru a evalua calitatea datelor sursă și, uneori, pentru a determina dacă datele curățate sunt chiar valoroase pentru procesare. Statisticile pot include numărul de rânduri abandonate și fixe și numărul de câmpuri rău și lipsă pentru fiecare coloană.
Până în prezent am descris o abordare de pre-procesare pentru curățarea datelor. Cu toate acestea, este posibilă efectuarea curățării în timpul procesării. Fiecare rând este verificat chiar înainte de a fi procesat. Acest lucru este uneori util, dacă nu există nici un punct în pre-procesare, deoarece nimeni nu poate repara datele rău înainte de timp pentru analiză ulterioară sau dacă procesarea este sensibilă la timp.
În acest scenariu, scopul principal al curățării este de a vă asigura că rândurile de date proaste nu rupe întreaga conductă de procesare și pot fi sărite sau fixate după cum este necesar.
Cum faceți verificarea câmpurilor? Trebuie să știți exact ce tip de date ar trebui să existe și, uneori, ce valori. Iată câteva exemple.
Câmpurile numerice sunt foarte frecvente în seturile de date. Dincolo de tipul de număr (întreg, real, complex), unele domenii sunt mai specializate. De exemplu, un câmp de preț poate necesita exact două puncte zecimale și să fie pozitiv. Iată o funcție care verifică dacă un șir reprezintă un preț:
func validate_price (s string) bool parts: = siruri de caractere.Split (s, ".") daca len (parts)! = 2 return false dollars, err: = strconv.Atoi (parts [0] = nil return false în cazul în care ați făcut bani < 0 return false cents, err := strconv.Atoi(parts[1]) if err != nil return false if cents < 0 || cents > 99 return false return true
Uneori trebuie să mergi deasupra și dincolo. Dacă trebuie să verificați dacă o adresă URL este validă, atunci există două abordări:
Dacă vă pasă numai dacă adresa URL este bine formată, atunci funcționează prima abordare. Dar dacă doriți să vă asigurați că adresa URL indică într-adevăr o destinație reală, trebuie să utilizați a doua abordare. Deoarece a doua abordare este o supersetare a primei abordări, hai să o folosim:
func validate_url (șir url) bool _, err: = http.Head (url) retur err == nil
Dacă valorile trebuie să respecte un format personalizat, puteți, de obicei, fie să le potriviți folosind funcții simple, cum ar fi Despică()
sau în cazuri mai complexe folosesc expresii regulate. De exemplu, dacă setul de date conține numere de securitate socială (sper că nu) în format XXX-XX-XXXX
atunci puteți să vă împărțiți cu "-" și asigurați-vă că există trei jetoane în care prima este de trei cifre lungi, al doilea este lung de două cifre, iar al treilea este de patru cifre. Dar este mai concis să folosiți un regex ca ^ \ D 3 - \ d 2 - \ d 4 $
.
Fixarea valorilor invalide nu este un lucru banal. Dacă metoda de fixare este incorectă, puteți ajunge la date corupte. Ar trebui să aveți în vedere cu atenție importanța câmpului, a gamei de valori posibile valide și cât de siguri sunteți că puteți corecta automat orice valoare nevalidă.
Aceasta este o rezolvare destul de sigur. Dacă un câmp de text ar trebui să fie toate majuscule, îl puteți rezolva fără a risca prea mult, deoarece caracterele care erau inițial mici nu reprezintă o informație importantă. Nu este nevoie să scrieți cod special deoarece pachetul de șiruri are a Toupper ()
funcţie. Există, de asemenea Pentru a reduce()
și chiar ToTitle ()
și ToTitleSpecific ()
funcții pentru capitalizarea corectă a textului.
O altă soluție comună ușoară este eliminarea spațiilor libere de conducere și de sfârșit. Veți fi surprins de câte persoane adaugă spații sau noi linii la introducerea datelor. Pachetul de șiruri are o selecție de TrimXXX ()
funcții care pot avea grijă de cele mai multe situații:
În unele cazuri, este OK să eliminați caracterele nevalide. Vă recomandăm să faceți acest lucru doar pentru câmpurile non-critice și opționale. De exemplu, este posibil să aveți un câmp de descriere sau de note care conține text liber și doriți să vă asigurați că nu conține anumite simboluri, cum ar fi citate sau ghilimele duble. Iată cum se face:
funcția șterge (s) string var b bytes.Buffer pentru _, r: = interval (uri) if r! = '' '&& r! =' \ "b.WriteRune (r) return b. String () func principal () original: = "citate" și "citate dublă". " clean: = remove_quotes (original) fmt.Println (original) fmt.Println (curat) Ieșire: "citate" și "citate dublă"..
Valorile numerice sunt deseori ușor de rezolvat. Dacă aveți nevoie de o precizie de două cifre zecimale, puteți trunchia sau rotunji cifre suplimentare. În același mod, este ușor să convertiți numerele cu numere în virgulă mobilă.
Uneori există o serie de valori valide și puteți aduce numere prea mari sau prea mici pentru a se potrivi domeniului. Următoarea funcție are un șir și o gamă de numere întregi și returnează un șir care reprezintă un întreg în interval. Valorile prea mari devin valoarea maximă, iar valoarea prea mică devine prea mică.
func fit_into_range (s șir, min int, max int) șir n, _: = strconv.Atoi (i) dacă n < min n = min else if n > max n = max altceva return s retur strconv.Itoa (n) func main () fmt.Println (fit_into_range ("15", 10, 20)) fmt.Println 10, 20)) fmt.Println (fit_into_range ("55", 10, 20)) Ieșire: 15 10 20
Adresele URL adesea pot fi reparate în siguranță prin încercarea unor scheme diferite ("http" sau "https") sau prin adăugarea sau abandonarea subdomeniilor "www". Combinarea opțiunilor cu încercarea de a prelua candidații vă poate da încredere că reparația a fost corectă.
Valorile lipsă sunt foarte frecvente atunci când ingerați date din lumea reală. Dacă este necesară valoarea lipsă, există două modalități principale de a se descurca (fără a respinge complet rândul) - utilizați valorile implicite sau recuperați valoarea dintr-o sursă alternativă.
Valorile implicite sunt utile deoarece codul de procesare nu trebuie să verifice dacă există o valoare sau nu. Codul de curățare a datelor asigură existența întotdeauna a unei valori. În multe cazuri, setarea implicită este atât de comună încât este de asemenea un ajutor pentru introducerea datelor, unde nu trebuie să introduceți din nou aceeași valoare implicită.
Această abordare este puțin mai implicată. Ideea este de a consulta o altă sursă de date care are informațiile solicitate. De exemplu, dacă aveți un e-mail de utilizator, dar lipsește numele și prenumele, puteți consulta baza de date cu utilizatorul și extrageți numele utilizatorului. Aceasta salvează codul de procesare de la accesarea DB sau chiar de a fi conștient de această dependență.
Să curățăm un mic set de produse. Câmpurile sunt:
Numele coloanei | Descrierea coloanei |
---|---|
id-ul | PRD-XXXX-XXXX (unde X este o cifră) |
Nume | până la 40 de caractere |
Preț | câmpul numeric cu precizie fixă (două zecimale) |
Descriere | până la 500 de caractere (opțional) |
Iată setul de date într-o formă lizibilă (spațiul alb va fi tăiat în timpul curățării):
const data = 'ID, Denumire, Pret, Descriere PRD-1234-0000, Airzooka, 9.99, Trage aer la oameni PRD-1234-0017, Onesie roz, 34.55, PR-1234-666, Oh oh, 18.18. PRD-1234-7777, Oh oh 2, prețul lipsă prd-1234-8888, PostIt !, 13.13, Fixable: litere mici id '
Primele două produse sunt valide. Cel de-al treilea produs, "PRD-1234-666", lipsește o cifră în id-ul său. Următorul produs, "PRD-1234-7777", nu are un preț. Ultimul produs, "prd-1234-8888", are un id de produs nevalid, dar poate fi fixat în siguranță (faceți majuscule).
Următorul cod va curăța datele, va repara ceea ce poate fi rezolvat, va renunța la rândurile care nu pot fi reparate și va produce un set de date curat și un raport care poate fi utilizat pentru corectarea manuală a datelor nevalide.
Pentru a verifica id-ul produsului și prețul, voi folosi expresii regulate. Iată cele două funcții de ajutor:
func verify_ProductId (s string) bool matched, _: = regexp.MatchString ('^ PRD- \ d 4 _: = regexp.MatchString ('^ \ d + \. \ d \ d $', s) returnat corespunzător
Odată ce datele sunt curățate și toate rândurile nevalide de date au fost abandonate, următoarea funcție va scrie datele curate într-un nou fișier CSV numit "clean.csv" și îl va imprima pe ecran.
Funcțiunea WriteCleanData (cleanData [] șirul) f, _: = os.Create ("clean.csv") w: = bufio.NewWriter (fmt.Println) _, line: = range cleanData fmt.Println (linie) w.WriteString (linie) w.WriteString ("\ n")
principal()
funcția face cea mai mare parte a muncii. Se iterează peste setul de date original, elimină spațiul alb redundant, stabilește ce poate, ține evidența rândurilor de date abandonate, scrie datele curate în fișier și în cele din urmă raportează despre liniile căzute.
()) string Id, Nume, Pret, Descriere " dropped: = [] string _, line: = range all_lines fields: = strings.Split (line, ",") if len (fields)! = 4 continue // Stripați toate spațiile de conducere și de sfârșit din fiecare câmp pentru i, f: Câmpuri fields [i] = strings.TrimSpace (f) // Fixare automată (nu trebuie verificată) id: = strings.ToUpper (câmpuri [0]) if! verifyProductId (id) dropped = ) continue nume: = câmpuri [1] // nume de produse nu pot fi goale dacă numele == "" dropped = append (dropped, line) ] rune (nume))> 40 name = string ([] rune (nume) [: 40]) descriere: = fields [2] if description : = câmpuri [3] // trunchiul descrierii la 500 de caractere (rune) dacă len ([] rune (nume))> 500 name = string; Alăturați ([] șir id, nume, preț, descriere, ",") cleanData = append (cleanData, cleanLine) writeCleanData (cleanData) // Raportați fmt.Println pentru ", s: = dropped range fmt.Println (s)
Go are pachete bine concepute pentru procesarea textului. Spre deosebire de cele mai multe limbi, obiectul șir este de fapt doar o felie de octeți. Toate logica de procesare a șirului este în pachete separate, cum ar fi "șiruri" și "strconv".
În cea de-a doua parte a tutorialului, am folosit o mulțime de concepte pentru a realiza o sarcină comună reală de curățare a unui set de date formatat CSV înainte de analiză.