Kihagyás

11. gyakorlat

A gyakorlat anyaga

Numpy

A Numpy a Numerical Python rövidítése, és az egyik legelterjedtebb modul, ha tudományos számításokról van szó. Az alap Python listák helyett egy sokkal jobban optimalizált tömb objektumot biztosít (ndarray néven). Különbségek az ndarray és a sima python list között:

  • A listákkal ellentétben a NumPy tömböknek fix mérete van, ha megváltoztatjuk egy ndarray méretét a létrejötte után, akkor az eredeti törlődik és egy új tömb jön létre.
  • Egy ndarray-ben csak ugyan olyan adattípusú elemek lehetnek.

NumPy tömbök létrehozása

  • Python listából
1
2
3
4
import numpy as np

list = [1,2,3]
array = np.array(list)
  • Numpy függvényekkel
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import numpy as np

#teli 0 mátrix
arr1 = np.zeros((2,3)) # [[0,0,0],
                       # [0,0,0]]
                       # paramétere egy int vagy tuple, ami a méretét adja meg

#teli 1 mátrix
arr2 = np.ones((1,2)) # [[1,1]]
                      # paramétere egy int vagy tuple, ami a méretét adja meg
#teli n mátrix
arr3 = np.full((2,2), 5) # [[5,5],
                         # [5,5]]
                         # paraméterei egy int vagy tuple, ami a méretét adja meg és egy valós szám, ami a tömb elemeit

#python range-hez hasonlóan
arr3 = np.arange(10)    # [0,1,2,3,4,5,6,7,8,9]
arr4 = np.arange(2,5,2) # [2,4]
                        # paraméterei az intervallum eleje (opcionális), vége és a lépésköz

#adott invervallumon n db szám létrehozása egyenletes közzel
arr5 = np.linspace(0,4,6) # [0,0.8,1.6,2.4,3.2,4]
                          # paraméterei az intervallum eleje, vége és hogy hány számot szeretnénk

ndarray adattagok

  • ndim - a tömb dimenzióinak száma
  • shape - a tömb konkrét dimenziói, ez egy ndim hosszú tuple
  • size - a tömb elemeinek száma
  • dtype - a tömb elemeinek adattípusa
  • itemsize - a tömb egy elemének mérete byte-ban
1
2
3
4
5
6
7
8
import numpy as np

matrix = np.array([[0,2],[3,4],[5,6]])
print(matrix.ndim)                      # 2
print(matrix.shape)                     # (3,2)
print(matrix.size)                      # 6
print(matrix.dtype)                     # int32
print(matrix.itemsize)                  # 4

Indexelés

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import numpy as np

matrix = [[1,2,3],[4,5,6]]

#indexelés pythonban
masodiksor_elso = matrix[1][0] # 4

#numpy indexelés
matrix = np.array(matrix)     # hogy lista helyett ndarray legyen
masodiksor_elso = matrix[1,0] # 4
                              # a sima matrix[1][0] is ugyan úgy működik

#index tömbbel
array = np.arange(10,1,-1)    # [10,9,8,7,6,5,4,3,2]
index = np.array([3,4,2,3])   # 
x = array[index]              # [7,6,8,7]

Műveletek

Sima python listák elemeinek összeadása a legalapabb módszerrel
1
2
3
4
5
x = [1,2,3]
y = [4,5,6]
z = []
for i in range(len(x)):
    z.append(x[i] + y[i])
NumPy változat
1
2
3
4
5
import numpy as np

x = np.array([1,2,3])
y = np.array([4,5,6])
z = x + y

Ugyan így az összes többi alapműveletre is

További NumPy műveletek
1
2
3
4
5
6
7
8
9
import numpy as np

x = np.array([1,2,3])
sum = np.sum(x)         # lista vagy mátrix elemeinek összege

matrix1 = np.array([[1,2],[3,4]])
matrix2 = np.array([[5,6],[7,8]])

matrixszorzat = np.dot(matrix1,matrix2) # mátrixszorzás (nem elemenként)

Reshape

A tömb méretének befolyásolására szolgál, hozzáadhatunk vagy elvehetünk dimenziókat vele, ameddig a dimenziók szorzata egyenlő az elemek számával.

1
2
3
4
5
6
7
8
9
import numpy as np

arr = np.arange(12)             # [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11]
matrix = arr.reshape(4,3)       # [[ 0,  1,  2],
                                # [ 3,  4,  5],
                                # [ 6,  7,  8],
                                # [ 9, 10, 11]]
#vissza vektorrá
arr2 = matrix.reshape(-1)       # [ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11]

