Egyszerű műveletek, maszkolás

Kezdjük a szokásos importokkal:

In [1]:
%pylab inline
Populating the interactive namespace from numpy and matplotlib
In [2]:
import pandas as pd

DataFrame létrehozása

Beolvasni már tudunk DataFrame-et, mi van, ha saját magunk akarjuk létrehozni?

Legkézenfekvőbb oszlopokból egy szótár segítségével létrehozni, melyben a különböző kulcsokhoz egy-egy lista, illetve tömb tartozik:

In [3]:
df=pd.DataFrame({'random1':random.random(4),
                 'nulla':[0 for i in range(4)]})
df
Out[3]:
nulla random1
0 0 0.201720
1 0 0.934053
2 0 0.240146
3 0 0.222493

Indexet is megadhatunk kézzel.

In [4]:
df=pd.DataFrame({'random1':random.random(4),
                 'nulla':[0 for i in range(4)]},
                 index=['a','b','c','d'])
df
Out[4]:
nulla random1
a 0 0.918215
b 0 0.230913
c 0 0.161259
d 0 0.982594

Ha sorokból akarjuk létrehozni, akkor a sorok listájából hozhatjuk létre. Az oszlopok neveit a columns argumentumban adhatjuk meg.

In [5]:
sor1=random.random(4) 
sor2=[0 for i in range(4)]

df=pd.DataFrame([sor1,sor2],columns=['a','b','c','d'],
                index=['random','nulla'])
df
Out[5]:
a b c d
random 0.381452 0.794531 0.95669 0.301953
nulla 0.000000 0.000000 0.00000 0.000000

2 dimenziós numpy tömbből is létrehozhatjuk.

In [6]:
df=pd.DataFrame(random.random((2,4)),columns=['a','b','c','d'],
               index=['random','random2'])
df
Out[6]:
a b c d
random 0.501972 0.743951 0.311027 0.465086
random2 0.558628 0.424588 0.227572 0.964177

Adatok elérése

In [7]:
df=pd.read_csv("data/kisnevsor.csv",index_col=0)

A pandas a DataFrame-ben tárolt értékeket elsősorban a fejléccel és a sorok neveivel teszi elérhetővé.

Már láttuk, ha egy oszlop nevét stringként szögletes zárójelekben írjuk a DataFrame neve mögé, visszakapjuk az oszlopot.

In [8]:
df["Eszter"]
Out[8]:
Név
Bálint    2
Csenge    4
István    5
Zita      3
Károly    4
Name: Eszter, dtype: int64

Ha több oszlopot is vissza szeretnénk kapni, akkor azokat egy stringeket tartalmazó listában írjuk a DataFrame mögötti szögletes zárójelbe.

In [9]:
df[["Eszter","Nem","Kor"]]
Out[9]:
Eszter Nem Kor
Név
Bálint 2 fiú 20
Csenge 4 lány 22
István 5 fiú 19
Zita 3 lány 20
Károly 4 fiú 21

Láttuk, hogy egy sort a loc konstrukcióval kérhetünk le név szerint.

In [10]:
df.loc['Bálint']
Out[10]:
Eszter        2
Orsi          .
Nem         fiú
Kor          20
Dátum     12:31
Name: Bálint, dtype: object

Több sort az oszlopokhoz hasonlóan kérhetünk le.

In [11]:
df.loc[['Bálint','Csenge']]
Out[11]:
Eszter Orsi Nem Kor Dátum
Név
Bálint 2 . fiú 20 12:31
Csenge 4 4 lány 22 13:20

Aki szeretné ugyanúgy számokkal indexelni a DataFrame-et, mint egy array-t, annak erre az iloc biztosít lehetőséget. Nézzük meg az előző eléréseket iloc-kal!

In [12]:
df.iloc[:,0] # az első (0.) oszlop
Out[12]:
Név
Bálint    2
Csenge    4
István    5
Zita      3
Károly    4
Name: Eszter, dtype: int64
In [13]:
df.iloc[0,0]  # az első sor első eleme
Out[13]:
2

A numpy tömböknél megismert minden indexelést tudunk itt használni.

