Să schimbăm exemplul cu o familie diferită și un DataFrame puțin mai mare. Fișierul „simpsons.csv” este reprodus mai jos. Observați ceva ciudat la el?
name,species,age,gender,fave,IQ,hair,salary Homer,human,36,M,beer,74,,52000 Marge,human,34,F,helping others,120,stacked tall, Bart,human,10,M,skateboard,90,buzz, Lisa,human,8,F,saxophone,200,curly, Maggie,human,1,F,pacifier,100,curly, SLH,dog,4,M,,,shaggy,
Ceea ce vreau să spun este poziționarea unor virgule. Cititorul atent va vedea o „virgulă dublă” în rândul lui Homer. Chiar și un cititor cu ochi mai puțin atenți va observa mai multe virgule la rând în rândul 42 al lui SLH. Și aproape fiecare rând (cu excepția celui cu Homer) se termină cu o virgulă, arătând pur și simplu dezordonat.
Această punctuație ciudată implică existența unor valori lipsă, ceea ce înseamnă exact ceea ce pare: pur și simplu nu există date pentru anumite coloane din anumite rânduri. Homer nu are o valoare „de păr”, nimeni în afară de Homer nu are o valoare „salary”, iar lui SLH îi lipsesc tot felul de lucruri.
Când citim asta într-un Pandas DataFrame, în stilul:
simpsons = pd.read_csv("simpsons.csv").set_index('name')
rezultatul arată astfel:
▐ species age gender fave IQ hair salary ▐ name ▐ Homer human 36 M beer 74.0 NaN 52000.0 ▐ Marge human 34 F helping others 120.0 stacked tall NaN ▐ Bart human 10 M skateboard 90.0 buzz NaN ▐ Lisa human 8 F saxophone 200.0 curly NaN ▐ Maggie human 1 F pacifier 100.0 curly NaN ▐ SLH dog 4 M NaN NaN shaggy NaN
Valorile lipsă apar ca NaN, aceeași valoare pe care ți-o amintești de la p. 114. Expresia „nu este un număr” are sens pentru cazul salary, deși cred că este puțin ciudată pentru hair la Homer (nu este un număr? se presupune că părul este un număr?…) În orice caz, ne putem aștepta ca acesta să fie cazul pentru multe seturi de date din lumea reală.
„Lipsește” poate însemna, de fapt, câteva lucruri subtil diferite. Poate înseamnă că valoarea pentru acel obiect de studiu a fost colectată, dar pierdută. Poate înseamnă că nu a fost colectată deloc. Poate înseamnă că acea variabilă nu are sens pentru acel obiect, ca în cazul IQ-ului unui câine. În cele din urmă, dacă vrem să folosim celelalte valori din acel rând, va trebui să ne înțelegem ce înseamnă valorile lipsă. Deocamdată, haideți să învățăm doar câteva modalități brute de a le trata.
O metodă (uneori) la îndemână este .dropna(). Dacă o apelați, va returna o copie modificată a DataFrame în care orice rând cu un NaN este eliminat. Totuși, acest lucru se dovedește a fi exagerat în cazul lui Simpson:
print(simpsons.dropna())
▐ Empty DataFrame ▐ Columns: [species, age, gender, fave, IQ, hair, salary] ▐ Index: []
Cu alte cuvinte, nu a mai rămas nimic. (Fiecare rând avea cel puțin un NaN, deci nimic nu a supraviețuit.)
Am putea transmite un argument opțional către .dropna() numit „how” și să-l setăm egal cu „all”: în acest caz, sunt eliminate doar rândurile cu toate valorile NaN. Uneori, acest lucru este „subevaluat”, ca în exemplul nostru Simpson: la urma urmei, niciunul dintre rânduri nu este în întregime NaN, așa că apelarea la .dropna(how=”all”) ar lăsa totul intact.
O altă opțiune este metoda .fillna(), care primește un argument „valoare implicită”: orice valoare NaN este înlocuită cu valoarea implicită din copia modificată returnată. Să încercăm cu șirul „none” ca valoare implicită:
print(simpsons.fillna("none"))
▐ species age gender fave IQ hair salary ▐ name ▐ Homer human 36 M beer 74.0 none 52000.0 ▐ Marge human 34 F helping others 120.0 stacked tall none ▐ Bart human 10 M skateboard 90.0 buzz none ▐ Lisa human 8 F saxophone 200.0 curly none ▐ Maggie human 1 F pacifier 100.0 curly none ▐ SLH dog 4 M none none shaggy none
Acest lucru este posibil util, dar în acest caz nu este o potrivire perfectă, deoarece coloane diferite necesită valori implicite diferite. Coloanele fave și hair ar putea avea „none” (indicând lipsa unui lucru preferat și, respectiv, lipsa părului), dar am putea dori ca salary implicit să fie 0. Modul de a realiza acest lucru este de a schimba coloanele individuale ale DataFrame. Iată:
simpsons['salary'] = simpsons['salary'].fillna(0)
simpsons['IQ'] = simpsons['IQ'].fillna(100)
simpsons['hair'] = simpsons['hair'].fillna("none")
print(simpsons)
▐ species age gender fave IQ hair salary ▐ name ▐ Homer human 36 M beer 74.0 none 52000.0 ▐ Marge human 34 F helping others 120.0 stacked tall 0.00 ▐ Bart human 10 M skateboard 90.0 buzz 0.00 ▐ Lisa human 8 F saxophone 200.0 curly 0.00 ▐ Maggie human 1 F pacifier 100.0 curly 0.00 ▐ SLH dog 4 M NaN 100.0 shaggy 0.00
Aici am presupus că IQ-ul implicit, pentru cineva care nu a făcut testul, este 100 (media). Am lăsat NaN așa cum este în fave, deoarece mi s-a părut potrivit.
Apropo, codul ăla este de obicei, mai mult decât pare la început. Când executăm o linie de genul:
simpsons['salary'] = simpsons['salary'].fillna(0)
de fapt, spunem „vă rugăm să înlocuiți coloana salary din DataFrame Simpsons cu o coloană nouă. Această nouă coloană ar trebui să fie – așteptați puțin – coloana salary existentă, dar cu zerouri care înlocuiesc NaN.”
Sursa: Stephen Davies, The Crystal Ball – Instruction Manual, Vol. 1: Introduction to Data Science, v. 1.1. Copyright © 2021 Stephen Davies. Licența CC BY-SA 4.0. Traducere și adaptare: Nicolae Sfetcu. © 2026 MultiMedia Publishing, Introducere în Știința Datelor, Volumul 1
Descoperă mai multe la MultiMedia
Abonează-te ca să primești ultimele articole prin email.



Lasă un răspuns