Stack

Mátrixok egymás mellé és egymásra illesztése

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import numpy as np

arr1 = np.array([[1,2],[3,4]])
arr2 = np.array([[5,6],[7,8]])

arr3 = np.hstack((arr1,arr2))       # [[1, 2, 5, 6],
                                    # [3, 4, 7, 8]]

arr4 = np.vstack((arr1,arr2))       # [[1, 2],
                                    # [3, 4],
                                    # [5, 6],
                                    # [7, 8]]

Alternatívák

Tensorflow és PyTorch

Mindkét modult főleg gépi tanulásnál használják, bár a szimplább, itt bemutatott dolgokra is képesek. Ugyan úgy megtalálható bennük egy n dimenziós mátrix reprezentására használható adattípus, csak ndarray helyett tensor néven. A főbb különbség a performancián jön csak ki, ugyan is míg a NumPy csak CPU-n tud számolni, addig az említett két modulban szerepel GPU támogatás is, ami bizonyos esetekben gyorsabb. A kisebb mátrixműveletek elvégézésénél még a NumPy nyer sebességben, még GPU-n se verik meg, viszont ez főleg annak tudható be, hogy a CPU sokkal gyorsabban eléri az adatot, mint a GPU. Ahogy egyre jobban elenyészővé válik az adat elérésének ideje (a tényleges számítás idejének növekedésével), úgy ezek a modulok a GPU-n számolva jobban teljesítenek.

Pandas

Adatelemzéshez elengedhetetlen python modul, főleg táblázatokból és adatbázisokból kinyert adatok feldolgozására használják, amihez egy a python-os dictionary-hez hasonló, de jobban optimalizált adatszerkezetet biztosít.

Series

A modul saját objektuma, ami egy táblázat egy oszlopára hasonlít, egydimenziós tömbként reprezentál bármilyen típusú adatot.

1
2
3
4
5
6
7
8
9
import pandas as pd

array = [1,3,5]
series = pd.Series(array)

print(series)               # 0    1
                            # 1    3
                            # 2    5
                            # dtype: int64

Minden sor címkézve is van, ugyan úgy mint egy dictionary-ben. Alapértelmezetten ez a címke a sorszámot jelöli.

1
2
3
4
5
6
7
8
9
import pandas as pd

array = [1,3,5]
series = pd.Series(array,index = ["elso","masodik","harmadik"])

print(series)               # elso        1
                            # masodik     3
                            # harmadik    5
                            # dtype: int64

Python dictionary átalakítása:

1
2
3
4
5
6
7
8
import pandas as pd

dictionary = {"elso": 1, "masodik" : 3, "harmadik": 5}
series = pd.Series(dictionary)
print(series)               # elso        1
                            # masodik     3
                            # harmadik    5
                            # dtype: int64

DataFrame

A modul saját objektuma, ami egy 2D mátrixra vagy egy teljes táblázatra hasonlít.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import pandas as pd

data = {
    "nem" : ["ferfi","no","no","ferfi"],
    "kor" : [23,32,42,19]
}
df = pd.DataFrame(data)
print(df)                   # Alapértelmezetten csak az első és utolsó 5 sort írja ki,
                            # ha az egész kell print(df.to_string())
                            #      nem  kor
                            # 0  ferfi   23
                            # 1     no   32
                            # 2     no   42
                            # 3  ferfi   19

Sorok lekérdezése

1
2
3
4
5
6
7
print(df.loc[0])            # nem    ferfi
                            # kor       23
                            # Name: 0, dtype: object

print(df.loc[[0,2]])        #      nem  kor
                            # 0  ferfi   23
                            # 2     no   42

Oszlop lekérdezése

1
2
3
4
5
print(df["nem"])            # 0    ferfi
                            # 1       no
                            # 2       no
                            # 3    ferfi
                            # Name: nem, dtype: object

Adatok beolvasása

A modul rengeteg fájlformátumból tud beolvasni (https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html), köztük csv, json, excel és sql támogatás is van. Ilyenkor egyből DataFrame objektumként kapjuk meg a tartalmat.

1
2
3
4
5
import pandas as pd

df1 = pd.read_csv("data.csv")
df2 = pd.read_json("data.json")
df3 = pd.read_excel("data.xls","Sheet1")

Az adat megjelenítése

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import pandas as pd

data = {
    "nem" : ["ferfi","no","no","ferfi"],
    "kor" : [23,32,42,19]
}
df = pd.DataFrame(data)

print(df.head(2))           # Az első 2 sor megjelenítése
print(df.tail(2))           # Az utolsó 2 sor megjelenítése

