Ez a bevezető az Üzleti Intelligencia tárgy laborjához készült. A pandas könyvtárhoz kívánok egy rövid bevezetőt nyújtani. Az anyag folyamatosan bővül.
Angol nyelven kiváló erőforrásokat találhatsz:
A pandas egy adatkezelő függvénykönyvtár, amit a Data Scientistek nagyon szeretnek. Az adatokat táblázatos formában kezeli. A táblázatoknak van fejlécük és indexük. Heterogén adatokat tárolhatunk: szöveges, számadat, igazságérték, dátum stb. Az adatok típusa egy oszlopon belül sem kell, hogy azonos legyen.
A pandas remekül együttműködik a Python gépi tanuló könyvtárával (scikit-learn) és a legelterjedtebb vizualizációs könyvtárakkal (matplotlib, seaborn).
In [1]:
import pandas as pd # konvenció szerint pd aliast használunk
%matplotlib inline
import matplotlib
import numpy as np
# tegyük szebbé a grafikonokat
matplotlib.style.use('ggplot')
matplotlib.pyplot.rcParams['figure.figsize'] = (15, 3)
matplotlib.pyplot.rcParams['font.family'] = 'sans-serif'
In [2]:
grades = pd.DataFrame(
{
'subject': ['analízis 1', 'digitális technika 1',
'fizika 1', 'mikmak', 'programozás alapjai 1', 'szoftvertechonológia',
'bevezetés a számításelméletbe 1'],
'grade': [3, 4, 3, 2, 5, 1, 4],
'teacher': ['a', 'b', 'a', 'c', 'd', 'd', 'd'],
'semester': [1, 1, 2, 2, 1, 3, 1],
}
)
grades
Out[2]:
A DataFrame elejét a .head függvénnyel, a végét a .tail-lel nézhetjük meg. Ennek akkor van jelentősége, ha nagy táblázatokkal dolgozunk.
In [3]:
grades.head()
Out[3]:
Alapértelmezetten 5 sort ír ki, de megadhatjuk paraméterként pontosan hány sort szeretnénk látni.
In [4]:
grades.tail(2)
Out[4]:
Fontos megemlíteni, hogy minden művelet egy új DataFrame-mel tér vissza, beleértve a head
és a tail
függvényeket is, azonban ezek az új DataFrame-ek nem tényleges másolatok, hanem csak ún. slice-ok az eredetiből. A copy
függénnyel tudunk másolatot készíteni.
A táblázat első oszlopa kitüntetett, ez a DataFrame indexe, ezzel tudjuk azonosítani a sorokat. Ugyan nem követelmény, hogy unikus legyen, de praktikus unikusra választani. Egynél több oszlopot is használhatunk indexként (multiindex).
In [5]:
grades['teacher']
Out[5]:
Amennyiben az oszlop neve nem tartalmaz szóközöket, attribútumként is elérjük.
In [6]:
grades.teacher
Out[6]:
A kapott eredmény nem tűnik táblázatnak és valóban más típusú
In [7]:
type(grades.teacher)
Out[7]:
Amikor a dimenziók száma egyre csökken, Series
objektumot kapunk vissza.
Egynél több oszlop kiválasztásánál dupla zárójelet kell használni.
In [8]:
grades[['grade', 'teacher']]
Out[8]:
Valójában az []
operátor indexének típusa alapján dől el, hogy milyen típust kapunk vissza.
Egy oszlopból is készíthethünk DataFrame
-et Series
helyett, ha listaként kérdezzük le:
In [9]:
print(type(grades[['grade']]))
grades[['grade']]
Out[9]:
In [10]:
grades = grades.set_index('subject')
grades
Out[10]:
In [11]:
grades.loc['fizika 1'] # a loc után [] kell!
Out[11]:
Mivel egyetlen sort kértünk, megint Series
objektumot kapunk.
In [12]:
type(grades.loc['fizika 1'])
Out[12]:
A Series egy egydimenziós adatsor, gondolhatunk rá úgy, mint a DataFrame egy sorára.
In [13]:
grades.iloc[1:3] # utolsó index nincs benne, [1, 3)
Out[13]:
In [14]:
grades.iloc[:, [0, 2]]
Out[14]:
In [15]:
grades.iloc[:, 1:-1]
Out[15]:
In [16]:
grades.iloc[1:5, 1:2]
Out[16]:
Egy sort vagy oszlopot többször is lekérdezhetünk, ráadásul akármilyen sorrendben.
In [17]:
grades.iloc[[4, 1, 1], [2, 1, 2]]
Out[17]:
In [18]:
grades.loc['fizika 1', 'grade']
Out[18]:
In [19]:
grades.semester == 1
Out[19]:
Ekkor azokra a sorokra kapunk True-t, ahol igaz a feltétel. A feltételek kombinálhatóak, a zárójelezésre figyelni kell:
In [20]:
(grades.semester == 1) & (grades.teacher == 'a')
Out[20]:
Az igazságértékek sorozatával pedig szűrhetjük a DataFrame-eket:
In [21]:
grades[grades.semester==1]
Out[21]:
In [22]:
grades[(grades.semester == 1) & (grades.teacher == 'a')]
Out[22]:
In [23]:
grades[['grade', 'semester']] + 15
Out[23]:
In [24]:
grades.index.str.upper()
Out[24]:
Át is állítható:
In [25]:
grades.index = grades.index.str.upper()
grades
Out[25]:
Majd visszaállítható:
In [26]:
grades.index = grades.index.str.lower()
grades
Out[26]:
In [27]:
credits = pd.DataFrame(
{
'subject': ['analízis 1', 'fizika 1', 'programozás alapjai 2'],
'credit': [7, 5, 5]
}
)
credits
Out[27]:
In [28]:
d = grades.merge(credits, left_index=True, right_on='subject', how='outer')
d
Out[28]:
left_index
: a baloldali DataFrame (grades ebben az esetben) indexe mentén joinoljon.right_on
: a jobboldali DataFrame (credits) subject mezője mentén joinoljon.how
: inner/outer. Egyezik az SQL-es joinnal.left_index=True
-ra kell állítani.left_on=col1
vagy left_on=[col1, col2]
In [29]:
grades.merge(credits, left_index=True, right_on='subject', how='inner')
Out[29]:
Látható, hogy nem minden tárgyhoz sikerült megtalálni a kreditszámot, hiszen nem mindegyik szerepelt a credits táblában.
A pandas NaN (not a number) tölti fel a hiányzó mezőket. Szerencsére a legtöbb műveletnek megmondhatjuk, hogy hogyan bánjon a NaN-okkal. Meg is szabadulhatunk tőlük:
In [30]:
d = d.dropna()
d
Out[30]:
In [31]:
print(type(grades.max()))
grades.max()
Out[31]:
A max
függvény egy Series-zel tér vissza, ami minden oszlop maximumát tartalmazza. Sorokra is felthetjük ugyanezt a kérdést, bár erre az adatra nem sok értelme van:
In [32]:
grades.max(axis=1)
Out[32]:
Hol veszi fel a maximumát?
In [33]:
# grades.idxmax() # hibát kapunk, mert az egyik oszlop szöveges
grades[['grade', 'semester']].idxmax()
Out[33]:
Indexelhetünk is a visszakapott értékekkel, így a legmagasabb értékeket tartalmazó sorokat kapjuk meg.
In [34]:
grades.loc[grades[['grade', 'semester']].idxmax()]
Out[34]:
A számadatot tartalmazó oszlopok közül megkaptuk, hogy melyik sornál veszi fel a maximális értéket. Holtverseny esetén a legelső előfordulást adja vissza.
Az idxmax
függvény Series
-re hasonlóan működik, csak az eredmény egyetlen skalár érték:
In [35]:
grades.grade.idxmax()
Out[35]:
A groupby függvénnyel tetszőleges oszlop mentén csoportosíthatjuk a DataFrame-et.
In [36]:
g = credits.groupby('credit')
In [37]:
g.groups
Out[37]:
Nem csak oszlop szerint tudunk csoportosítani, hanem tetszőleges kifejezés szerint.
In [38]:
credits.credit % 3
Out[38]:
Eszerint groupby:
In [39]:
credits.groupby(credits.credit % 3)
Out[39]:
Csoportonként végezhetünk műveleteket:
In [40]:
grades.groupby("semester").mean()
Out[40]:
Egynél több oszlop szerint is csoportosíthatunk, ekkor az olszopok értékeinek összes kombinációja (direkt szorzat) szerepelni fog az indexben.
A size
függvénnyel az egyes csoportok elemeinek számát kérhetjük le.
In [41]:
grades.groupby(["semester", "teacher"]).size()
Out[41]:
Ismét Series
objektumot kaphatunk. A könnyebb olvashatóság kedvéért DataFrame
-é konvertálhatjuk:
In [42]:
grades.groupby(["semester", "teacher"]).size().to_frame()
Out[42]:
In [43]:
grades.sort_index()
Out[43]:
Illetve egy vagy több oszlop szerint rendezve:
In [44]:
grades.sort_values(['grade', 'semester'])
Out[44]:
Fordított sorrendben:
In [45]:
grades.sort_index(ascending=False)
Out[45]:
In [46]:
grades.plot(y='grade')
Out[46]:
Az oszlopdiagramnak több értelme lenne:
In [47]:
grades.plot(y='grade', kind='bar')
Out[47]:
Nem adtuk meg az x tengelyt, ekkor automatikusan a DataFrame indexét használja, ami ebben az esetben a tárgyakat jelenti.
Ábrázolhatnánk félév szerint is egy scatter ploton.
In [48]:
grades.plot(x='semester', y='grade', kind='scatter')
Out[48]:
Szinte minden művelet alapértelmezetten egy új DataFrame-mel tér vissza, nem módosítja a paramétereit. Ezt el kell tárolnunk, ha használni akarjuk.
Ha a többit is szeretnénk kiírni, használjuk a print függvényt.