In [14]:
df.iloc[::-1,3:5] 
Out[14]:
Kor Dátum
Név
Károly 21 14:55
Zita 20 14:50
István 19 12:35
Csenge 22 13:20
Bálint 20 12:31

Sőt, a DataFrame belsejét átalakíthatjuk numpy array-jé, és alkalmazhatjuk rá a korábban tanult módszereket :-)

In [15]:
df.values
Out[15]:
array([[2, '.', 'fiú', 20, '12:31'],
       [4, '4', 'lány', 22, '13:20'],
       [5, '4', 'fiú', 19, '12:35'],
       [3, '5', 'lány', 20, '14:50'],
       [4, '.', 'fiú', 21, '14:55']], dtype=object)

Név szerint lekérdezni az oszlopokat sokkal biztonságosabb, mint ha az oszlop sorszáma szerint kérdeznénk le (mint egy numpy tömbben) hiszen nem keverhetjük össze az indexeket!

Új sor/oszlop hozzáadása, törlés

Ha új sort szeretnénk hozzáadni a táblázathoz, akkor a .loc["Új_sor_indexe"] változónak egy, az oszlopok számával megegyező hosszúságú listát kell odaadnunk.

In [16]:
df.loc["Dávid"]=[5,5,"fiú",20,'12:32']
df
Out[16]:
Eszter Orsi Nem Kor Dátum
Név
Bálint 2 . fiú 20 12:31
Csenge 4 4 lány 22 13:20
István 5 4 fiú 19 12:35
Zita 3 5 lány 20 14:50
Károly 4 . fiú 21 14:55
Dávid 5 5 fiú 20 12:32

Ha új oszlopot, akkor hasonlóan járunk el, de nem szükséges a loc, mert az a sorokat indexeli.

In [17]:
df["Emelt"]=[0,0,1,1,0,0]
df
Out[17]:
Eszter Orsi Nem Kor Dátum Emelt
Név
Bálint 2 . fiú 20 12:31 0
Csenge 4 4 lány 22 13:20 0
István 5 4 fiú 19 12:35 1
Zita 3 5 lány 20 14:50 1
Károly 4 . fiú 21 14:55 0
Dávid 5 5 fiú 20 12:32 0

Ha sort szeretnénk törölni, a drop függvénnyel tehetjük meg. Itt használhatjuk az inplace opciót, ami mindig arra vonatkozik, hogy a függvényünk egy új DataFrame-mel tér-e vissza, vagy felülírja a már meglévőt.

In [18]:
df.drop("Bálint",inplace=True)
df
Out[18]:
Eszter Orsi Nem Kor Dátum Emelt
Név
Csenge 4 4 lány 22 13:20 0
István 5 4 fiú 19 12:35 1
Zita 3 5 lány 20 14:50 1
Károly 4 . fiú 21 14:55 0
Dávid 5 5 fiú 20 12:32 0

Ha oszlopot szeretnénk törölni, akkor ugyanígy tehetjük meg, csak más tengely mentén kell törölni. Figyeljük meg, hogy itt az inplace nélkül egy DataFrame-et kapunk visszatérési értékként.

In [19]:
df.drop("Emelt",axis=1)
Out[19]:
Eszter Orsi Nem Kor Dátum
Név
Csenge 4 4 lány 22 13:20
István 5 4 fiú 19 12:35
Zita 3 5 lány 20 14:50
Károly 4 . fiú 21 14:55
Dávid 5 5 fiú 20 12:32

Az oszlopnevek és a sornevek elérése

Írassuk ki a táblázatunk oszlopainak a nevét!

In [20]:
df.columns
Out[20]:
Index(['Eszter', 'Orsi', 'Nem', 'Kor', 'Dátum', 'Emelt'], dtype='object')

Írassuk ki a táblázatunk sorainak a nevét!

In [21]:
df.index
Out[21]:
Index(['Csenge', 'István', 'Zita', 'Károly', 'Dávid'], dtype='object', name='Név')

Szükség lehet rá, hogy a fenti listákat tényleg Python-féle list-ként kapjuk vissza.

