Materiál k cvičení DBM1 týden #3, sezona 2024/2025
Při práci v Pandas budeme často využívat datový typ DataFrame, který je základním prvkem pro práci s tabulkovými daty. DataFrame je dvourozměrná datová struktura, která obsahuje data uspořádaná do řádků a sloupců.
pip install pandas
pip install openpyxl
📄 Datové zdroje: customer_purchases.csv, customer_purchases.xlsx (umělá data o nákupech zákazníků)
import pandas as pd
df_csv = pd.read_csv("data/customer_purchases.csv")
df_xlsx = pd.read_excel("data/customer_purchases.xlsx")
print(df_csv)
print(df_xlsx)
Pokud není nainstalovná knihovna pandas, bude ve zdrojovém kódu podtrženo volání pd.read_csv a pd.read_excel.
Jelikož ke čtení Excel souborů je potřeba extra knihovna, s kterou na pozadí pracuje Pandas při načítání, není její absence detekována v kódu a na problém by se narazilo až při spuštění skriptu.
Pokud se tedy vypíše chyba ImportError: Missing optional dependency 'openpyxl'. Use pip or conda to install openpyxl., nainstalujte knihovnu openpyxl pomocí pip install openpyxl.
Výpisem by mělo být zobrazení (opsání) tabulky ze vstupního souboru. Všimněte si, že Pandas automaticky detekuje hlavičku tabulky a použije ji jako názvy sloupců a vlevo jsou čísla řádků od 0.
Funkce read_csv má mnoho parametrů, které umožňují nastavit různé vlastnosti načítání souboru (viz bublina v IDE). My použili zatím volání bez parametrů, což znamená, že se použije výchozí nastavení.
📚 Dokumentace Pandas → read_csv
Pokud se některé znaky nezobrazují správně, může to být způsobeno špatným kódováním souboru. V češtině je často používáno kódování windows-1250 nebo cp1250, ideálně by ale mělo být použito kódování utf-8 (což je defaultní hodnota v používané funkci).
Při problému je možné explicitně při načítání souboru určit kódování pomocí parametru encoding. Např. pro načtení souboru s kódováním cp1250:
df_csv = pd.read_csv("data/customer_purchases.csv", encoding="cp1250")
Pokud jsou hodnoty v souboru oddělené jiným znakem než čárkou , (např. v českých souborech je často středník ;), je možné to nastavit pomocí parametru sep. Např. pro načtení souboru s oddělovačem středníkem:
df_csv = pd.read_csv("data/customer_purchases.csv", sep=";")
Samozřejmě lze kombinovat více parametrů, např.:
df_csv = pd.read_csv("data/customer_purchases.csv", sep=";", encoding="cp1250")
※ Náš CSV soubor má čárky jako oddělovače a je v kódování
utf-8.
print(df_csv.head())
print(df_xlsx.head())
Funkce head vypíše prvních 5 řádků tabulky. Podobně funguje funkce tail, která vypíše posledních 5 řádků tabulky.
print(df_csv.info())
print(df_xlsx.info())
Funkce info vypíše základní informace o DataFrame, jako jsou názvy sloupců, počet neprázdných hodnot, datové typy sloupců a celkovou velikost tabulky.
V našem případě máme následující výstup:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10 entries, 0 to 9
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 CustomerID 10 non-null int64
1 Name 10 non-null object
2 PurchaseAmount 10 non-null float64
3 PurchaseDate 10 non-null object
4 DiscountApplied 5 non-null float64
dtypes: float64(2), int64(1), object(2)
memory usage: 528.0+ bytes
Q1: K čemu slouží a co říkají
Not-Null CountaDtype?
Funkce describe vypíše základní statistické informace o číselných sloupcích (počet, průměr, směrodatná odchylka, min, max, kvartily).
print(df_csv.describe())
print(df_xlsx.describe())
Q2: Co je to kvartil a jakou informaci poskytuje?
Výběr sloupce podle názvu:
print(df_csv["Name"])
Výběr řádku podle indexu:
print(df_csv.loc[0])
Výběr konkrétní hodnoty jako kombinace řádku a sloupce:
print(df_csv.loc[0, "Name"])
Pokud chceme vybírat sloupce přes indexy, nikoliv názvy, můžeme použít funkci iloc:
print(df_csv.iloc[:, 1]) # vše řádky, druhý sloupec
print(df_csv.iloc[0, 1]) # první řádek, druhý sloupec
print(df_csv.iloc[0:3, 1:3]) # první až třetí řádek, druhý až třetí sloupec
print(df_csv.iloc[0:3, [0,2]]]) # první až třetí řádek, první a třetí sloupec
df_csv = df_csv.rename(columns={"Name": "CustomerName"})
print(df_csv)
Všimněte si, že funkce rename vrací nový DataFrame, takže je potřeba uložit její výstup zpět do proměnné (byť se stejným názvem). Parametr columns je slovník, kde klíč je původní název sloupce a hodnota je nový název sloupce.
Nový sloupec můžeme přidat jednoduše tak, že přiřadíme nový sloupec do DataFrame jako nový klíč v slovníku. Na pravé straně přiřazení může být i výpočet z jiných sloupců.
df_csv["X"] = "🐾"
df_csv["DiscountPercentage"] = df_csv["DiscountApplied"] / (df_csv["PurchaseAmount"] + df_csv["DiscountApplied"])
print(df_csv.to_string())
df_csv = df_csv.drop(columns=["X"])
print(df_csv)
Hodnota lze změnit přímo pomocí přístupu k dané buňce:
df_csv.loc[0, "DiscountApplied"] = 10
print(df_csv)
Dříve jsme pozorovaly, že sloupec PurchaseDate má datový typ object, což znamená, že Pandas neví, že se jedná o datum. Můžeme tento sloupec převést na typ datetime pomocí speciální funkce to_datetime.
Dále Name je typ object, což je obecný typ pro hodnoty.
df_csv["PurchaseDate"] = pd.to_datetime(df_csv["PurchaseDate"], format="%Y-%m-%d")
df_csv["Name"] = df_csv["Name"].astype("string")
print(df_csv.info())
📚 Datetime format "%Y-%m-%d" znamená, že datum je ve formátu YYYY-MM-DD. Detailnější popis formátovacích znaků je v dokumentaci Pythonu.
※ String na rozdíl od object je speciální datový typ v Pandas, který je optimalizovaný pro práci s textem.
Q3: Zkuste, jak se chová volání
df_csv["Name"].str.upper()pokud je sloupec typustringa pokud je typuobject. Zkuste změnit nějakou hodnotu na číslo a zjistěte, co se stane.
Filtrování dat můžeme provést pomocí podmíněného výběru přes zápis v hranatých závorkách. Např. získání řádků, kde je PurchaseAmount větší než 150:
df = df_csv.loc[df_csv["PurchaseAmount"] > 150]
print(df)
Pro kombinaci podmínek můžeme použít logické operátory & (a) a | (nebo). Např. získání řádků, kde je PurchaseAmount větší než 150 a byla aplikována sleva:
df = df_csv.loc[(df_csv["PurchaseAmount"] > 150) & (df_csv["DiscountApplied"] > 0)]
print(df)
Kromě toho lze vybrat klasicky rozsahem indexů, např.:
df = df_csv.loc[2:5]
print(df)
Řazení dat můžeme provést pomocí funkce sort_values. Např. seřazení podle sloupce PurchaseAmount sestupně:
df = df_csv.sort_values(by="PurchaseAmount", ascending=False)
df = df_csv.sort_values(by=["PurchaseAmount", "PurchaseDate"], ascending=False)
print(df)
Dříve jsme mohli pozorovat, že ve sloupci DiscountApplied jsou některé hodnoty chybějící (NaN). Pandas má zabudované metody pro práci s chybějícími hodnotami.
Pro odstranění řádků s chybějícími hodnotami můžeme použít funkci dropna:
df = df_csv.dropna()
print(df)
Pro nahrazení chybějících hodnot nějakou konstantou (např. 0) můžeme použít funkci fillna:
# df = df_csv.fillna(0) # všechny chybějící hodnoty
df = df_csv.fillna({"DiscountApplied": 0}) # jen pro sloupec DiscountApplied
print(df)
Po provedení změn můžeme DataFrame uložit zpět do souboru. Pro uložení do CSV souboru:
df_csv.to_csv("data/customer_purchases_modified.csv", index=False)
※
index=Falseznamená, že se nebude ukládat číslování řádků do souboru.
Načtený a upravený DataFrame můžeme rychle vizualizovat pomocí grafů. Pro jednoduchý scatter plot můžeme použít knihovnu Seaborn, která je postavena nad Matplotlib.
pip install matplotlib
pip install seaborn
import matplotlib
matplotlib.use("TkAgg") # Ensure an interactive backend is set
import matplotlib.pyplot as plt
import seaborn as sns
# Create the scatter plot
sns.set_theme(style="whitegrid")
sns.scatterplot(data=df_csv, x="PurchaseDate", y="PurchaseAmount")
# Save to file and display the plot
plt.savefig("customer_purchases.png")
plt.show()
※ Vizualizce budou detailněji probírány na pozdějších cvičeních.