Introducere
Organizarea, gestionarea si stocarea datelor reprezinta aspecte importante in proiectele orientate pe date, deoarece determina accesul mai usor la acestea si actualizarea lor intr-o maniera mult mai eficienta. Pentru lucrul cu date se utilizeaza structuri de date, care permit organizarea datelor astfel incat sa fie posibila stocarea si procesarea colectiilor de date.
Pandas este o biblioteca pentru analiza si manipularea datelor flexibila, rapida, puternica si usor de utilizat, construita pe baza NumPy, de la care adopta parti importante ale stilului de codare. In timp ce NumPy este construit pentru lucrul cu date numerice omogene de tip tablou, Pandas este conceput pentru lucrul cu date eterogene tabelare.
Pe langa structurile de date definite la nivelul limbajului de programare Python (liste, tupluri, multime, dictionare), in Pandas sunt introduse doua noi structuri de date: Series, pentru date unidimensionale, respectiv DataFrame, pentru date bidimensionale.
Structura | Dimensiune | Descriere |
---|---|---|
Series | 1 | tablou unidimensional etichetat in care pot fi stocate date de orice tip (intreg, sir de caractere, float, obiect, etc.) |
DataFrame | 2 | structura de date bidimensionala (tabelara), cu dimensiuni modificabile, cu axe etichetate (randuri si coloane) |
Pentru a putea folosi biblioteca Pandas la nivelul implementarilor este necesara includerea acesteia prin intermediul unei clauze import. Din acest punct de vedere exista inclusiv o conventie de includere a bibliotecii cu redenumirea acesteia sub numele pd, pentru o utilizare mai eficienta. Referirea definitiilor de la nivelul Pandas se va face, in acest caz, prin intermediul noului nume al modulului (pd.read_csv(), pd.Series(), pd.DataFrame()).
Pentru a permite lucrul cu structurile de date disponibile la nivelul Pandas vom utiliza un set de date (Netflix Movies and TV Shows) care are in vedere productiile oferite de catre serviciul de streaming Netflix. Setul de date este disponibil in cadrul platformei Kaggle, la adresa https://www.kaggle.com/shivamb/netflix-shows.
import numpy as np import pandas as pd df = pd.read_csv("data/netflix_titles.csv", sep=",", header=0) df.head()
Citim datele de la nivelul setului Netflix Movies and TV Shows intr-o structura de date de tip DataFrame, folosind functia pandas.read_csv(), si aruncam o privire la primele 5 inregistrari din aceasta.
Fiecare coloana de la nivelul structurii de date de tip DataFrame este o serie Pandas (Series). In acest caz, variabila s este asociata obiectului de tip Series care contine titlurile productiilor Netflix.
s = df['title'] s.head() # Output 0 Dick Johnson Is Dead 1 Blood & Water 2 Ganglands 3 Jailbirds New Orleans 4 Kota Factory Name: title, dtype: object
Tipuri de date in Pandas
Un tip de date defineste domeniul de valori posibile si operatiile permise asupra valorilor din domeniu. Limbajul Python pune la dispozitie urmatoarele tipuri de date: numerice (int, float, complex), logice (bool), secvente (siruri, liste, tupluri), tabele asociative (dictionary), multimi (set), clase, instante si exceptii.
Spre deosebire de Python, biblioteca NumPy accepta o varietate mult mai mare de tipuri de date. Tipurile de date primitive acceptate sunt strans legate de cele din limbajul de programare C. Deoarece Pandas utilizeza in cea mai mare parte tipuri de date NumPy, verificarea tipului unei coloane a unei structuri de tip DataFrame sau Series va returna tipul de date obiect din NumPy (dtype), instanta a clasei numpy.dtype.
Pandas | Python | NumPy | Descriere |
---|---|---|---|
obiect | string, date de tipuri diferite | np.object | siruri de caractere sau combinatii de date numerice si non-numerice |
int64 | int | np.int | valori intregi pe 64 biti |
float64 | float | np.float | valori reale pe 64 biti |
bool | bool | np.bool | valori de tipul True, False |
complex | complex | np.complex | valori de tip complex (a+bj) |
datetime64 | np.datetime64 | moment de timp | |
timedelta64 | np.timedelta64 | perioada de timp, de la nanosecunde la zile | |
category | lista finita de valori unice |
In cele ce urmeaza, utilizam atributul dtypes pentru a afisa coloanele de la nivelul structurii de date de tip DataFrame (df) impreuna cu tipul de date asociat acestora. Rezultatul obtinut prin intermediul atributului dtypes este un obiect de tip serie Pandas.
df.dtypes # Output show_id object type object title object director object cast object country object date_added object release_year int64 rating object duration object listed_in object description object dtype: object
Se poate observa faptul ca marea majoritate a coloanelor din setul de date incarcat (Netflix Movies and TV Shows) sunt de tip object. Aceasta inseamna ca la nivelul acestor coloane sunt stocate in special siruri de caractere, precum titlul filmului sau serialului (title), regizorul (director), distributia (cast), descrierea productiei (description). O singura coloana detine un alt tip de date, si anume coloana care pastreaza anul lansarii (release_year); aceasta coloana pastreaza valori de tip intreg.
df.title.dtype # Output dtype('O')
df['title'].dtype # Output dtype('O')
In mod similar, atributul dtype poate fi utilizat pentru a verifica tipul de date al unei anumite coloane de la nivelul structurii de date. Tipul de date marcat cu O are aici semnificatia de obiect, ceea ce in Pandas inseamna, in general, sir de caractere. Tipul de date object se utilizeaza si in situatia in care la nivelul unei coloane dintr-o structura de tip DataFrame sunt pastrate valori de tipuri de date diferite (de exemplu, combinatii de valori intregi, reale si/sau siruri de carectere).
Pentru a determina care este tipul de date al celor doua structuri create la punctul precedent este suficienta apelarea functiei type, functie definita in limbajul Python.
type(df) # Output pandas.core.frame.DataFrame
type(s) # Output pandas.core.series.Series
Structuri de date de tip Series
Un obiect de tip Series (serie Pandas) este o structura de date indexate, unidimensionala, in care pot fi stocate date de orice tip (valori intregi, siruri de caractere, valori reale, obiecte Python, etc.).
Un obiect de tip Series este alcatuit din doua componente de tip tablou aflate in legatura. Primul tablou pastreaza valorile elementelor, unde fiecare valoare este asociata unei etichete. Etichetele sunt disponibile la nivelul celui de-al doilea tablou, care mai este cunoscut sub numele de index.
s = df['title'] s.head() # Output 0 Dick Johnson Is Dead 1 Blood & Water 2 Ganglands 3 Jailbirds New Orleans 4 Kota Factory Name: title, dtype: object
Daca se doreste incarcarea directa a datelor din coloana title a setului de date Netflix Movies and TV Shows intr-o structura de tip Series, trebuie furnizate argumente suplimentare pentru functia pandas.read_csv(): usecols, cu valoarea title, si squeeze, cu valoarea True.
s = pd.read_csv("data/netflix_titles.csv", sep=",", usecols=['title'], squeeze=True) s.head() # Output 0 Dick Johnson Is Dead 1 Blood & Water 2 Ganglands 3 Jailbirds New Orleans 4 Kota Factory Name: title, dtype: object
Valoarea True precizata pentru argumentul squeeze stabileste conversia unei structuri de date de tip DataFrame cu o singura coloana la o structura de tip Series.
Accesarea individuala a celor doua componente ale unei serii Pandas se poate realiza prin intermediul atributelor index, respectiv values.
s.index # Output RangeIndex(start=0, stop=8807, step=1)
s.values # Output array(['Dick Johnson Is Dead', 'Blood & Water', 'Ganglands', ..., 'Zombieland', 'Zoom', 'Zubaan'], dtype=object)
Principala modalitate de creare a unei structuri de date de tip Series o reprezinta pandas.Series(). O sintaxa de baza a metodei este disponibila mai jos, unde pot fi observati si o serie de parametri definiti la nivelul ei:
• data: contine datele care vor fi stocate in structura de tip Series; daca datele sunt precizate ca si dictionar, ordinea argumentelor este pastrata;
• index: sunt permise valori ale indexului care nu sunt unice; in cazul in care nu este furnizat un index, se vor utiliza valori numerice pentru indexarea datelor (0, 1, 2, …, n); daca datele furnizate sunt de tip dictionar si nu este precizata o valoare pentru index (None), atunci cheile dictionarului sunt transmise indexului; daca indexul nu este None, seria rezultata este reindexata cu valorile indexului;
• dtype: tipul de date asociat seriei rezultat; daca nu este precizata o valoare pentru acest parametru, tipul de date va fi dedus din date;
• name: numele care trebuie dat seriei.
pandas.Series(data=None, index=None, dtype=None, name=None)
La crearea unei serii Pandas, pentru parametrul data poate fi furnizata o secventa Python, un tablou multidimensional NumPy (ndarray) sau chiar o valoare scalara. Implicit, fiecarui element al seriei ii va fi asociat un indice numeric, de la 0 la n-1, unde n este numarul de elemente de la nivelul seriei.
O serie Pandas este o structura asemanatoare unui tablou (unidimensional) NumPy (one-dimensional ndarray), dar care prezinta functionalitati suplimentare, precum indexarea valorilor folosind etichete. Putem crea o structura de tip Series numita studenti, plecand de la un tablou NumPy care stocheza ani de admitere in cadrul unor programe de studii, si precizand ca index o lista cu nume de persoane/studenti.
an_admitere = np.array([2003, 2016, 2018, 2020]) studenti = pd.Series(data = an_admitere, index = ['Casandra', 'Zaya', 'Reya', 'Maru']) studenti # Output Casandra 2003 Zaya 2016 Reya 2018 Maru 2020 dtype: int32
Urmatorul exemplu creaza o serie Pandas pe baza unei liste care pastreaza la nivelul elementelor informatii corespunzatoare unui tutor. Deoarece pentru aceste informatii nu sunt precizate, in prima faza, etichete, indexarea se realizeaza la nivelul structurii prin intermediul unor indici numerici. Se poate observa faptul ca valorile elementelor seriei sunt de tipuri diferite (siruri de caractere si valori intregi), motiv pentru care tipul de date al elementelor seriei este stabilit ca fiind object.
tutor = pd.Series( data = ['Marian Bucos', 'Sl.dr.ing.', 345, 'Programare pentru Ingineria Datelor', 'https://ti.etcti.upt.ro/cursuri/programare-pentru-ingineria-datelor']) tutor # Output 0 Marian Bucos 1 Sl.dr.ing. 2 345 3 Programare pentru Ingineria Datelor 4 https://ti.etcti.upt.ro/cursuri/programare-pen... dtype: object
De asemenea, exista posibilitatea asocierii de etichete elementelor seriei, la crearea acesteia, si utilizarea indexului pentru a selecta elemente specifice de la nivelul seriei.
tutor = pd.Series( data = ['Marian Bucos', 'Sl.dr.ing.', 345, 'Programare pentru Ingineria Datelor', 'https://ti.etcti.upt.ro/cursuri/programare-pentru-ingineria-datelor'], index = ['nume', 'grad', 'id curs', 'denumire curs', 'adresa curs']) tutor # Output nume Marian Bucos grad Sl.dr.ing. id curs 345 denumire curs Programare pentru Ingineria Datelor adresa curs https://ti.etcti.upt.ro/cursuri/programare-pen... dtype: object
Obiectele de tip Series accepta atat indexarea bazata pe numere intregi, cat si pe etichete, si ofera o serie de metode pentru efectuarea de operatii care au in vedere indexul. Daca se adopta indexarea de baza etichetelor, acestea nu trebuie sa fie unice, ci doar sa poate fi utilizate la nivelul unei functii hash().
tutor = pd.Series({ 'nume': 'Marian Bucos', 'grad': 'Sl.dr.ing.', 'id curs': 345, 'denumire curs': 'Programare pentru Ingineria Datelor', 'adresa curs': 'https://ti.etcti.upt.ro/cursuri/programare-pentru-ingineria-datelor'}) tutor # Output nume Marian Bucos grad Sl.dr.ing. id curs 345 denumire curs Programare pentru Ingineria Datelor adresa curs https://ti.etcti.upt.ro/cursuri/programare-pen... dtype: object
O serie Pandas este un tablou etichetat unidimensional, ale carui elemente pot fi accesate prin intermediul etichetelor indexului. Urmatoarele doua exemple precizeaza modalitati de accesare a unui singur element al seriei pe baza unei etichete din index, respectiv a mai multor elemente prin furnizarea unei liste de etichete de la nivelul indexului.
tutor['denumire curs'] # Output 'Programare pentru Ingineria Datelor'
tutor[['nume', 'denumire curs']] # Output nume Marian Bucos denumire curs Programare pentru Ingineria Datelor dtype: object
Seriile Pandas sunt structuri mutabile, ceea ce inseamna ca valorile elementelor pot fi actualizate dupa initializare.
tutor['grad'] = 'Prof.dr.ing.' tutor # Output nume Marian Bucos grad Prof.dr.ing. id curs 345 denumire curs Programare pentru Ingineria Datelor adresa curs https://ti.etcti.upt.ro/cursuri/programare-pen...
In mod similar secventelor Python si tablourilor NumPy, datele de la nivelul elementelor unei serii Pandas pot fi accesate prin intermediul indexului numeric asociat.
tutor[0] # Output 'Marian Bucos'
tutor[0:2] # Output nume Marian Bucos grad Prof.dr.ing. dtype: object
tutor[::-1] # Output birou DataLab B226 adresa curs https://ti.etcti.upt.ro/cursuri/programare-pen... denumire curs Programare pentru Ingineria Datelor id curs 345 grad Prof.dr.ing. nume Marian Bucos dtype: object
O parte din metodele de la nivelul structurilor de tip Series returneaza o alta structura de tip Series ca si rezultat. Acest lucru ofera posibilitatea apelului succesiv de metode, care mai este cunoscut si sub numele de inlantuire de metode (method chaining). Un exemplu de inlantuire a mai multor metode poate avea in vedere obtinerea unui top 5 al celor mai utilizate initiale pentru titlurile productiilor Netflix.
s.groupby(s.str[0:1])\ .count()\ .sort_values(ascending=False)\ .head() # Output title T 1525 S 719 M 637 B 576 A 566 Name: title, dtype: int64
Obiectele de tipul Series beneficiaza de o lista impresionanta de atribute (proprietati ale obiectelor). Cele mai importante atribute pentru structurile de date de tip Series sunt precizata in tabelul de mai jos.
Nume | Descriere | Exemplu | Rezultat |
---|---|---|---|
dtype | returneaza obiectul dtype corespunzator datelor | s.dtype | dtype(‘O’) |
hasnans | returneaza True daca sunt prezente valori lipsa la nivelul elementelor seriei | s.hasnans | False |
index | returneaza intervalul indexului seriei sau etichetele axei | s.index | RangeIndex(start=0, stop=8807, step=1) |
name | returneaza numele seriei | s.name | ‘title’ |
ndim | returneaza dimensiunea datelor, implicit 1 (Series) | s.ndim | 1 |
nbytes | returneaza numarul de octeti corespunzatori datelor de la nivelul seriei | s.nbyte | 70456 |
shape | returneaza un tuplu corespunzator formei datelor | s.shape | (8807,) |
size | retuneaza numarul de elemente de la nivelul structurii | s.size | 8807 |
values | returneaza seria ca si tablou ndarray (NumPy) | s.values | array([‘Dick Johnson Is Dead’, ‘Blood & Water’, ‘Ganglands’, …, ‘Zombieland’, ‘Zoom’, ‘Zubaan’], dtype=object) |
Structuri de date de tip DataFrame
Structurile de date de tip DataFrame sunt elemente de baza in Pandas. O structura de tip DataFrame este o structura bidimensionala, tabelara, compusa din randuri si coloane. Doua axe sunt disponibile la nivelul structurii, o axa verticala (index), respectiv o axa orizontala (coloane). Referirea celor doua axe se poate realiza prin intermediul valorilor intregi, conventie ce a fost preluata din NumPy. Astfel, pentru axa verticala se utilizeaza valoare 0 (axis=0), in timp ce pentru axa orizontala se utilizeaza valoarea 1 (axis=1).
Incarcam la nivelul unei structuri de date de tip DataFrame (df) continutul setului de date Netflix Movies and TV Shows, prin intermediul metodei pandas.read_csv(). In acest fel obtinem o structura de tip DataFrame care are in componenta 8 serii Pandas, cate una pentru fiecare coloana de la nivelul setului de date.
df = pd.read_csv("data/netflix_titles.csv", sep=",", header=0) print(df.head()) # Output show_id type title director \ 0 s1 Movie Dick Johnson Is Dead Kirsten Johnson 1 s2 TV Show Blood & Water NaN 2 s3 TV Show Ganglands Julien Leclercq 3 s4 TV Show Jailbirds New Orleans NaN 4 s5 TV Show Kota Factory NaN cast country \ 0 NaN United States 1 Ama Qamata, Khosi Ngema, Gail Mabalane, Thaban... South Africa 2 Sami Bouajila, Tracy Gotoas, Samuel Jouy, Nabi... NaN 3 NaN NaN 4 Mayur More, Jitendra Kumar, Ranjan Raj, Alam K... India date_added release_year rating duration \ 0 September 25, 2021 2020 PG-13 90 min 1 September 24, 2021 2021 TV-MA 2 Seasons 2 September 24, 2021 2021 TV-MA 1 Season 3 September 24, 2021 2021 TV-MA 1 Season 4 September 24, 2021 2021 TV-MA 2 Seasons listed_in \ 0 Documentaries 1 International TV Shows, TV Dramas, TV Mysteries 2 Crime TV Shows, International TV Shows, TV Act... 3 Docuseries, Reality TV 4 International TV Shows, Romantic TV Shows, TV ... description 0 As her father nears the end of his life, filmm... 1 After crossing paths at a party, a Cape Town t... 2 To protect his family from a powerful drug lor... 3 Feuds, flirtations and toilet talk go down amo... 4 In a city of coaching centers known to train I...
Fiecare coloana de la nivelul structurii beneficiaza de un nume sau eticheta. Astfel, pentru structura de date df sunt disponibile urmatoarele nume (etichete) pentru coloane: show_id, type, title, director, cast, country, date_added, release_year, rating, duration, listed_in, description.
df.columns.values # Output array(['show_id', 'type', 'title', 'director', 'cast', 'country', 'date_added', 'release_year', 'rating', 'duration', 'listed_in', 'description'], dtype=object)
Mai mult, in Pandas inclusiv randurile (inregistrarile) unei structuri de tip DataFrame detin un nume sau o eticheta. Implicit, aceasta eticheta este o valoare numerica corespunzatoare pozitiei inregistrarii la nivelul liniilor de date.
df.index.values # Output array([ 0, 1, 2, ..., 8804, 8805, 8806], dtype=int64)
Totusi, exista posibilitatea setarii unei coloane ca si index al structurii, ceea ce inseamna ca valorile sale vor fi utilizate ca si etichete ale inregistrarilor. De exemplu, putem seta coloana show_id in pozitia de index al structurii df, folosind metoda pandas.DataFrame.set_index(). Metoda stabileste indexul (etichetele randurilor) pentru structura de tip DataFrame utilizand una sau mai multe coloane. Noul index poate inlocui indexul precedent sau il poate extinde.
df.set_index('show_id').head()
df.set_index('show_id').index.values # Output array(['s1', 's2', 's3', ..., 's8805', 's8806', 's8807'], dtype=object)
Daca dorim revenirea la valorile indexului implicit, acest lucru poate fi realizat cu ajutorul functiei pandas.DataFrame.reset_index(). In absenta precizarii argumentului drop cu valoarea True, vechiul index este trecut la nivelul structurii, in postura de coloana.
df.reset_index().index.values # Output array([ 0, 1, 2, ..., 8804, 8805, 8806], dtype=int64)
Cea mai simpla modalitatea de vizualizare a informatiilor de baza cu privire la o structura de tip DataFrame o reprezinta metoda pandas.DataFrame.info(). Sunt disponibile in felul acesta urmatoarele informatii: numarul de coloane, etichetele coloanelor, tipurile de date ale coloanelor, numarul de instante din fiecare coloana care detin valori nenule, intervalul de valori corespunzatoare indexului.
df.info() # Output <class 'pandas.core.frame.DataFrame'> RangeIndex: 8807 entries, 0 to 8806 Data columns (total 12 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 show_id 8807 non-null object 1 type 8807 non-null object 2 title 8807 non-null object 3 director 6173 non-null object 4 cast 7982 non-null object 5 country 7976 non-null object 6 date_added 8797 non-null object 7 release_year 8807 non-null int64 8 rating 8803 non-null object 9 duration 8804 non-null object 10 listed_in 8807 non-null object 11 description 8807 non-null object dtypes: int64(1), object(11) memory usage: 825.8+ KB
In Pandas, crearea unei noi structuri de date de tip DataFrame poate fi realizata prin apelarea constructorului pandas.DataFrame(). O sintaxa de baza si o lista a parametrilor de la nivelul metodei sunt disponibile in cele ce urmeaza:
• data: contine datele care vor fi stocate in structura de tip DataFrame; daca datele sunt precizate ca si dictionar, ordinea coloanelor este cea de la inserare;
• index: indexul ce urmeaza a fi utilizat pentru structura rezultat; var fi utilizate etichetele implicite (valori intregi), daca datele de intrare nu precizeaza informatii de indexare sau nu este precizat un index;
• columns: etichetele coloanelor ce urmeaza a fi utilizate pentru structura rezultat, atunci cand datele nu prezinta etichete; daca sunt prezente etichete ale coloanelor la nivelul datelor, atunci se va realiza selectia coloanelor;
• dtype: tipul de date care trebuie impus; un singur astfel de tip da date poate fi precizat; daca nu este precizata o valoare pentru acest parametru, tipul de date va fi dedus din date.
pandas.DataFrame(data=None, index=None, columns=None, dtype=None)
Pentru crearea unui obiect de tip DataFrame, in constructorul clasei pot fi precizate urmatoarele tipuri de argumente:
• un dictionar care contine serii Pandas, tablouri, sau obiecte de tip lista;
• o structura iterabila;
• un tablou bidimensional NumPy (ndarray);
• o alta structura de tip DataFrame.
O prima modalitate de implementarea a unui obiect de tip DataFrame poate avea in vedere furnizarea unui dictionar, in care cheile reprezinta numele coloanelor, in timp ce valorile reprezinta continutul acestora. Valoarile de la nivelul elementelor dictionarului sunt liste de elemente de aceiasi dimensiune. Pentru implementarea indexului structurii este utilizata functia pandas.data_range(), pentru a crea un obiect de tip DatetimeIndex.
tutori = pd.DataFrame( data={'nume': ['Adrian Cosma', 'Mihai Popescu', 'Florin Vlad', 'Radu Marinescu'], 'grad': ['Sl', 'Sl', 'Prof', 'Prof'], 'birou': ['A236', 'B123', 'C314', 'A210'], 'varsta': [43, 35, 56, 62], 'departament': ['COM', 'MEO', 'EA', 'COM'] }, index=pd.date_range( start='1/10/2010', end='1/10/2014', periods=4, name='data_angajarii' ) ) tutori # Output nume grad birou varsta departament data_angajarii 2010-01-10 Adrian Cosma Sl A236 43 COM 2011-05-12 Mihai Popescu Sl B123 35 MEO 2012-09-10 Florin Vlad Prof C314 56 EA 2014-01-10 Radu Marinescu Prof A210 62 COM
Se obtine astfel o structura de tip DataFrame (tutori) care contine date corespunzatoare tutorilor de la nivelul unei facultati (nume, grad, birou, varsta, departament).
tutori.info() # Output <class 'pandas.core.frame.DataFrame'> DatetimeIndex: 4 entries, 2010-01-10 to 2014-01-10 Data columns (total 5 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 nume 4 non-null object 1 grad 4 non-null object 2 birou 4 non-null object 3 varsta 4 non-null int64 4 departament 4 non-null object dtypes: int64(1), object(4) memory usage: 192.0+ bytes
Crearea unui DataFrame poate avea ca si punct de plecare si o structura iterabila, precum o lista de orase, sau chiar o lista de dictionare care stocheza orase si judete.
orase = pd.DataFrame( ['Timisoara', 'Cluj-Napoca', 'Bucuresti', 'Iasi', 'Constanta', 'Brasov', 'Anina'], columns=['nume']) # Output nume 0 Timisoara 1 Cluj-Napoca 2 Bucuresti 3 Iasi 4 Constanta 5 Brasov 6 Anina
Daca in primul caz denumirea coloanei introduse la nivelul structurii de tip DataFrame se stabileste prin ultilizarea argumentului columns, in cel de-al doilea caz numele coloanelor sunt preluate din cheile dictionarelor.
orase = pd.DataFrame([ {'nume': 'Timisoara', 'judet': 'Timis'}, {'nume': 'Cluj-Napoca'}, {'nume': 'Bucuresti'}, {'nume': 'Iasi', 'judet': 'Iasi'}, {'nume': 'Constanta', 'judet': 'Constanta'}, {'nume': 'Brasov', 'judet': 'Brasov'}, {'nume': 'Anina', 'judet': 'Caras-Severin'} ]) # Output nume judet 0 Timisoara Timis 1 Cluj-Napoca NaN 2 Bucuresti NaN 3 Iasi Iasi 4 Constanta Constanta 5 Brasov Brasov 6 Anina Caras-Severin
In exemplul precedent, fiecare intrare din lista este un dictionar in care cheile reprezinta numele coloanelor, iar valorile sunt valori ale coloanei respective pentru un anumit index. Acest format permite inclusiv utilizarea unor structuri de date de tip dictionar de dimensiuni diferite. Pentru coloanele care nu au corespondent in dictionare este precizat in acest caz valoare NaN (Not a Number), valoare lipsa.
Pentru un ultim exemplu de creare a unui DataFrame consideram un dictionar care contine doua serii Pandas, title si director. Cele doua serii sunt introduse prin mecanisme diferite de preluare a unor coloane de la nivelul unui alt DataFrame, cel care a fost obtinut prin incarcarea setului de date Netflix Movies and TV Shows.
title = pd.read_csv("data/netflix_titles.csv", sep=",", usecols=['title'], squeeze=True) director = df['director'] # Output df2 = pd.DataFrame({ 'title': title, 'director': director, 'imdb': np.nan, 'views': np.random.randint(1, 1000000, size=len(df.index))}) title director imdb views 0 Dick Johnson Is Dead Kirsten Johnson NaN 660590 1 Blood & Water NaN NaN 259509 2 Ganglands Julien Leclercq NaN 950122 3 Jailbirds New Orleans NaN NaN 979987 4 Kota Factory NaN NaN 11755 ... ... ... ... ... 8802 Zodiac David Fincher NaN 523581 8803 Zombie Dumb NaN NaN 660600 8804 Zombieland Ruben Fleischer NaN 968184 8805 Zoom Peter Hewitt NaN 111915 8806 Zubaan Mozez Singh NaN 339572
In plus, noua structura, df2, introduce o coloana, imdb, pentru care nu sunt inca disponibile valori, si o alta coloana, views, in care sunt generate valori intregi aleatoare in intervalul 1..1000000.
df2.info() # Output <class 'pandas.core.frame.DataFrame'> RangeIndex: 8807 entries, 0 to 8806 Data columns (total 4 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 title 8807 non-null object 1 director 6173 non-null object 2 imdb 0 non-null float64 3 views 8807 non-null int32 dtypes: float64(1), int32(1), object(2) memory usage: 240.9+ KB
Fiecare din componentele de baza ale unei structuri de tip DataFrame (index, coloane, date) poate fi accesata independent de celelalte. Obiectele corespunzatoare acestor componente sunt disponibile prin intermediul atributelor index, column, respectiv values.
df2.index # Output RangeIndex(start=0, stop=8807, step=1)
df2.columns # Output Index(['title', 'director', 'imdb', 'views'], dtype='object')
df2.values # Output array([['Dick Johnson Is Dead', 'Kirsten Johnson', nan, 660590], ['Blood & Water', nan, nan, 259509], ['Ganglands', 'Julien Leclercq', nan, 950122], ..., ['Zombieland', 'Ruben Fleischer', nan, 968184], ['Zoom', 'Peter Hewitt', nan, 111915], ['Zubaan', 'Mozez Singh', nan, 339572]], dtype=object)
Dupa cum am putut vedea si mai sus, fiecare coloana de la nivelul unei structuri de tip DataFrame este o serie Pandas. Daca se doreste lucrul doar cu date de la nivelul unei singure coloane, atunci aceasta poate fi extrasa ca si serie Pandas.
title1 = df['title'] print(title1.head()) # Output 0 Dick Johnson Is Dead 1 Blood & Water 2 Ganglands 3 Jailbirds New Orleans 4 Kota Factory Name: title, dtype: object
type(title1) # Output pandas.core.series.Series
Extragerea uneia sau mai multor coloane poate fi realizata si prin precizarea in operatorul index a unei liste de nume de coloane valide din cadrul structurii. In astfel de cazuri, rezultatul operatiei va fi reprezentat de o structura de tip DataFrame.
title2 = df[['title']] print(title2.head()) # Output title 0 Dick Johnson Is Dead 1 Blood & Water 2 Ganglands 3 Jailbirds New Orleans 4 Kota Factory
type(title2) # Output pandas.core.frame.DataFrame
print(df[['title', 'director']]) # Output title director 0 Dick Johnson Is Dead Kirsten Johnson 1 Blood & Water NaN 2 Ganglands Julien Leclercq 3 Jailbirds New Orleans NaN 4 Kota Factory NaN ... ... ... 8802 Zodiac David Fincher 8803 Zombie Dumb NaN 8804 Zombieland Ruben Fleischer 8805 Zoom Peter Hewitt 8806 Zubaan Mozez Singh
Exista o multitudine de modalitati pentru a extrage elemente, randuri, coloane, subseturi de date de la nivelul unui DataFrame. Doua din cele mai eficiente astfel de mecanisme includ proprietatile pandas.DataFrame.loc si pandas.DataFrame.iloc din clasa DataFrame. Proprietatea pandas.DataFrame.loc acceseaza un grup de randuri si coloane pe baza etichetelor sau pe baza unui tablou boolean, in timp ce pandas.DataFrame.iloc permite selectarea unor subseturi din structura exclusiv pe baza pozitiei randurilor si coloanelor.
Sintaxele generala de utilizare a acestor doua proprietati pentru a extrage randuri si coloane din structuri de date de tip DataFrame sunt prezentate mai jos.
df.loc[eticheta_rand, eticheta_coloana] df.iloc[index_rand, index_coloana]
Termenii eticheta_rand si eticheta_coloana pot fi nume de coloane, liste cu nume de coloane, felii de nume de coloane; in plus, eticheta_rand poate fi si un tablou boolean. Termenii index_rand si index_coloana pot fi valori intregi, liste de valori intregi, sau felii de valori intregi.
tutori, \ type(tutori) # Output ( nume grad birou varsta departament data_angajarii 2010-01-10 Adrian Cosma Sl A236 43 COM 2011-05-12 Mihai Popescu Sl B123 35 MEO 2012-09-10 Florin Vlad Prof C314 56 EA 2014-01-10 Radu Marinescu Prof A210 62 COM, pandas.core.frame.DataFrame)
Pentru structura de date de tip DataFrame tutori, disponibila mai sus, implementam expresii folosind proprietatea pandas.DataFrame.loc, astfel incat sa obtinem datele care au in vedere urmatoarele situatii:
• numelel tutorului angajat in data de 2010-01-10; rezultatul acestei expresii este un sir de caractere;
tutori.loc['2010-01-10', 'nume'] # Output 'Adrian Cosma'
• numele tutorilor angajati in doua date explicit precizate la nivelul unei liste de valori; rezultatul acestei expresii este o serie Pandas;
tutori.loc[['2010-01-10','2012-09-10'], 'nume'] # Output data_angajarii 2010-01-10 Adrian Cosma 2012-09-10 Florin Vlad Name: nume, dtype: object
• numele tutorilor angajati intre doua date, una de inceput (2010-01-10) si o alta de final (2010-01-10); acest interval este precizat prin intermediul felierii; rezultatul acestei expresii este o serie Pandas;
tutori.loc['2010-01-10':'2012-09-10', 'nume'] # Output data_angajarii 2010-01-10 Adrian Cosma 2011-05-12 Mihai Popescu 2012-09-10 Florin Vlad Name: nume, dtype: object
• numele si birourile tutorilor angajati intre doua date, una de inceput (2010-01-10) si o alta de final (2010-01-10); acest interval este precizat prin intermediul felierii; coloanele pentru care sunt extrase valori sunt precizate ca si lista de nume de coloane; rezultatul acestei expresii este o structura de date de tip DataFrame;
tutori.loc['2010-01-10':'2012-09-10', ['nume', 'birou']] # Output nume birou data_angajarii 2010-01-10 Adrian Cosma A236 2011-05-12 Mihai Popescu B123 2012-09-10 Florin Vlad C314
• valorile corespunzatoare coloanelor nume, grad, birou pentru toate inregistrarile; coloanele sunt precizate prin intermediul felierii (coloana inceput: coloana final); pentru a obtine datele corespunzatoare tuturor inregistrarilor, operatorul de feliere apare fara precizarea unor etichete (:); rezultatul acestei expresii este o structura de date de tip DataFrame;
tutori.loc[:, 'nume':'birou'] # Output nume grad birou data_angajarii 2010-01-10 Adrian Cosma Sl A236 2011-05-12 Mihai Popescu Sl B123 2012-09-10 Florin Vlad Prof C314 2014-01-10 Radu Marinescu Prof A210
Toate implementarile de mai sus pot fi rescrise folosind proprietatea pandas.DataFrame.iloc si pozitiile coloanelor si randurilor, astfel:
• numelel tutorului angajat in data de 2010-01-10; eticheta 2010-01-10 apare in prima pozitie (0) la nivelul indexului, iar coloana nume are pozitia 0 in lista coloanelor; rezultatul acestei expresii este un sir de caractere;
tutori.iloc[0, 0] # Output 'Adrian Cosma'
• numele tutorilor angajati in doua date explicit precizate la nivelul unei liste de valori; cele doua date corespund inregistrarilor cu indicii 0, respectiv 2; coloana nume are pozitia 0 in lista coloanelor; rezultatul acestei expresii este o serie Pandas;
tutori.iloc[[0, 2], 0] # Output data_angajarii 2010-01-10 Adrian Cosma 2012-09-10 Florin Vlad Name: nume, dtype: object
• numele tutorilor angajati intre doua date, una de inceput (2010-01-10) si o alta de final (2010-01-10); acest interval este precizat prin intermediul felierii; cele doua date corespund inregistrarilor cu indicii 0, respectiv 2, prin urmare felierea se precizeaza prin 0:3; coloana nume are pozitia 0 in lista coloanelor; rezultatul acestei expresii este o serie Pandas;
tutori.iloc[0:3, 0] # Output data_angajarii 2010-01-10 Adrian Cosma 2011-05-12 Mihai Popescu 2012-09-10 Florin Vlad Name: nume, dtype: object
• numele si birourile tutorilor angajati intre doua date, una de inceput (2010-01-10) si o alta de final (2010-01-10); acest interval este precizat prin intermediul felierii; cele doua date corespund inregistrarilor cu indicii 0, respectiv 2, prin urmare felierea se precizeaza prin 0:3; coloanele pentru care sunt extrase valori sunt precizate ca si lista a pozitiilor coloanelor, adica [0, 2]; rezultatul acestei expresii este o structura de date de tip DataFrame;
tutori.iloc[0:3, [0, 2]] # Output nume birou data_angajarii 2010-01-10 Adrian Cosma A236 2011-05-12 Mihai Popescu B123 2012-09-10 Florin Vlad C314
• valorile corespunzatoare coloanelor nume, grad, birou pentru toate inregistrarile; coloanele sunt precizate prin intermediul felierii (pozitie coloana inceput: pozitie coloana final), adica 0:3; pentru a obtine datele corespunzatoare tuturor inregistrarilor, operatorul de feliere apare fara precizarea unor etichete (:); rezultatul acestei expresii este o structura de date de tip DataFrame;
tutori.iloc[:, 0:3] # Output nume grad birou data_angajarii 2010-01-10 Adrian Cosma Sl A236 2011-05-12 Mihai Popescu Sl B123 2012-09-10 Florin Vlad Prof C314 2014-01-10 Radu Marinescu Prof A210
Consideram structura de date de tip DataFrame orase, introdusa mai sus, structura care contine orase si judete din Romania. Pentru unele orase (exemplu, Cluj-Napoca, Bucuresti) nu este precizata la crearea structurii si valoarea pentru judet.
orase, \ orase.shape # Output ( nume judet 0 Timisoara Timis 1 Cluj-Napoca NaN 2 Bucuresti NaN 3 Iasi Iasi 4 Constanta Constanta 5 Brasov Brasov 6 Anina Caras-Severin, (7, 2))
Dorim adaugarea a doua noi coloane la structura de tip DataFrame; o prima coloana, populatie, precizeaza valori pentru toate inregistrarile prin intermediul unei liste de valori de tip intreg. Cea de-a doua coloana, suprafata, nu introduce pentru moment valori pentru nici o inregistrare.
orase['populatie'] = [329003, 324267, 2121794, 376180, 313931, 289646, 9172] orase['suprafata'] = np.nan orase, \ orase.shape # Output ( nume judet populatie suprafata 0 Timisoara Timis 329003 NaN 1 Cluj-Napoca NaN 324267 NaN 2 Bucuresti NaN 2121794 NaN 3 Iasi Iasi 376180 NaN 4 Constanta Constanta 313931 NaN 5 Brasov Brasov 289646 NaN 6 Anina Caras-Severin 9172 NaN, (7, 4))
Pentru adaugarea unei noi inregistrari la finalul structurii orase, putem utiliza metoda pandas.DataFrame.append(); inregistrarea noua este precizata la nivelul primului argument al metodei sub forma unui dictionar.
orase = orase.append( {'nume': 'Ploiesti', 'populatie': 228550, 'judet': 'Prahova'}, ignore_index=True) orase, \ orase.shape # Output ( nume judet populatie suprafata 0 Timisoara Timis 329003 NaN 1 Cluj-Napoca NaN 324267 NaN 2 Bucuresti NaN 2121794 NaN 3 Iasi Iasi 376180 NaN 4 Constanta Constanta 313931 NaN 5 Brasov Brasov 289646 NaN 6 Anina Caras-Severin 9172 NaN 7 Ploiesti Prahova 228550 NaN, (8, 4))
Si obiectele de tip DatFrame beneficiaza de o lista consistenta de atribute (proprietati ale obiectelor). Cele mai importante atribute pentru structurile de date de tip DataFrame sunt precizata in tabelul de mai jos.
Nume | Descriere | Exemplu | Rezultat |
---|---|---|---|
dtypes | returneaza obiectelel dtype corespunzator coloanelor structurii | tutori.dtyes | nume object grad object birou object varsta int64 departament object dtype: object |
index | returneaza intervalul indexului structurii sau etichetele axei | df.index | RangeIndex(start=0, stop=8807, step=1) |
columns | returneaza numele coloanelor structurii | df.columns | Index([‘show_id’, ‘type’, ‘title’, ‘director’, ‘cast’, ‘country’, ‘date_added’, ‘release_year’, ‘rating’, ‘duration’, ‘listed_in’, ‘description’], dtype=’object’) |
ndim | returneaza o valoare intreaga care corespunde numarului de axe | df.ndim | 2 |
axes | returneaza o lista care reprezinta axele structurii | df.axes | [RangeIndex(start=0, stop=8807, step=1), Index([‘show_id’, ‘type’, ‘title’, ‘director’, ‘cast’, ‘country’, ‘date_added’, ‘release_year’, ‘rating’, ‘duration’, ‘listed_in’, ‘description’], dtype=’object’)] |
shape | returneaza un tuplu corespunzator dimensionalitatii structurii | df.shape | (8807, 12) |
size | retuneaza numarul de elemente de la nivelul structurii | df.size | 105684 |
values | returneaza structura ca si tablou ndarray (NumPy) | tutori.values | array([[‘Adrian Cosma’, ‘Sl’, ‘A236’, 43, ‘COM’], [‘Mihai Popescu’, ‘Sl’, ‘B123’, 35, ‘MEO’], [‘Florin Vlad’, ‘Prof’, ‘C314’, 56, ‘EA’], [‘Radu Marinescu’, ‘Prof’, ‘A210’, 62, ‘COM’]], dtype=object) |