print(df.info())            # Alap információk a DataFrame-ről
                            # <class 'pandas.core.frame.DataFrame'>
                            # RangeIndex: 4 entries, 0 to 3         <-- sorok száma
                            # Data columns (total 2 columns):       <-- oszlopok száma
                            # #   Column  Non-Null Count  dtype     <-- az oszlopok neve és adattípusa
                            # ---  ------  --------------  -----
                            # 0   nem     4 non-null      object
                            # 1   kor     4 non-null      int64
                            # dtypes: int64(1), object(1)
                            # memory usage: 192.0+ bytes
                            # None

print(df.mean())            # A sorok átlaga oszloponként
print(df.count())           # A nem üres sorok száma oszloponként
print(df.max())             # A legnagyobb érték oszloponként (szövegnél ábécé sorrendben utolsó)
print(df.min())             # A legkisebb érték oszloponként (szövegnél ábécé sorrendben első)
print(df.median())          # A sorok mediánja oszloponként

DataFrame-ek összekötése

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import pandas as pd

data1 = {
    "nem" : ["ferfi","no","no","ferfi"],
    "kor" : [23,32,42,19]
}
data2 = {
    "nem" : ["ferfi","ferfi"],
    "kor" : [30,65]
}
data3 = {
    "hazas" : [True,False]
}
df1 = pd.DataFrame(data1)
df2 = pd.DataFrame(data2)
df3 = pd.DataFrame(data3)

df1.append(df2)         # További sorok beszúrása

df3 = pd.concat([df1,df3],axis=1)       # df1 oszlopai mellé kerülnek df2 oszlopai
                                        #      nem  kor  hazas
                                        # 0  ferfi   23   True
                                        # 1     no   32  False
                                        # 2     no   42    NaN
                                        # 3  ferfi   19    NaN

Hiányos adatok pótlása/eltávolítása

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
print(pd.isnull(df3))           # egy True/False táblázatot ad vissza, ahol a True értékek jelölik a hiányzó cellákat
                                #      nem    kor  hazas
                                # 0  False  False  False
                                # 1  False  False  False
                                # 2  False  False   True
                                # 3  False  False   True

pd.notnull(df3)                 # ugyan ez csak fordítva

print(df3.dropna())             # törli azokat a sorokat, amiknél van NaN érték valamelyik oszlopban
                                # alapértelmezetten nem változtatja meg a változó tartalmát,
                                # de ha az inplace paraméterét igazra állítjuk, akkor már igen
                                # a "subset" opcionális paraméterével megadható az is, hogy melyik
                                # oszlopkat nézze (ha nincs megadva, mindet)

                                #      nem  kor  hazas
                                # 0  ferfi   23   True
                                # 1     no   32  False

print(df3.dropna(axis=1))       # törli azokat az oszlopokat, amiknél van NaN érték valamelyik sorban
                                # inplace paraméter itt is ugyan úgy működik

                                #      nem  kor
                                # 0  ferfi   23
                                # 1     no   32
                                # 2     no   42
                                # 3  ferfi   19

Ha nem akarjuk elveszteni azokat a sorokat vagy oszlopokat, amikben van üres érték, fel is tölthetjük egységesen ezeket a cellákat.

1
2
3
4
5
6
7
8
df3["hazas"].fillna(True,inplace = True)    # A NaN értékek feltöltése a "hazas" oszlopban úgy,
                                            # hogy a változtatások mentődnek a df3 változóba

print(df3)                  #      nem  kor  hazas
                            # 0  ferfi   23   True
                            # 1     no   32  False
                            # 2     no   42   True
                            # 3  ferfi   19   True

Adatok módosítása

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
df3["hazas"].replace(True,"hazas")          # A "hazas" oszlopban a True értékek módosítása a "hazas" szóra
df3["hazas"].replace(False,"nem hazas")
#vagy egyszerre, úgy hogy változzon df3 értéke
df3["hazas"].replace([True,False],["hazas","nem hazas"], inplace= True)
print(df3)          #     nem  kor      hazas
                    # 0  ferfi   23      hazas
                    # 1     no   32  nem hazas
                    # 2     no   42      hazas
                    # 3  ferfi   19      hazas

df3.rename(columns ={"hazas" : "hazas-e"}, inplace = True)      # Oszlop átnevezése

Szűrés, rendezés, groupby

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
df3[df3["kor"] > 30]        # boolean szűrés, akár több kifejezést is összekapcsolhatunk & és | jelekkel
df3.sort_values("kor")      # értékek rendezése a megadott oszlop szerint, alapértelemzetten növekvő sorrendben
                            #      nem  kor      hazas
                            # 3  ferfi   19      hazas
                            # 0  ferfi   23      hazas
                            # 1     no   32  nem hazas
                            # 2     no   42      hazas