In [22]:
df.columns.tolist()
Out[22]:
['Eszter', 'Orsi', 'Nem', 'Kor', 'Dátum', 'Emelt']
In [23]:
list(df.columns)
Out[23]:
['Eszter', 'Orsi', 'Nem', 'Kor', 'Dátum', 'Emelt']

Egyszerű műveletek

A teljes DataFrame-mel csinálhatunk műveteleket, ha azok értelmesek.

In [24]:
sub_df=df[["Eszter","Kor"]]
sub_df+1
Out[24]:
Eszter Kor
Név
Csenge 5 23
István 6 20
Zita 4 21
Károly 5 22
Dávid 6 21

Az oszlopokkal műveleteket végezhetünk, mint a numpy tömbökkel.

In [25]:
(df['Eszter']+2)/3
Out[25]:
Név
Csenge    2.000000
István    2.333333
Zita      1.666667
Károly    2.000000
Dávid     2.333333
Name: Eszter, dtype: float64
In [26]:
df['Eszter']/=2
df
Out[26]:
Eszter Orsi Nem Kor Dátum Emelt
Név
Csenge 2.0 4 lány 22 13:20 0
István 2.5 4 fiú 19 12:35 1
Zita 1.5 5 lány 20 14:50 1
Károly 2.0 . fiú 21 14:55 0
Dávid 2.5 5 fiú 20 12:32 0
In [27]:
df['Eszter']*df['Kor']
Out[27]:
Név
Csenge    44.0
István    47.5
Zita      30.0
Károly    42.0
Dávid     50.0
dtype: float64

A stringekkel is!

In [28]:
df['Nem']+'ka'
Out[28]:
Név
Csenge    lányka
István     fiúka
Zita      lányka
Károly     fiúka
Dávid      fiúka
Name: Nem, dtype: object

A sorokkal is.

In [29]:
sub_df.loc["Dávid"]+3
Out[29]:
Eszter     8
Kor       23
Name: Dávid, dtype: int64

Beépített aggregáló függvények

A DataFrame-re is könnyű néhány beépített függvény segítségével különböző aggregált értékeket számolni.

Például álljon itt oszloponként a számok összege:

In [30]:
df.sum()
Out[30]:
Eszter                         10.5
Nem               lányfiúlányfiúfiú
Kor                             102
Dátum     13:2012:3514:5014:5512:32
Emelt                             2
dtype: object

Mit tegyünk, ha ezt soronként szeretnénk visszakapni? Változtassuk meg az összegzés "tengelyét" (axis)! Az előző eset ugyanis az alapértelmezett axis=0 volt, ami oszloponként végzi a műveletet. Csak a jegyeket tartalmazó oszlopokat összegezzük.

In [31]:
df[["Eszter","Orsi"]].sum(axis=1)
Out[31]:
Név
Csenge    2.0
István    2.5
Zita      1.5
Károly    2.0
Dávid     2.5
dtype: float64

Számoltassuk meg, hány elem van az oszlopokban, illetve a sorokban!

In [32]:
df.count()
Out[32]:
Eszter    5
Orsi      5
Nem       5
Kor       5
Dátum     5
Emelt     5
dtype: int64
In [33]:
df.count(axis=1)
Out[33]:
Név
Csenge    6
István    6
Zita      6
Károly    6
Dávid     6
dtype: int64

Ezt persze az array-hez hasonlóan is megtehettük volna:

In [34]:
df.shape
Out[34]:
(5, 6)

További ötletek beépített függvényekre: mean, median, min, max, std.

Bool indexelés

Nagyon gyakran előfordul, hogy a táblázatunkból csak bizonyos feltételeknek megfelelő sorokat szeretnénk látni. Ha a táblázat sorainak számával megegyező hosszú igaz/hamis sorozatot adunk meg a DataFrame mögötti szögletes zárójelben, akkor csak az igaz elemeket fogjuk visszakapni visszatérési értékként.

Először nézzük meg, mi történik, ha megkérdezzük, hogy egy oszlop egyenlő-e egy értékkel:

In [35]:
df
Out[35]:
Eszter Orsi Nem Kor Dátum Emelt
Név
Csenge 2.0 4 lány 22 13:20 0
István 2.5 4 fiú 19 12:35 1
Zita 1.5 5 lány 20 14:50 1
Károly 2.0 . fiú 21 14:55 0
Dávid 2.5 5 fiú 20 12:32 0
In [36]:
df["Nem"]=="lány"
Out[36]:
Név
Csenge     True
István    False
Zita       True
Károly    False
Dávid     False
Name: Nem, dtype: bool

Láttuk, hogy minden sorhoz kaptunk egy igaz/hamis értéket. Most a fenti kifejezést beírjuk a []-be:

In [37]:
df[df["Nem"]=="lány"]
Out[37]:
Eszter Orsi Nem Kor Dátum Emelt
Név
Csenge 2.0 4 lány 22 13:20 0
Zita 1.5 5 lány 20 14:50 1

De más feltételt is megadhatunk, például hogy kinek adott Eszter 2-esnél jobb jegyet.

In [38]:
df[df["Eszter"]>2]
Out[38]:
Eszter Orsi Nem Kor Dátum Emelt
Név
István 2.5 4 fiú 19 12:35 1
Dávid 2.5 5 fiú 20 12:32 0

Két feltételt összefűzhetünk egymáshoz, ilyenkor a & és a | operátorokat használjuk and és or helyett, mert azok nem tudnak két sorozatot elemenként összehasonlítani. A feltételeket zárójelbe kell tenni, különben hibát kapunk.

Ezek alapján az, akinek Eszter kettesnél jobbat adott, és idősebb 19 évesnél:

In [39]:
df[(df["Eszter"]>2) & (df["Kor"]>19)]
Out[39]:
Eszter Orsi Nem Kor Dátum Emelt
Név
Dávid 2.5 5 fiú 20 12:32 0

Sorba rendezés

Szükségünk lehet arra, hogy a táblázatunkat sorba rendezzük valamelyik oszlop szerint. Ilyenkor a sort_values(by="oszlop_neve") függvényt használjuk, melynek megadhatjuk, hogy növekvő (ascending=True), vagy csökkenő (ascending=False) sorrendben szeretnénk-e a rendezést.

A függvény visszatérési értéke a rendezett táblázat.

In [40]:
df.sort_values(by="Kor",ascending=False)
Out[40]:
Eszter Orsi Nem Kor Dátum Emelt
Név
Csenge 2.0 4 lány 22 13:20 0
Károly 2.0 . fiú 21 14:55 0
Zita 1.5 5 lány 20 14:50 1
Dávid 2.5 5 fiú 20 12:32 0
István 2.5 4 fiú 19 12:35 1

Sorba rendezhetünk több oszlop szerint is.

In [41]:
df.sort_values(by=["Orsi","Kor"],ascending=True)
Out[41]:
Eszter Orsi Nem Kor Dátum Emelt
Név
Dávid 2.5 5 fiú 20 12:32 0
Károly 2.0 . fiú 21 14:55 0
István 2.5 4 fiú 19 12:35 1
Csenge 2.0 4 lány 22 13:20 0
Zita 1.5 5 lány 20 14:50 1

Ha azt szeretnénk, hogy az eredeti DataFrame-ben rendezve tárolódjanak el a sorok, be kell kapcsolnunk az inplace=True paramétert, ami felülírja a DataFrame-et a rendezés után.

In [42]:
df.sort_values(by="Kor",ascending=False,inplace=True)

Persze, ezt elérhettük volna szokásos értékadással is.

In [43]:
df=df.sort_values(by="Kor",ascending=False)

Ha a DataFrame indexe szerint szeretnénk sorba rendezni, akkor a sort_index() függvény segít (itt is választhatjuk, hogy helyben szeretnénk-e a rendezést az inplace=True segítségével):

In [44]:
df.sort_index(inplace=True)
In [45]:
df
Out[45]:
Eszter Orsi Nem Kor Dátum Emelt
Név
Csenge 2.0 4 lány 22 13:20 0
Dávid 2.5 5 fiú 20 12:32 0
István 2.5 4 fiú 19 12:35 1
Károly 2.0 . fiú 21 14:55 0
Zita 1.5 5 lány 20 14:50 1