Knihovna Pandas¶
Pandas je open-source knihovna pro Python, která se používá pro práci s daty, zejména pro analýzu a manipulaci s tabulkovými daty.
Datové struktury:
DataFrame
- dvourozměrné pole podobné tabulkám v databázíchSeries
- jednorozměrné pole podobné seznamu
Klíčové funkce:
- načítání a ukládání dat z různých formátů (CSV, Excel, SQL, JSON atd.)
- filtrování, třídění a agregace dat
- práce s chybějícími nebo duplicitními daty
- skupinové operace
- časové řady a jejich analýza
Pandas je hojně využívána v datové vědě či strojovém učení.
import pandas as pd
data = pd.Series([1, 2, 3])
data
0 1 1 2 2 3 dtype: int64
data[0]
1
Vytvoření datového objektu ze slovníku:
pd.Series({"leden": 1, "unor": 2, "brezen": 3})
leden 1 unor 2 brezen 3 dtype: int64
data = pd.Series(data=[1, 2, 3], index=["leden", "unor", "brezen"])
data
leden 1 unor 2 brezen 3 dtype: int64
data["leden"]
1
Vytvoření datového objektu z Numpy pole:
import numpy as np
pd.Series(np.array([1, 2, 3]))
0 1 1 2 2 3 dtype: int64
DataFrame¶
Dvourozměrná datová struktura obsahující řádky a sloupce, kde každý sloupec je Series
a může mít jiný datový typ.
data = pd.DataFrame(np.random.uniform(-5, 9, size=(3, 3)),
index=["leden", "unor", "brezen"],
columns=["2021", "2022", "2023"])
data
2021 | 2022 | 2023 | |
---|---|---|---|
leden | -2.264276 | 2.725971 | -0.250796 |
unor | 4.575983 | -3.601472 | -4.089013 |
brezen | 8.654382 | -3.785402 | -4.854020 |
type(data["2021"])
pandas.core.series.Series
Zobrazení dat¶
Pro zobrazení prvních nebo posledních řádků lze použít metody head()
a tail()
.
data.head(2)
2021 | 2022 | 2023 | |
---|---|---|---|
leden | -2.264276 | 2.725971 | -0.250796 |
unor | 4.575983 | -3.601472 | -4.089013 |
data.tail(1)
2021 | 2022 | 2023 | |
---|---|---|---|
brezen | 8.654382 | -3.785402 | -4.85402 |
Výběr a indexování¶
data["2021"]
leden -2.264276 unor 4.575983 brezen 8.654382 Name: 2021, dtype: float64
data[["2021", "2023"]]
2021 | 2023 | |
---|---|---|
leden | -2.264276 | -0.250796 |
unor | 4.575983 | -4.089013 |
brezen | 8.654382 | -4.854020 |
# výběr jedné hodnoty
data.loc["leden", "2023"]
-0.25079593693519797
# výběr více hodnot
data.loc[["leden", "brezen"], ["2023"]]
2023 | |
---|---|
leden | -0.250796 |
brezen | -4.854020 |
data.loc[["leden"], ["2021", "2022"]]
2021 | 2022 | |
---|---|---|
leden | -2.264276 | 2.725971 |
# výběr na základě pozice
data.iloc[0]
2021 -2.264276 2022 2.725971 2023 -0.250796 Name: leden, dtype: float64
data.iloc[1:]
2021 | 2022 | 2023 | |
---|---|---|---|
unor | 4.575983 | -3.601472 | -4.089013 |
brezen | 8.654382 | -3.785402 | -4.854020 |
data.iloc[0, 0]
-2.2642755316495435
Filtrování¶
data > 0
2021 | 2022 | 2023 | |
---|---|---|---|
leden | False | True | False |
unor | True | False | False |
brezen | True | False | False |
data[data > 0]
2021 | 2022 | 2023 | |
---|---|---|---|
leden | NaN | 2.725971 | NaN |
unor | 4.575983 | NaN | NaN |
brezen | 8.654382 | NaN | NaN |
data["2021"] > 0
leden False unor True brezen True Name: 2021, dtype: bool
data[data["2021"] > 0]
2021 | 2022 | 2023 | |
---|---|---|---|
unor | 4.575983 | -3.601472 | -4.089013 |
brezen | 8.654382 | -3.785402 | -4.854020 |
data[data["2021"] > 0]["2022"]
unor -3.601472 brezen -3.785402 Name: 2022, dtype: float64
data[data["2021"] > 0][["2022", "2023"]]
2022 | 2023 | |
---|---|---|
unor | -3.601472 | -4.089013 |
brezen | -3.785402 | -4.854020 |
V případě logických operátorů použijeme &
(and) a |
(or). Závorky jsou v tomto případě nutné.
(data["2021"] > 0) & (data["2022"] > 0)
leden False unor False brezen False dtype: bool
data[(data["2021"] > 0) & (data["2022"] > 0)]
2021 | 2022 | 2023 |
---|
Modifikace datových objektů¶
Přidání nového sloupce:
data["2024"] = data["2023"] + 0.1
data
2021 | 2022 | 2023 | 2024 | |
---|---|---|---|---|
leden | -2.264276 | 2.725971 | -0.250796 | -0.150796 |
unor | 4.575983 | -3.601472 | -4.089013 | -3.989013 |
brezen | 8.654382 | -3.785402 | -4.854020 | -4.754020 |
Odstranění sloupce:
data.drop("2024", axis=1)
2021 | 2022 | 2023 | |
---|---|---|---|
leden | -2.264276 | 2.725971 | -0.250796 |
unor | 4.575983 | -3.601472 | -4.089013 |
brezen | 8.654382 | -3.785402 | -4.854020 |
# nedojde k modifikaci objektu!
data
2021 | 2022 | 2023 | 2024 | |
---|---|---|---|---|
leden | -2.264276 | 2.725971 | -0.250796 | -0.150796 |
unor | 4.575983 | -3.601472 | -4.089013 | -3.989013 |
brezen | 8.654382 | -3.785402 | -4.854020 | -4.754020 |
# modifikace stavájícího objektu
data.drop("2024", axis=1, inplace=True)
data
2021 | 2022 | 2023 | |
---|---|---|---|
leden | -2.264276 | 2.725971 | -0.250796 |
unor | 4.575983 | -3.601472 | -4.089013 |
brezen | 8.654382 | -3.785402 | -4.854020 |
Odstranění řádku:
data.drop("brezen", axis=0)
2021 | 2022 | 2023 | |
---|---|---|---|
leden | -2.264276 | 2.725971 | -0.250796 |
unor | 4.575983 | -3.601472 | -4.089013 |
Pro přidání řádku lze použít metodu loc
:
data.loc["duben"] = np.random.uniform(20, 30, size=(1, 3))[0]
data
2021 | 2022 | 2023 | |
---|---|---|---|
leden | -2.264276 | 2.725971 | -0.250796 |
unor | 4.575983 | -3.601472 | -4.089013 |
brezen | 8.654382 | -3.785402 | -4.854020 |
duben | 23.248635 | 28.812526 | 26.635986 |
Změna indexu¶
data
2021 | 2022 | 2023 | |
---|---|---|---|
leden | -2.264276 | 2.725971 | -0.250796 |
unor | 4.575983 | -3.601472 | -4.089013 |
brezen | 8.654382 | -3.785402 | -4.854020 |
duben | 23.248635 | 28.812526 | 26.635986 |
data.index
Index(['leden', 'unor', 'brezen', 'duben'], dtype='object')
data.reset_index()
index | 2021 | 2022 | 2023 | |
---|---|---|---|---|
0 | leden | -2.264276 | 2.725971 | -0.250796 |
1 | unor | 4.575983 | -3.601472 | -4.089013 |
2 | brezen | 8.654382 | -3.785402 | -4.854020 |
3 | duben | 23.248635 | 28.812526 | 26.635986 |
data["mesice"] = ["prosinec", "leden", "unor", "brezen"]
data
2021 | 2022 | 2023 | mesice | |
---|---|---|---|---|
leden | -2.264276 | 2.725971 | -0.250796 | prosinec |
unor | 4.575983 | -3.601472 | -4.089013 | leden |
brezen | 8.654382 | -3.785402 | -4.854020 | unor |
duben | 23.248635 | 28.812526 | 26.635986 | brezen |
data.set_index("mesice")
2021 | 2022 | 2023 | |
---|---|---|---|
mesice | |||
prosinec | -2.264276 | 2.725971 | -0.250796 |
leden | 4.575983 | -3.601472 | -4.089013 |
unor | 8.654382 | -3.785402 | -4.854020 |
brezen | 23.248635 | 28.812526 | 26.635986 |
data
2021 | 2022 | 2023 | mesice | |
---|---|---|---|---|
leden | -2.264276 | 2.725971 | -0.250796 | prosinec |
unor | 4.575983 | -3.601472 | -4.089013 | leden |
brezen | 8.654382 | -3.785402 | -4.854020 | unor |
duben | 23.248635 | 28.812526 | 26.635986 | brezen |
# pro modifikaci objektu použijte inplace
data.set_index("mesice", inplace=True)
data
2021 | 2022 | 2023 | |
---|---|---|---|
mesice | |||
prosinec | -2.264276 | 2.725971 | -0.250796 |
leden | 4.575983 | -3.601472 | -4.089013 |
unor | 8.654382 | -3.785402 | -4.854020 |
brezen | 23.248635 | 28.812526 | 26.635986 |
Práce s prázdnými hodnotami¶
data.iloc[0, 0] = np.nan
data
2021 | 2022 | 2023 | |
---|---|---|---|
mesice | |||
prosinec | NaN | 2.725971 | -0.250796 |
leden | 4.575983 | -3.601472 | -4.089013 |
unor | 8.654382 | -3.785402 | -4.854020 |
brezen | 23.248635 | 28.812526 | 26.635986 |
Řádky či sloupce obsahující prázdné hodnoty lze odstranit pomocí metody dropna()
.
data.dropna()
2021 | 2022 | 2023 | |
---|---|---|---|
mesice | |||
leden | 4.575983 | -3.601472 | -4.089013 |
unor | 8.654382 | -3.785402 | -4.854020 |
brezen | 23.248635 | 28.812526 | 26.635986 |
data.dropna(axis=1)
2022 | 2023 | |
---|---|---|
mesice | ||
prosinec | 2.725971 | -0.250796 |
leden | -3.601472 | -4.089013 |
unor | -3.785402 | -4.854020 |
brezen | 28.812526 | 26.635986 |
Metoda fillna()
naopak umožňuje prázdné hodnoty nahradit.
data.fillna(0)
2021 | 2022 | 2023 | |
---|---|---|---|
mesice | |||
prosinec | 0.000000 | 2.725971 | -0.250796 |
leden | 4.575983 | -3.601472 | -4.089013 |
unor | 8.654382 | -3.785402 | -4.854020 |
brezen | 23.248635 | 28.812526 | 26.635986 |
data.fillna(data["2021"].mean())
2021 | 2022 | 2023 | |
---|---|---|---|
mesice | |||
prosinec | 12.159667 | 2.725971 | -0.250796 |
leden | 4.575983 | -3.601472 | -4.089013 |
unor | 8.654382 | -3.785402 | -4.854020 |
brezen | 23.248635 | 28.812526 | 26.635986 |
Konverze¶
Data lze převést např. do Numpy pole.
data.to_numpy()
array([[ nan, 2.7259705 , -0.25079594], [ 4.57598346, -3.6014724 , -4.08901297], [ 8.65438166, -3.78540249, -4.85402042], [23.24863454, 28.81252551, 26.63598593]])
Import vstupních dat do datových objektů Pandas¶
Knihovna Pandas umožňuje vytvoření objektu DataFrame
na základě nejrůznějších datových formátů, např.:
- CSV - metoda
read_csv()
- MS Excel - metoda
read_excel()
- relační databáze - modul
pandas.io.sql
Příklad načtení souhrných statistických výsledků voleb do zastupitelstev krajů 2024 (https://www.volby.cz/):
volby = pd.read_csv('data/02/data-export.csv', sep=";")
volby
Volební strana | Středočeský kraj | Jihočeský kraj | Plzeňský kraj | Karlovarský kraj | Ústecký kraj | Liberecký kraj | Královéhradecký kraj | Pardubický kraj | Kraj Vysočina | Jihomoravský kraj | Olomoucký kraj | Zlínský kraj | Moravskoslezský kraj | Celkem ČR | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Ukončené zpracování | Ano | Ano | Ano | Ano | Ano | Ano | Ano | Ano | Ano | Ano | Ano | Ano | Ano | NaN |
1 | ANO | 33,35 | 24,13 | 38,63 | 44,03 | 39,47 | 32,87 | 34,54 | 29,78 | 34,77 | 28,79 | 40,42 | 37,27 | 47,22 | 35,38 |
2 | ČSNS+KSČM | NaN | NaN | NaN | NaN | NaN | 4,99 | 5,17 | NaN | NaN | NaN | NaN | NaN | 7,40 | 1,43 |
3 | ČSNS+KSČM+ČSSD | 5,19 | NaN | NaN | NaN | NaN | NaN | NaN | 6,05 | 6,00 | NaN | 6,29 | 5,63 | NaN | 2,24 |
4 | ČSNS+KSČM+SD-SN | NaN | NaN | 6,68 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0,40 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
78 | Zel+ED+TOP+JP | NaN | NaN | NaN | NaN | 4,01 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0,29 |
79 | Zel+LES+SEN+Ide | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1,84 | NaN | NaN | NaN | 0,25 |
80 | Zelení+LES | NaN | NaN | NaN | NaN | NaN | 2,79 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0,13 |
81 | Zelení+Levice | NaN | 0,66 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0,05 |
82 | Zelení+SEN 21 | 1,05 | NaN | NaN | NaN | NaN | NaN | 1,86 | NaN | NaN | NaN | NaN | NaN | NaN | 0,26 |
83 rows × 15 columns
volby = volby.drop(0, axis=0).set_index("Volební strana")
volby
Středočeský kraj | Jihočeský kraj | Plzeňský kraj | Karlovarský kraj | Ústecký kraj | Liberecký kraj | Královéhradecký kraj | Pardubický kraj | Kraj Vysočina | Jihomoravský kraj | Olomoucký kraj | Zlínský kraj | Moravskoslezský kraj | Celkem ČR | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Volební strana | ||||||||||||||
ANO | 33,35 | 24,13 | 38,63 | 44,03 | 39,47 | 32,87 | 34,54 | 29,78 | 34,77 | 28,79 | 40,42 | 37,27 | 47,22 | 35,38 |
ČSNS+KSČM | NaN | NaN | NaN | NaN | NaN | 4,99 | 5,17 | NaN | NaN | NaN | NaN | NaN | 7,40 | 1,43 |
ČSNS+KSČM+ČSSD | 5,19 | NaN | NaN | NaN | NaN | NaN | NaN | 6,05 | 6,00 | NaN | 6,29 | 5,63 | NaN | 2,24 |
ČSNS+KSČM+SD-SN | NaN | NaN | 6,68 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0,40 |
ČSNS+SOCDE+KSČM | NaN | NaN | NaN | NaN | 7,94 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0,58 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
Zel+ED+TOP+JP | NaN | NaN | NaN | NaN | 4,01 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0,29 |
Zel+LES+SEN+Ide | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1,84 | NaN | NaN | NaN | 0,25 |
Zelení+LES | NaN | NaN | NaN | NaN | NaN | 2,79 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0,13 |
Zelení+Levice | NaN | 0,66 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 0,05 |
Zelení+SEN 21 | 1,05 | NaN | NaN | NaN | NaN | NaN | 1,86 | NaN | NaN | NaN | NaN | NaN | NaN | 0,26 |
82 rows × 14 columns
# reálná data -> nejrůznější problémy :-)
# volby.loc["ANO"]
volby.index[0]
# https://unicode-explorer.com/c/200B
'ANO\u200b'
volby.index = volby.index.str.replace('\u200b', '')
volby.index[0]
'ANO'
volby.loc["ANO"]
Středočeský kraj 33,35 Jihočeský kraj 24,13 Plzeňský kraj 38,63 Karlovarský kraj 44,03 Ústecký kraj 39,47 Liberecký kraj 32,87 Královéhradecký kraj 34,54 Pardubický kraj 29,78 Kraj Vysočina 34,77 Jihomoravský kraj 28,79 Olomoucký kraj 40,42 Zlínský kraj 37,27 Moravskoslezský kraj 47,22 Celkem ČR 35,38 Name: ANO, dtype: object
# nelze určit maximální hodnotu
# volby2024.loc["ANO"].max()
volby.loc["ANO"].dtype
dtype('O')
### decimal - nefunguje ideálně (důvod: druhý řádek)
volby = pd.read_csv('data/02/data-export.csv', sep=";", decimal=",")\
.drop(0, axis=0).set_index("Volební strana")
volby.index = volby.index.str.replace('\u200b', '')
volby.loc["ANO"]
Středočeský kraj 33,35 Jihočeský kraj 24,13 Plzeňský kraj 38,63 Karlovarský kraj 44,03 Ústecký kraj 39,47 Liberecký kraj 32,87 Královéhradecký kraj 34,54 Pardubický kraj 29,78 Kraj Vysočina 34,77 Jihomoravský kraj 28,79 Olomoucký kraj 40,42 Zlínský kraj 37,27 Moravskoslezský kraj 47,22 Celkem ČR 35.38 Name: ANO, dtype: object
volby = pd.read_csv('data/02/data-export.csv', sep=";")\
.drop(0, axis=0).set_index("Volební strana")
# nebo lze resit elegantneji
volby = pd.read_csv('data/02/data-export.csv', sep=";", skiprows=lambda r: r == 1)\
.set_index("Volební strana")
volby.index = volby.index.str.replace('\u200b', '')
volby = volby.apply(lambda x: x.str.replace(',','.').astype(float))
volby.loc["ANO"]
Středočeský kraj 33.35 Jihočeský kraj 24.13 Plzeňský kraj 38.63 Karlovarský kraj 44.03 Ústecký kraj 39.47 Liberecký kraj 32.87 Královéhradecký kraj 34.54 Pardubický kraj 29.78 Kraj Vysočina 34.77 Jihomoravský kraj 28.79 Olomoucký kraj 40.42 Zlínský kraj 37.27 Moravskoslezský kraj 47.22 Celkem ČR 35.38 Name: ANO, dtype: float64
volby.loc["ANO"].idxmax(), volby.loc["ANO"].max()
('Moravskoslezský kraj', 47.22)
Výpočet korelační matice¶
data = {
'Cena': [100, 150, 200, 250, 300],
'Prodeje': [20, 15, 10, 5, 2]
}
df = pd.DataFrame(data)
df
Cena | Prodeje | |
---|---|---|
0 | 100 | 20 |
1 | 150 | 15 |
2 | 200 | 10 |
3 | 250 | 5 |
4 | 300 | 2 |
Chceme zjistit, jak moc jsou prodeje závislé na cenách pomocí korelační matice, což je koncept z lineární algebry.
df.corr()
Cena | Prodeje | |
---|---|---|
Cena | 1.000000 | -0.996241 |
Prodeje | -0.996241 | 1.000000 |
Pokud je hodnota blízko -1, znamená to silnou negativní korelaci, což naznačuje, že s rostoucí cenou klesají prodeje.