df3.sort_values(["kor","hazas-e"], ascending = [False,True])    # rendezés több oszlop alapján csökkenő és növekvő sorrendben
group = df3.groupby("hazas-e")          # groupby egy oszlop szerint
group.describe()                        #             kor
                                        #           count  mean        std   min   25%   50%   75%   max
                                        # hazas-e
                                        # hazas       3.0  28.0  12.288206  19.0  21.0  23.0  32.5  42.0
                                        # nem hazas   1.0  32.0        NaN  32.0  32.0  32.0  32.0  32.0

Mentés

1
df3.to_csv("valami.csv")

Alternatívák

Dask

Bár az API sokkal szegényesebb, alternatíva lehet olyan esetekben, amikor a feldolgozandó adat nem fér bele a memóriába. A model különlegessége az, hogy semmit nem számol addig, ameddig meg nem kérjük rá külön a compute() függvényével. Így pl. két nagy adatbázis összefűzésénél nem próbálja meg egyből elmenteni az eredményt, ha utána amúgy is csak egy része érdekelne minket. Teljesítmény szempontjából rosszabb mint a pandas, viszont ha nem fér bele a memóriába az adat, akkor a pandas nem tud vele mit kezdeni.

PySpark

Főleg olyan esetekben használják, amikor több gépre osztanak le valamilyen műveletet. Hasonló teljesítménye van mint az előző modulnak, ha belefér a memóriába az adat, akkor még mindig a pandas nyer.

Vaex

Bár kevesebb funkciót támogat mint a pandas, az alap (pl. összefésülés, rendezés) feladatokat hasonló sebességgel vagy gyorsabban végzi el.

Matplotlib

Matplotlib

A NumPy modul egy kiegészítése, amivel grafikonokat rajzolhatunk ki (matlab-hoz hasonló módon). Nekünk a pyplot API lesz belőle csak fontos amit a matplotlib.pyplot modul importálásával érhetünk el.

Plot

1
2
3
4
5
6
7
8
9
import matplotlib.pyplot as plt
import numpy as np

x = np.array([0,10])    # ezek lehetnének akár sima python listák is, ugyan úgy működik
y = np.array([0,40])
plt.plot(x,y)           # a pontok megjelenítése
                        # egy pont az (x[i], y[i]) koordináta-párból jön létre,
                        # így jelen esetben egy (0,0) és egy (10,40) pontból áll az egyenes
plt.show()              # a grafikon megjelenítse

plot1

Ha a show függvényhívás előtt többször is meghívjuk a plot függvényt, akkor több egyenest is rajzolhatunk ugyan arra az ábrára. Alapértelmezetten összeköti a pontokat, de a plot függvény 3. paraméterében ezt meg tudjuk változtatni, ahogy a pontok formáját és színét is. Pl.:

1
2
3
4
5
6
plt.plot(y,x)
plt.plot(x,y,'x--r')    # [forma][vonal][szín] formátum
                        # (jelen esetben x forma, szaggatott vonal, piros szín)
                        # ha a vonal helyére nem írunk semmit, akkor csak a pontokat fogja kirajzolni,
                        # nem köti össze
plt.show()

plot2

Az összes formátum megtalálható a modul dokumentációjában (https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html#matplotlib.pyplot.plot lap alja).

Feliratok

1
2
3
4
5
plt.plot(x,y)
plt.title("Title")      # A diagram címe
plt.xlabel("x")         # Tengelyfeliratok
plt.ylabel("y")
plt.show()

plot3

Több grafikon egyszerre

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import matplotlib.pyplot as plt
import numpy as np

x = np.array([0,10,20,30])
y = np.array([0,40,70,10])
plt.subplot(1,2,1)
plt.plot(x,y,'r')

x = np.array([0,1,2,3])
y = np.array([0,10,-20,30])
plt.subplot(1,2,2)
plt.plot(x,y)

plt.show()

plot4

A subplot függvénynek 3 paramétere van. Az első az, hogy a grafikonok hány sorban lesznek, a második, hogy hány oszlopban és a harmadik, hogy a következőnek kirajzolt grafikon hanyadik a sorban. Így pl. ha 6 ábrát szeretnénk egyszerre kirajzolni, mondjuk egy 2x3-as elrendezésben, akkor az első grafikon kirajzolása előtt meghívjuk a subplot függvényt (2,3,1) paraméterezéssel, majd a következőnél (2,3,2), stb.

Scatter

A scatter függvény segítségével is hasonló ábrákat rajzolhatunk, viszont itt biztosan nincsenek összekötve a pontok, illetve egyesével változtathatjuk minden pont színét.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import matplotlib.pyplot as plt
import numpy as np

x = np.array([11,  1,  0,  3, 13, 13,  2,  5, 10,  4])
y = np.array([23, 25, 37, 21, 20, 23, 22, 33, 32, 28])
plt.scatter(x,y)

x = np.array([14,  6, 10,  2,  0, 11, 10, 12,  0, 12])
y = np.array([28, 35,  7, 21, 12,  0, 17, 27, 18, 27])
colors = np.array(["red","green","blue","yellow","pink","black","orange","purple","beige","brown"])
plt.scatter(x,y, color = colors)
plt.show()

plot5

Bar

A bar függvénnyel tudunk oszlopdiagrammokat készíteni. Ennek a paraméterezése azzal tér el, hogy az első paraméterben szereplő lista most az oszlopok címe lesz.

1
2
3
4
5
6
7
8
9
import matplotlib.pyplot as plt
import numpy as np

x = np.array(["A","B","C","D","E"])     # Címkék
y = np.array([3,2,4,5,1])               # Oszlopok értékei


plt.bar(x,y, color = "red")             # A color paraméteren keresztül ugyan úgy színezhető
plt.show()

plot6

Histogram

Egyetlen listát vár paraméterként, amiből kirajzol egy hisztogrammot.

1
2
3
4
5
6
7
import matplotlib.pyplot as plt
import numpy as np

x = np.random.normal(200,20,300)    # 300 normál eloszlású szám generálása 200-as átlaggal, 10-es szórással
plt.hist(x)

plt.show()

plot7

Pie

Kördiagram készítésére használt függvény.

1
2
3
4
5
6
7
8
9
import matplotlib.pyplot as plt
import numpy as np

x = np.array([39,21,13,27])
labels = ["Kutya","Cica","T-Rex","lorem ipsum"]
colors = ["red","blue","green","orange"]
plt.pie(x, labels = labels, colors = colors)

plt.show()

plot8

Egy körcikk kiemelése
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import matplotlib.pyplot as plt
import numpy as np

x = np.array([39,21,13,27])
labels = ["Kutya","Cica","T-Rex","lorem ipsum"]
colors = ["red","blue","green","orange"]
explode = [0,0.2,0,0]                           # a 0-nál nagyobb értékkel rendelkező körcikkek lesznek kiemelve
                                                # jelen esetben mivel ez a második indexű, így a 
                                                # 21 értékű, "Cica" felírat kék körcikk lesz ez

plt.pie(x, labels = labels, colors = colors, explode = explode)

plt.show()

plot9

Feladatok

  1. Készítsd el a foo függvényt, ami 2 mátrixot és egy string-et vár paraméterként. Ellenőrizd le, hogy a két mátrix alakja ugyan olyan. Ha nem, alaktísd át az egyiket (ha azonos elemszámúak akkor az elsőt, amúgy a nagyobbat) úgy, hogy megegyezzen az elemszámuk (a nagyobbat alakítsd vektorrá és vágd le a végét) és az alakuk is. A függvény a két mátrix elemenkénti szorzatával térjen vissza.

  2. Olvasd be a data1.csv és data2.csv fájlokat egy-egy változóba. Fűzd össze a két fájl tartalmát (a második fájl utolsó oszlopa nem egyezik meg az első fájl utolsó oszlopával, így először nevezd át a DataFrame-en belül). Töröld ki azokat a sorokat, ahol az "ip_address" oszlop üres. Töltsd ki a "gender" oszlop üres sorait úgy, hogy mindenhova az "Attack Helicopter" szó kerüljön. Végül mentsd el a táblázatot "res.csv" néven.

  3. Az említett függvények további opcionális paramétereinek áttekintése (pl. a bar függvénynél a width).

  4. MOAÁ (Mother of All Ábrák) Készíts el egy ábrát, amin az összes tanult grafikon szerepel (egymás mellett/alatt valamilyen elrendezésben). A felhasznált adatok és címkék szabadon választhatóak, de legyenek valami értelmes mennyiségben (ne 3 érték szerepeljen egy hisztogrammon). Ezen kívül még mindegyik grafikont kirajzoló függvénynek használd legalább 2 opcionális paraméterét (pl. szín, vastagság, stb).


Utolsó frissítés: 2021-05-31 12:08:34