Knihovna Polars: výkonnější alternativa ke knihovně Pandas (líné vyhodnocování operací)

26. 1. 2023
Doba čtení: 33 minut

Sdílet

 Autor: Polars team, podle licence: CC BY-NC 2.5
Mezi zajímavé vlastnosti knihovny Polars patří schopnost pracovat s daty, jejichž objem je větší než volná kapacita operační paměti. Protože se jedná o velmi důležitou vlastnost, budeme se touto technikou zabývat dnes.

Obsah

1. Knihovna Polars: výkonnější alternativa ke knihovně Pandas (líné vyhodnocování operací)

2. Líné operace a líné vyhodnocování v IT

3. Koncept líných datových rámců

4. Líné načtení dat do datového rámce ze souboru ve formátu CSV

5. Převod běžného datového rámce na líný datový rámec

6. Převod líného datového rámce na běžný datový rámec

7. Ukázka podpory líných operací v knihovně Polars

8. Konstrukce plánu s větším množstvím operací; realizace plánu

9. Větší množství naplánovaných operací

10. Ladění naplánovaných operací s využitím omezeného objemu dat

11. Limity operace fetch při agregaci dat

12. Další snížení počtu řádků vracených operací fetch: zvýraznění nekorektních výsledků

13. Operace head aplikovaná na líný rámec

14. Rozvětvení a opětovné spojení plánů

15. Vizualizace plánu

16. Vizualizace plánu s operacemi SLICE

17. Obsah závěrečné části seriálu o knihovně Polars

18. Repositář s demonstračními příklady

19. Odkazy na Internetu

1. Knihovna Polars: výkonnější alternativa ke knihovně Pandas (líné vyhodnocování operací)

Jak jsme si již několikrát připomenuli v předchozí dvojici článků [1] [2], je knihovna Polars navržena takovým způsobem, aby byly operace s daty uloženými v datových řadách nebo v datových rámcích realizovány co nejrychleji, ideálně s využitím souběžně běžících úloh, ale i s využitím moderních SIMD operací. Mnohem užitečnější je však další vlastnost této knihovny – schopnost pracovat s daty, jejichž objem je větší než volná kapacita operační paměti. Vzhledem k tomu, že se jedná o velmi důležitou vlastnost (a v mnoha případech vlastně o jediný důvod, proč vlastně uvažovat o přechodu od PandasPolars), budeme se touto velmi zajímavou problematikou zabývat v dnešním článku.

2. Líné operace a líné vyhodnocování v IT

V informatice se na mnoha místech setkáme s využitím takzvaných „líných“ operací popř. „líných datových struktur“ resp. „líného vyhodnocování“. Jedná se o koncept, který je založen na tom, že se nějaký výpočet či operace neprovede ihned ve chvíli, kdy je v programu zapsána, ale obecně se její vykonání přesune do budoucnosti s tím předpokladem, že mnohdy vlastně není nutné operaci provádět vůbec nebo ne v plném rozsahu. Připomeňme si například, jak jsou realizovány „líné sekvence“ v programovacím jazyku Clojure. Obecně platí, že se prvky v líných sekvencích vyhodnocují až tehdy, kdy je to nezbytně nutné a předpokládá se, že k vyhodnocení nemusí dojít vůbec.

Příkladem může být líná sekvence, která vznikne aplikací funkcí range + filter + map + take. V Clojure můžeme pro větší čitelnost použít threading makro, takže výsledný zápis připomíná klasickou pipelinu:

(->> (range)
     (map #(* % 3))
     (filter #(even %))
     (take 10))

Funkce range obecně (pokud se jí nezadají další parametry) generuje nekonečnou sekvenci, ovšem díky pozdějšímu použití take se z této nekonečné sekvence získá jen prvních n prvků – a až za podmínky, kdy se musí pracovat s hodnotou prvku (například když se má výsledek vytisknout). Aplikace funkcí range, filter a map jsou tedy provedeny později či vůbec ne. V našem konkrétním případě bude výsledkem tato konečná a realizovaná sekvence:

(0 6 12 18 24 30 36 42 48 54)
Poznámka: koncept líného vyhodnocování operací není použit pouze v jazyku Clojure, ale najdeme ho (pochopitelně v poněkud odlišné podobě) například v OCamlu, Scheme, Haskellu, Mirandě, ale – i když jen v omezené míře – například i v Pythonu (generátory, které mohou vytvářet nekonečné sekvence).

3. Koncept líných datových rámců

V tomto seriálu jsme se již několikrát zmínili o funkci nazvané read_csv. Připomeňme si, že tato funkce slouží pro načtení dat uložených ve formátu CSV (comma separated values), TSV (tab separated values) popř. z textového souboru s pevně zadanou strukturou. Výsledkem je plnohodnotný datový rámec, jenž je uložený v operační paměti a na který je možné aplikovat všechny předminule i minule popsané operace, včetně seskupení dat s jejich následnou agregací. Například:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# přečtení zdrojových dat
df = polars.read_csv("hall_of_fame.csv")
 
# maximální počet zobrazených řádků
polars.Config.set_tbl_rows(100)
 
# seskupení podle názvu jazyka
df = df.groupby("Winner", maintain_order=True).agg([polars.col("Year").len().alias("Zvítězil")]). \
        sort("Zvítězil"). \
        reverse(). \
        head(5)
 
# zobrazíme datový rámec
print(df)

Jakým způsobem je ale vůbec možné pracovat s daty, která mají větší objem, než je volná kapacita operační paměti? Řešením jsou takzvané líné datové rámce. V případě použití líných rámců se operace vyžadované uživatelem neprovádí hned, ale až ve chvíli, kdy jsou výsledky skutečně zapotřebí – vyžadované operace jsou tedy zapamatovány ve formě plánu. A navíc je vykonávání operací řešeno formou „streamu“, tj. v naprosté většině případů se nevyžaduje, aby byl celý datový rámec uložen v operační paměti. Práci s línými datovými rámci si ostatně ukážeme v navazujících kapitolách.

4. Líné načtení dat do datového rámce ze souboru ve formátu CSV

Podívejme se nyní na způsob „líného“ načtení datového rámce ze souboru, v němž jsou data uložena ve formátu CSV. Namísto funkce read_csv použijeme funkci nazvanou scan_csv, která má stejné povinné i nepovinné parametry, jako již zmíněná funkce read_csv, takže záměna v existujících skriptech je možná a hlavně snadná:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# líné přečtení zdrojových dat
df = polars.scan_csv("hall_of_fame.csv")
 
# zobrazíme líně načtený datový rámec
print(df)
print()
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu získáte na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame01_scan_csv.py.

Výsledek, který získáme po spuštění tohoto skriptu, je zcela odlišný od výsledku operace read_csv. Funkce scan_csv totiž pouze zaznamená, jaká operace se má provést a uloží tento záznam do plánu. A tento plán je skriptem zobrazen:

naive plan: (run LazyFrame.describe_optimized_plan() to see the optimized plan)
 
  CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS

Výsledkem je tedy líný datový rámec. Naproti tomu použití funkce read_csv vede k okamžitému načtení dat a výsledkem bude běžný datový rámec:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# okamžité přečtení zdrojových dat
df = polars.read_csv("hall_of_fame.csv")
 
# zobrazíme načtený datový rámec
print(df)
print()

S výsledkem:

shape: (20, 2)
┌──────┬────────┐
│ Year ┆ Winner │
│ ---  ┆ ---    │
│ i64  ┆ str    │
╞══════╪════════╡
│ 2022 ┆ C++    │
│ 2021 ┆ Python │
│ 2020 ┆ Python │
│ 2019 ┆ C      │
│ ...  ┆ ...    │
│ 2006 ┆ Ruby   │
│ 2005 ┆ Java   │
│ 2004 ┆ PHP    │
│ 2003 ┆ C++    │
└──────┴────────┘

5. Převod běžného datového rámce na líný datový rámec

Knihovna Polars umožňuje provést převod běžného datového rámce (tj. rámce s vyhodnocenými daty) na líný datový rámec. Pro tento účel se používá metoda nazvaná příznačně lazy. Podívejme se nyní na to, jak tento převod může proběhnout v praxi. V dalším demonstračním příkladu nejdříve načteme obsah souboru ve formátu CSV do běžného datového rámce, jehož obsah je následně zobrazen na terminálu. Posléze z tohoto rámce vytvoříme líný datový rámec s využitím již zmíněné metody lazy a následně tento líný datový rámec zobrazíme:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# přečtení zdrojových dat
df = polars.read_csv("hall_of_fame.csv")
 
# převod na líný datový rámec
df2 = df.lazy()
 
# zobrazíme načtený datový rámec
print(df)
print()
 
# následně zobrazíme líný datový rámec
print(df2)
print()
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu získáte na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame02_read_csv_and_con­vert.py.

Ze zobrazených výsledků je patrné, že se nejdříve skutečně zobrazí obsah běžného datového rámce:

shape: (20, 2)
┌──────┬────────┐
│ Year ┆ Winner │
│ ---  ┆ ---    │
│ i64  ┆ str    │
╞══════╪════════╡
│ 2022 ┆ C++    │
│ 2021 ┆ Python │
│ 2020 ┆ Python │
│ 2019 ┆ C      │
│ ...  ┆ ...    │
│ 2006 ┆ Ruby   │
│ 2005 ┆ Java   │
│ 2004 ┆ PHP    │
│ 2003 ┆ C++    │
└──────┴────────┘

Následně se namísto obsahu líného datového rámce vzniklého konverzí zobrazí – přesně podle očekávání – pouze plán, tj. seznam operací, které se mají provést v budoucnosti:

naive plan: (run LazyFrame.describe_optimized_plan() to see the optimized plan)
 
  DF ["Year", "Winner"]; PROJECT */2 COLUMNS; SELECTION: "None"

6. Převod líného datového rámce na běžný datový rámec

Způsob převodu běžného datového rámce na líný datový rámec jsme si ukázali v předchozí kapitole. Mnohdy je však mnohem důležitější provést opačný převod, tedy převod líného rámce na běžný rámec. V tomto případě však není slovo „převod“ zcela přesné, protože se nejedná o transformaci dat, ale o „realizaci“ (uskutečnění) všech operací, které byly pouze naplánovány. Podívejme se na jednoduchý příklad, v němž se převod/realizace provádí metodou nazvanou collect:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# líné přečtení zdrojových dat
df = polars.scan_csv("hall_of_fame.csv")
 
# zobrazíme líně načtený datový rámec
print(df)
print()
 
# převod na běžný datový rámec
df2 = df.collect()
 
# zobrazíme běžný (výsledný) datový rámec
print(df2)
print()
print(df2.columns)
print(df2.dtypes)
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu získáte na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame03_collect_to_df.py.

Po spuštění tohoto demonstračního příkladu se nejdříve zobrazí plán pro líný datový rámec:

naive plan: (run LazyFrame.describe_optimized_plan() to see the optimized plan)
 
  CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS

Ve druhém kroku se zobrazí realizovaný konkrétní datový rámec vytvořený metodou collect:

shape: (20, 2)
┌──────┬────────┐
│ Year ┆ Winner │
│ ---  ┆ ---    │
│ i64  ┆ str    │
╞══════╪════════╡
│ 2022 ┆ C++    │
│ 2021 ┆ Python │
│ 2020 ┆ Python │
│ 2019 ┆ C      │
│ ...  ┆ ...    │
│ 2006 ┆ Ruby   │
│ 2005 ┆ Java   │
│ 2004 ┆ PHP    │
│ 2003 ┆ C++    │
└──────┴────────┘
 
['Year', 'Winner']
[Int64, Utf8]
Poznámka: zatímco práce s líným datovým rámcem není prakticky závislá na volné kapacitě operační paměti, po realizaci již mohou nastat problémy v případě, že se zpracovává enormní množství dat (což ovšem není náš případ).

7. Ukázka podpory líných operací v knihovně Polars

Nyní se dostáváme k velmi důležité vlastnosti knihovny Polars. Připomeňme si, že dokud není nutné pracovat s daty podrobenými nějaké operaci nebo sérií operací, není vlastně nutné tyto operace ani provádět – postačuje si pouze zapamatovat jejich pořadí a případný použitý parametr nebo parametry. A přesně tímto způsobem se pracuje s línými datovými rámci, protože každá další operace nad rámcem se „pouze“ zapíše do plánu.

Samozřejmě si tento koncept můžeme velmi snadno otestovat, a to konkrétně na demonstračním příkladu, v němž se pokusíme záznamy v líném datovém rámci seřadit podle sloupce „Winner“. V případě, že by se následně nezavolala operace collect, k vlastnímu řazení by vůbec nedošlo:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# líné přečtení zdrojových dat
df = polars.scan_csv("hall_of_fame.csv")
 
# zobrazíme líně načtený datový rámec
print(df)
print()
 
# aplikace operace na líný datový rámec
df2 = df.sort("Winner")
 
# převod na běžný datový rámec
df3 = df2.collect()
 
# zobrazíme druhý líny datový rámec
print(df2)
print()
 
# zobrazíme běžný (výsledný) datový rámec
print(df3)
print()
print(df3.columns)
print(df3.dtypes)
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu získáte na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame04_lazy_sort.py.

Opět je vhodné si alespoň ve stručnosti okomentovat jednotlivé informace vypsané po spuštění tohoto demonstračního příkladu. Nejdříve se líně načtou data ze souboru s formátem CSV. Výsledkem je líný datový rámec, který je zobrazen formou svého plánu, tedy následovně:

naive plan: (run LazyFrame.describe_optimized_plan() to see the optimized plan)
 
  CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS

Z tohoto líného datového rámce je s využitím operace sort vytvořen nový líný datový rámec, jehož plán je pochopitelně odlišný – obsahuje totiž i onu operaci seřazení:

naive plan: (run LazyFrame.describe_optimized_plan() to see the optimized plan)
 
  SORT BY [col("Winner")]
    CSV SCAN hall_of_fame.csv
    PROJECT */2 COLUMNS

A konečně se po provedení operace collect realizují obě naplánované operace, tedy načtení dat ze souboru typu CSV a seřazení záznamů na základě obsahu sloupce „Winner“. Výsledkem těchto dvou operací je již běžný datový rámec s tímto obsahem:

shape: (20, 2)
┌──────┬──────────────┐
│ Year ┆ Winner       │
│ ---  ┆ ---          │
│ i64  ┆ str          │
╞══════╪══════════════╡
│ 2019 ┆ C            │
│ 2017 ┆ C            │
│ 2008 ┆ C            │
│ 2022 ┆ C++          │
│ ...  ┆ ...          │
│ 2010 ┆ Python       │
│ 2007 ┆ Python       │
│ 2006 ┆ Ruby         │
│ 2013 ┆ Transact-SQL │
└──────┴──────────────┘
 
['Year', 'Winner']
[Int64, Utf8]

8. Konstrukce plánu s větším množstvím operací; realizace plánu

Samotný plán postupně vytvářený pro líné datové rámce pochopitelně může obsahovat i větší množství operací a dokonce je ho možné i větvit. Nejdříve si ukažme, jak by vypadal plán se třemi operacemi:

  1. (Líné) načtení datového rámce
  2. Seřazení záznamů podle zvoleného sloupce
  3. Otočení pořadí všech záznamů

Tyto operace jsou postupně definovány v následujícím skriptu:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# líné přečtení zdrojových dat
df = polars.scan_csv("hall_of_fame.csv")
 
# zobrazíme líně načtený datový rámec
print(df)
print()
 
# aplikace operace na líný datový rámec
df2 = df.sort("Winner").reverse()
 
# převod na běžný datový rámec
df3 = df2.collect()
 
# zobrazíme druhý líny datový rámec
print(df2)
print()
 
# zobrazíme běžný (výsledný) datový rámec
print(df3)
print()
print(df3.columns)
print(df3.dtypes)
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu získáte na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame05_lazy_sort_rever­se.py.

Povšimněte si, jak se liší druhý plán od plánu z předchozího demonstračního příkladu – operace reverse je rozepsána na dvě paralelně probíhající operace:

naive plan: (run LazyFrame.describe_optimized_plan() to see the optimized plan)
 
  CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS
 
 
naive plan: (run LazyFrame.describe_optimized_plan() to see the optimized plan)
 
   LOCAL SELECT [col("Year").reverse(), col("Winner").reverse()] FROM
    SORT BY [col("Winner")]
      CSV SCAN hall_of_fame.csv
      PROJECT */2 COLUMNS
 
 
shape: (20, 2)
┌──────┬──────────────┐
│ Year ┆ Winner       │
│ ---  ┆ ---          │
│ i64  ┆ str          │
╞══════╪══════════════╡
│ 2013 ┆ Transact-SQL │
│ 2006 ┆ Ruby         │
│ 2007 ┆ Python       │
│ 2010 ┆ Python       │
│ ...  ┆ ...          │
│ 2022 ┆ C++          │
│ 2008 ┆ C            │
│ 2017 ┆ C            │
│ 2019 ┆ C            │
└──────┴──────────────┘
 
['Year', 'Winner']
[Int64, Utf8]

9. Větší množství naplánovaných operací

Počet operací postupně „líně“ aplikovaných na data není prakticky nijak omezen, takže ke dvojici operací scan_csv+sort můžeme velmi snadno přidat operaci další, například reverse. I tato operace bude do výsledného plánu přidána a vykonána později, pokud to bude explicitně požadováno:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# líné přečtení zdrojových dat
df = polars.scan_csv("hall_of_fame.csv")
 
# zobrazíme plán pro líně načtený datový rámec
print(df.describe_plan())
print(df.describe_optimized_plan())
print()
 
# aplikace operace na líný datový rámec
df2 = df.sort("Winner").reverse()
 
# převod na běžný datový rámec
df3 = df2.collect()
 
# zobrazíme plán pro druhý líny datový rámec
print(df2.describe_plan())
print(df2.describe_optimized_plan())
print()
 
# zobrazíme běžný (výsledný) datový rámec
print(df3)
print()
print(df3.columns)
print(df3.dtypes)
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu získáte na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame06_describe_plan.py.

Výsledkem činnosti tohoto skriptu bude plán obsahující operaci sort; výsledný datový rámec je pak složen ze dvou datových řad (series), jejichž prvky jsou explicitně otočeny. To je ostatně zajímavý koncept – sort je operace naplánovaná pro celý datový rámec zatímco reverse jako operace aplikované na jednotlivé sloupce:

  CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS
 
  CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS
 
 
   LOCAL SELECT [col("Year").reverse(), col("Winner").reverse()] FROM
    SORT BY [col("Winner")]
      CSV SCAN hall_of_fame.csv
      PROJECT */2 COLUMNS
 
   LOCAL SELECT [col("Year").reverse(), col("Winner").reverse()] FROM
    SORT BY [col("Winner")]
      CSV SCAN hall_of_fame.csv
      PROJECT */2 COLUMNS
 
 
shape: (20, 2)
┌──────┬──────────────┐
│ Year ┆ Winner       │
│ ---  ┆ ---          │
│ i64  ┆ str          │
╞══════╪══════════════╡
│ 2013 ┆ Transact-SQL │
│ 2006 ┆ Ruby         │
│ 2007 ┆ Python       │
│ 2010 ┆ Python       │
│ ...  ┆ ...          │
│ 2022 ┆ C++          │
│ 2008 ┆ C            │
│ 2017 ┆ C            │
│ 2019 ┆ C            │
└──────┴──────────────┘
 
['Year', 'Winner']
[Int64, Utf8]

10. Ladění naplánovaných operací s využitím omezeného objemu dat

Prozatím jsme při převodu líného datového rámce na běžný datový rámec používali metodu collect, která spustila všechny operace a posléze výsledek těchto operací zkonvertovala do běžného datového rámce. Namísto metody collect je však možné použít například i metodu fetch, které se předá požadovaný počet řádků ve výsledku. Tato metoda se používá například tehdy, pokud je nutné provést ladění celého skriptu a vstupní data jsou zbytečně objemná (ovšem přesný počet řádků ve výsledku není garantován – je pouze přibližný):

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# líné přečtení zdrojových dat
df = polars.scan_csv("hall_of_fame.csv")
 
# zobrazíme plán pro líně načtený datový rámec
print(df.describe_plan())
print()
 
# aplikace operace na líný datový rámec
df2 = df.sort("Winner").reverse()
 
# převod vybraných prvků na běžný datový rámec
df3 = df2.fetch(5)
 
# zobrazíme plán pro druhý líny datový rámec
print(df2.describe_plan())
print()
 
# zobrazíme běžný (výsledný) datový rámec
print(df3)
print()
print(df3.columns)
print(df3.dtypes)
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu získáte na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame07_fetch.py.

Výsledný plán je naprosto stejný, jako v předchozím příkladu:

  CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS
 
 
   LOCAL SELECT [col("Year").reverse(), col("Winner").reverse()] FROM
    SORT BY [col("Winner")]
      CSV SCAN hall_of_fame.csv
      PROJECT */2 COLUMNS

Liší se ovšem výsledná podoba získaného datového rámce, který bude obsahovat jen pět řádků (záznamů):

shape: (5, 2)
┌──────┬────────┐
│ Year ┆ Winner │
│ ---  ┆ ---    │
│ i64  ┆ str    │
╞══════╪════════╡
│ 2018 ┆ Python │
│ 2020 ┆ Python │
│ 2021 ┆ Python │
│ 2022 ┆ C++    │
│ 2019 ┆ C      │
└──────┴────────┘
 
['Year', 'Winner']
[Int64, Utf8]

11. Limity operace fetch při agregaci dat

Demonstrační příklad z předchozí kapitoly byl založen na operaci fetch, která z líného datového rámce přečetla v daném případě přesný počet řádků. Ovšem tak tomu nemusí být vždy. Podívejme se na následující skript, kde vyžadujeme přečtení pěti řádků, ovšem z líného datového rámce, který vznikl agregací dat:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# líné přečtení zdrojových dat
df = polars.scan_csv("hall_of_fame.csv")
 
# zobrazíme plán pro líně načtený datový rámec
print(df.describe_plan())
print()
 
# seskupení podle názvu jazyka
df2 = df.groupby("Winner", maintain_order=True).agg([polars.col("Year")])
 
# převod vybraných prvků na běžný datový rámec
df3 = df2.fetch(5)
 
# zobrazíme plán pro druhý líny datový rámec
print(df2.describe_plan())
print()
 
# zobrazíme běžný (výsledný) datový rámec
print(df3)
print()
print(df3.columns)
print(df3.dtypes)
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu získáte na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame08_group_by.py.

Za povšimnutí stojí v tomto případě nikoli vlastní plán, ale počet řádků uložených ve výsledném datovém rámci. Vrátí se tři řádky a nikoli pět řádků. Je tomu tak proto, že při agregaci se pracuje s pěti hodnotami „Year“, které jsou však agregovány do již zmíněných třech řádků:

  CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS
 
 
  Aggregate
        [col("Year")] BY [col("Winner")] FROM
          CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS
 
 
 
shape: (3, 2)
┌────────┬────────────────────┐
│ Winner ┆ Year               │
│ ---    ┆ ---                │
│ str    ┆ list[i64]          │
╞════════╪════════════════════╡
│ C++    ┆ [2022]             │
│ Python ┆ [2021, 2020, 2018] │
│ C      ┆ [2019]             │
└────────┴────────────────────┘
 
['Winner', 'Year']
[Utf8, List(Int64)]

12. Další snížení počtu řádků vracených operací fetch: zvýraznění nekorektních výsledků

Pro zajímavost se podívejme, jaká situace nastane ve chvíli, kdy ještě více snížíme počet operací pomocí fetch, a to konkrétně na pouhé dva záznamy. Nyní bude výsledný datový rámec získaný po provedení všech operací obsahovat dva řádky (což bychom mohli očekávat), ale navíc tyto řádky nebudou obsahovat všechny potřebné údaje:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# líné přečtení zdrojových dat
df = polars.scan_csv("hall_of_fame.csv")
 
# zobrazíme plán pro líně načtený datový rámec
print(df.describe_plan())
print()
 
# seskupení podle názvu jazyka
df2 = df.groupby("Winner", maintain_order=True).agg([polars.col("Year")])
 
# převod vybraných prvků na běžný datový rámec
df3 = df2.fetch(2)
 
# zobrazíme plán pro druhý líny datový rámec
print(df2.describe_plan())
print()
 
# zobrazíme běžný (výsledný) datový rámec
print(df3)
print()
print(df3.columns)
print(df3.dtypes)
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu získáte na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame09_group_by_fetch.py.

Nyní obsahuje výsledný datový rámec informaci o tom, že C++ vyhrál pouze v roce 2022 (a nikoli 2×) a Python v roce 2021 (a nikoli celkem 5×)! Už z těchto výsledků vyplývá, že fetch se skutečně hodí jen pro ladicí účely a nikoli pro „zkrácené“ výpočty s reálnými daty a očekávanými reálnými výsledky:

  CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS
 
 
  Aggregate
        [col("Year")] BY [col("Winner")] FROM
          CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS
 
 
 
shape: (2, 2)
┌────────┬───────────┐
│ Winner ┆ Year      │
│ ---    ┆ ---       │
│ str    ┆ list[i64] │
╞════════╪═══════════╡
│ C++    ┆ [2022]    │
│ Python ┆ [2021]    │
└────────┴───────────┘
 
['Winner', 'Year']
[Utf8, List(Int64)]

13. Operace head aplikovaná na líný rámec

Pokud skutečně vyžadujeme už v rámci líného vyhodnocování operací prováděných nad datovými rámci zmenšit množství dat ve zpracovávaných datových rámcích, musí se namísto poněkud problematické a neintuitivní (viz výše) operace fetch použít líná varianta operace head nebo tail. Tyto operace vrací nový líný rámec, takže pokud se má výsledek vytisknout či jiným způsobem zpracovat, musí následovat operace collect. Podívejme se na jednoduchý příklad:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# líné přečtení zdrojových dat
df = polars.scan_csv("hall_of_fame.csv")
 
# zobrazíme plán pro líně načtený datový rámec
print(df.describe_plan())
print()
 
# seskupení podle názvu jazyka
df2 = (
    df.groupby("Winner", maintain_order=True)
    .agg([polars.col("Year").len().alias("Zvítězil")])
    .sort("Zvítězil")
    .reverse()
    .head(5)
)
 
# převod prvků na běžný datový rámec
df3 = df2.collect()
 
# zobrazíme plán pro druhý líny datový rámec
print(df2.describe_plan())
print()
 
# zobrazíme běžný (výsledný) datový rámec
print(df3)
print()
print(df3.columns)
print(df3.dtypes)
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu získáte na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame10_group_by_len_sor­t_reverse_head.py.

Nyní je zajímavé se podívat na plán, který nově obsahuje operaci SLICE, která z líného datového rámce přečte pouze prvních pět záznamů:

  CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS
 
 
  SLICE[offset: 0, len: 5]
     LOCAL SELECT [col("Winner").reverse(), col("Zvítězil").reverse()] FROM
      SORT BY [col("Zvítězil")]
        Aggregate
                [col("Year").count().alias("Zvítězil")] BY [col("Winner")] FROM
                  CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS

A výsledný rámec bude vypadat takto:

shape: (5, 2)
┌─────────────┬──────────┐
│ Winner      ┆ Zvítězil │
│ ---         ┆ ---      │
│ str         ┆ u32      │
╞═════════════╪══════════╡
│ Python      ┆ 5        │
│ C           ┆ 3        │
│ Objective-C ┆ 2        │
│ Java        ┆ 2        │
│ Go          ┆ 2        │
└─────────────┴──────────┘
 
['Winner', 'Zvítězil']
[Utf8, UInt32]

Operace head a tail je možné zřetězit, ale zajímavé je, že nedojde k optimalizaci těchto operací do jediné operace SLICE (alespoň ne v současné variantě knihovny Polars):

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# líné přečtení zdrojových dat
df = polars.scan_csv("hall_of_fame.csv")
 
# zobrazíme plán pro líně načtený datový rámec
print(df.describe_plan())
print()
 
# seskupení podle názvu jazyka
df2 = (
    df.groupby("Winner", maintain_order=True)
    .agg([polars.col("Year").len().alias("Zvítězil")])
    .sort("Zvítězil")
    .reverse()
    .head(10)
    .tail(5)
)
 
# převod prvků na běžný datový rámec
df3 = df2.collect()
 
# zobrazíme plán pro druhý líny datový rámec
print(df2.describe_plan())
print(df2.describe_optimized_plan())
print()
 
# zobrazíme běžný (výsledný) datový rámec
print(df3)
print()
print(df3.columns)
print(df3.dtypes)

S výsledky:

  CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS
 
 
  SLICE[offset: -5, len: 5]
    SLICE[offset: 0, len: 10]
       LOCAL SELECT [col("Winner").reverse(), col("Zvítězil").reverse()] FROM
        SORT BY [col("Zvítězil")]
          Aggregate
                [col("Year").count().alias("Zvítězil")] BY [col("Winner")] FROM
                  CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS
 
 
  SLICE[offset: -5, len: 5]
    SLICE[offset: 0, len: 10]
       LOCAL SELECT [col("Winner").reverse(), col("Zvítězil").reverse()] FROM
        SORT BY [col("Zvítězil")]
          Aggregate
                [col("Year").count().alias("Zvítězil")] BY [col("Winner")] FROM
                  CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS
 
 
 
shape: (5, 2)
┌──────────────┬──────────┐
│ Winner       ┆ Zvítězil │
│ ---          ┆ ---      │
│ str          ┆ u32      │
╞══════════════╪══════════╡
│ C++          ┆ 2        │
│ PHP          ┆ 1        │
│ Ruby         ┆ 1        │
│ Transact-SQL ┆ 1        │
│ JavaScript   ┆ 1        │
└──────────────┴──────────┘

['Winner', 'Zvítězil']
[Utf8, UInt32]

14. Rozvětvení a opětovné spojení plánů

V předchozím textu jsme si řekli, že může dojít k rozvětvení plánů (z líného datového rámce je odvozeno více nových datových rámců aplikací nějaké operace) nebo dokonce i ke spojení plánů. A právě tyto situace si otestujeme v dnešním posledním demonstračním příkladu, v němž z jediného zdrojového datového rámce df1 aplikací různých operací odvodíme plány df2, df3, df4 a df5. A nakonec tyto odvozené líné datové rámce opět spojíme operací concat (tu jsme si sice ještě nepopisovali, ale v našem případě dojde ke spojení rámců „pod sebou“, protože všechny datové rámce mají stejné typy i názvy sloupců):

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# líné přečtení zdrojových dat
df1 = polars.scan_csv("hall_of_fame.csv")
 
# seřazení podle zvoleného sloupce
df2 = df1.sort("Year")
 
# seřazení podle zvoleného sloupce
df3 = df1.sort("Year").reverse()
 
# seskupení podle názvu jazyka
df4 = (
    df2.groupby("Winner", maintain_order=True)
    .agg([polars.col("Year").len().alias("Zvítězil")])
    .sort("Zvítězil")
)
 
# otočení prvků + získání pěti výsledků
df5 = df4.reverse().head(5)
 
# spojení několika datových rámců - spojení plánů
df6 = polars.concat([df2, df3, df4, df5], how="vertical")
 
# zobrazíme plány pro všechny líné datové rámce
print("df1")
print(df1.describe_plan())
print()
 
print("df2")
print(df2.describe_plan())
print()
 
print("df3")
print(df3.describe_plan())
print()
 
print("df4")
print(df4.describe_plan())
print()
 
print("df5")
print(df5.describe_plan())
print()
 
print("df6")
print(df6.describe_plan())
print()

Po spuštění tohoto skriptu se všechny plány postupně vypíšou:

df1
  CSV SCAN hall_of_fame.csv
  PROJECT */2 COLUMNS
 
 
df2
  SORT BY [col("Year")]
    CSV SCAN hall_of_fame.csv
    PROJECT */2 COLUMNS
 
 
df3
   LOCAL SELECT [col("Year").reverse(), col("Winner").reverse()] FROM
    SORT BY [col("Year")]
      CSV SCAN hall_of_fame.csv
      PROJECT */2 COLUMNS
 
 
df4
  SORT BY [col("Zvítězil")]
    Aggregate
        [col("Year").count().alias("Zvítězil")] BY [col("Winner")] FROM
          SORT BY [col("Year")]
    CSV SCAN hall_of_fame.csv
    PROJECT */2 COLUMNS
 
 
df5
  SLICE[offset: 0, len: 5]
     LOCAL SELECT [col("Winner").reverse(), col("Zvítězil").reverse()] FROM
      SORT BY [col("Zvítězil")]
        Aggregate
                [col("Year").count().alias("Zvítězil")] BY [col("Winner")] FROM
                  SORT BY [col("Year")]
    CSV SCAN hall_of_fame.csv
    PROJECT */2 COLUMNS

Za povšimnutí stojí především poslední plán pro líný datový rámec df6, protože tento plán vznikl sloučením (union) všech předchozích plánů, což je z výsledku patrné:

df6
  RECHUNK
    UNION:
    PLAN 0:
      SORT BY [col("Year")]
        CSV SCAN hall_of_fame.csv
        PROJECT */2 COLUMNS
    PLAN 1:
       LOCAL SELECT [col("Year").reverse(), col("Winner").reverse()] FROM
        SORT BY [col("Year")]
          CSV SCAN hall_of_fame.csv
          PROJECT */2 COLUMNS
    PLAN 2:
      SORT BY [col("Zvítězil")]
        Aggregate
                [col("Year").count().alias("Zvítězil")] BY [col("Winner")] FROM
                  SORT BY [col("Year")]
    CSV SCAN hall_of_fame.csv
    PROJECT */2 COLUMNS
 
    PLAN 3:
      SLICE[offset: 0, len: 5]
         LOCAL SELECT [col("Winner").reverse(), col("Zvítězil").reverse()] FROM
          SORT BY [col("Zvítězil")]
            Aggregate
                [col("Year").count().alias("Zvítězil")] BY [col("Winner")] FROM
                  SORT BY [col("Year")]
    CSV SCAN hall_of_fame.csv
    PROJECT */2 COLUMNS
 
    END UNION

15. Vizualizace plánu

Namísto metody describe_plan je možné plány operací nad líným datovým rámcem zobrazit (resp. přesněji řečeno vizualizovat) metodou show_graph. Pro tuto operaci je nutné mít nainstalovánu knihovnu Matplotlib. Skript z předchozí kapitoly nepatrně upravíme takovým způsobem, že namísto tisku plánů na terminál je zobrazíme v grafickém okně:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# líné přečtení zdrojových dat
df1 = polars.scan_csv("hall_of_fame.csv")
 
# seřazení podle zvoleného sloupce
df2 = df1.sort("Year")
 
# seřazení podle zvoleného sloupce
df3 = df1.sort("Year").reverse()
 
# seskupení podle názvu jazyka
df4 = (
    df2.groupby("Winner", maintain_order=True)
    .agg([polars.col("Year").len().alias("Zvítězil")])
    .sort("Zvítězil")
)
 
# otočení prvků + získání pěti výsledků
df5 = df4.reverse().head(5)
 
# spojení několika datových rámců - spojení plánů
df6 = polars.concat([df2, df3, df4, df5], how="vertical")
 
# zobrazíme plány pro všechny líné datové rámce
# v grafické podobě
df1.show_graph()
df2.show_graph()
df3.show_graph()
df4.show_graph()
df5.show_graph()
df6.show_graph()

Vizualizované výsledky vypadají následovně:

Obrázek 1: Vizualizovaný plán pro datový rámec #1.

Obrázek 2: Vizualizovaný plán pro datový rámec #2.

Obrázek 3: Vizualizovaný plán pro datový rámec #3.

Obrázek 4: Vizualizovaný plán pro datový rámec #4.

Obrázek 5: Vizualizovaný plán pro datový rámec #5.

Obrázek 6: Vizualizovaný plán pro datový rámec #5.

16. Vizualizace plánu s operacemi SLICE

Na závěr si ukažme, jak vypadá vizualizovaný plán, v němž jsou použity operace SLICE:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import polars
 
# líné přečtení zdrojových dat
df = polars.scan_csv("hall_of_fame.csv")
 
# zobrazíme plán pro líně načtený datový rámec
print(df.describe_plan())
print()
 
# seskupení podle názvu jazyka
df2 = (
    df.groupby("Winner", maintain_order=True)
    .agg([polars.col("Year").len().alias("Zvítězil")])
    .sort("Zvítězil")
    .reverse()
    .head(10)
    .tail(5)
)
 
# zobrazíme plán pro druhý líny datový rámec
# v grafické podobě
df2.show_graph()

V tomto případě by se měl zobrazit tento diagram:

Obrázek 7: Vizualizovaný plán pro výsledný líný datový rámec.

ict ve školství 24

17. Obsah závěrečné části seriálu o knihovně Polars

Ve čtvrté a současně i poslední části miniseriálu o knihovně Pandas se budeme zabývat velmi častou operací – spojením dvou (nebo i v případě potřeby většího množství) datových rámců. V knihovně Polars je možné rámce spojit jak „po řádcích“, tak i „po sloupcích“ a popř. i vyřešit splynutí hodnot z těch sloupců, které si logicky odpovídají. To však není vše, protože lze provést i operace typu join (což je jméno převzaté ze SQL). K dispozici je vnitřní join, levý join, pravý join i vnější join.

Poznámka: mnohé z těchto operací probíhají odlišným způsobem, než je tomu v knihovně Pandas a to z jednoho prostého důvodu – Polars totiž (alespoň prozatím) nepodporuje převod jednoho či většího množství sloupců na indexy. V této knihovně je tedy každému záznamu přiřazen celočíselný index odpovídající pořadí záznamu v datovém rámci. Při spojování je tudíž nutné namísto indexů explicitně specifikovat sloupce obsahující odpovídající si hodnoty.

18. Repositář s demonstračními příklady

Zdrojové kódy všech prozatím popsaných demonstračních příkladů určených pro programovací jazyk Python 3 (nikoli ovšem pro starší verze Pythonu 2!) byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/most-popular-python-libs. V případě, že nebudete chtít klonovat celý repositář (ten je ovšem stále velmi malý, dnes má velikost zhruba několik desítek kilobajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:

# Demonstrační příklad Stručný popis příkladu Cesta
1 series01_from_list.py konstrukce datové řady ze seznamu https://github.com/tisnik/most-popular-python-libs/blob/master/polars/se­ries01_from_list.py
2 series02_from_tuple.py konstrukce datové řady z n-tice https://github.com/tisnik/most-popular-python-libs/blob/master/polars/se­ries02_from_tuple.py
3 series03_from_range.py konstrukce datové řady generátorem range https://github.com/tisnik/most-popular-python-libs/blob/master/polars/se­ries03_from_range.py
4 series04_from_other_type.py použití odlišných datových typů prvků v datové řadě https://github.com/tisnik/most-popular-python-libs/blob/master/polars/se­ries04_from_other_type.py
5 series05_strings.py datová řada obsahující řetězce https://github.com/tisnik/most-popular-python-libs/blob/master/polars/se­ries05_strings.py
6 series06_booleans.py datová řada obsahující pravdivostní hodnoty https://github.com/tisnik/most-popular-python-libs/blob/master/polars/se­ries06_booleans.py
7 series07_null_value.py datová řada obsahující prvky s hodnotou null https://github.com/tisnik/most-popular-python-libs/blob/master/polars/se­ries07_null_value.py
8 series08_type_specification.py explicitní specifikace datového typu https://github.com/tisnik/most-popular-python-libs/blob/master/polars/se­ries08_type_specification­.py
9 series09_select.py výběr prvků z datové řady pomocí indexu, indexů či řezu https://github.com/tisnik/most-popular-python-libs/blob/master/polars/se­ries09_select.py
10 series10_filter.py výběr prvků z datové řady pomocí filtru (podmínky) https://github.com/tisnik/most-popular-python-libs/blob/master/polars/se­ries10_filter.py
11 series11_from_arange.py konstrukce datové řady s využitím numpy.arange https://github.com/tisnik/most-popular-python-libs/blob/master/polars/se­ries11_from_arange.py
12 series12_from_linspace.py konstrukce datové řady s využitím numpy.linspace https://github.com/tisnik/most-popular-python-libs/blob/master/polars/se­ries12_from_linspace.py
       
13 data_frame01_load_csv.py načtení dat ze souboru typu CSV https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame01_load_csv.py
14 data_frame02_load_csv_no_header_A.py práce se soubory typu CSV bez hlavičky (nekorektní varianta) https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame02_load_csv_no_he­ader_A.py
15 data_frame03_load_csv_no_header_B.py práce se soubory typu CSV bez hlavičky (korektní varianta) https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame03_load_csv_no_he­ader_B.py
16 data_frame04_load_csv_no_header_C.py práce se soubory typu CSV bez hlavičky (korektní varianta s explicitními jmény sloupců) https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame04_load_csv_no_he­ader_B.py
17 data_frame05_load_tsv_A.py práce se soubory typu TSV (nekorektní varianta) https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame05_load_tsv_A.py
18 data_frame06_load_tsv_B.py práce se soubory typu TSV (korektní varianta) https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame06_load_tsv_B.py
19 data_frame07_describe.py získání metainformací o datovém rámci https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame07_describe.py
20 data_frame08_timestamps_A.py načtení dat obsahujících časová razítka https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame08_timestamps_A.py
21 data_frame09_timestamps_B.py načtení dat obsahujících časová razítka https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame09_timestamps_B.py
22 data_frame10_load_sql_A.py načtení dat z relační databáze s uložením výsledku ve formě datového rámce https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame10_load_sql_A.py
23 data_frame11_load_sql_B.py načtení dat z relační databáze s uložením výsledku ve formě datového rámce https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame11_load_sql_B.py
       
24 data_frame12_head_A.py zobrazení hlavičky datového rámce https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame12_head_A.py
25 data_frame13_head_B.py zobrazení hlavičky datového rámce se specifikací počtu řádků https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame13_head_B.py
26 data_frame14_head_C.py globální změna počtu zobrazených řádků u datového rámce https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame14_head_C.py
27 data_frame15_formatting_A.py různé způsoby naformátování obsahu datových rámců https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame15_formatting_A.py
28 data_frame16_formatting_B.py různé způsoby naformátování obsahu datových rámců https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame16_formatting_B.py
29 data_frame17_sort.py seřazení údajů v datovém rámci https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame17_sort.py
30 data_frame18_sort_reverse.py zpětné seřazení údajů v datovém rámci https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame18_sort_reverse.py
31 data_frame19_unique.py zajištění unikátnosti záznamů https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame19_unique.py
32 data_frame20_map_conversion.py konverze dat ve sloupci s využitím metody map https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame20_map_conversion­.py
33 data_frame21_apply_conversion.py konverze dat ve sloupci s využitím metody apply https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame21_apply_conversi­on.py
34 data_frame22_group_by.py seskupení údajů na základě zvoleného sloupce https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame22_group_by.py
35 data_frame23_group_by_sort.py seskupení a seřazení údajů při agregaci na základě hodnot ve zvoleném sloupci https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame23_group_by_sort.py
36 data_frame23_group_by_sort_B.py ukázka rozdílů mezi použitím a nepoužitím sort při agregaci https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame23_group_by_sort_B­.py
37 data_frame24_sort_group_by_sort.py kombinace sort a groupby https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame24_sort_group_by_sor­t.py
38 data_frame25_group_by_len.py jednoduchá agregace údajů při seskupení https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame25_group_by_len.py
39 data_frame26_group_by_len_sort.py jednoduchá agregace údajů při seskupení, kombinace se seřazením https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame26_group_by_len_sor­t.py
40 data_frame27_group_by_len_sor­t_reverse.py jednoduchá agregace údajů při seskupení, kombinace se seřazením https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame27_group_by_len_sor­t_reverse.py
41 data_frame28_group_by_len_sor­t_reverse_head.py kombinace předchozího s head https://github.com/tisnik/most-popular-python-libs/blob/master/polars/da­ta_frame28_group_by_len_sor­t_reverse_head.py
       
42 lazy_frame01_scan_csv.py líné načtení dat ze souboru typu CSV https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame01_scan_csv.py
43 lazy_frame02_read_csv_and_convert.py načtení dat ze souboru typu CSV do datového rámce a konverze na líný datový rámec https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame02_read_csv_and_con­vert.py
44 lazy_frame03_collect_to_df.py převod líného datového rámce na běžný datový rámec https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame03_collect_to_df.py
45 lazy_frame04_lazy_sort.py operace sort aplikovaná líně https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame04_lazy_sort.py
46 lazy_frame05_lazy_sort_reverse.py dvojice operací sort + reverse, taktéž aplikovaných líně https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame05_lazy_sort_rever­se.py
47 lazy_frame06_describe_plan.py zobrazení informací o plánovaných operacích https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame06_describe_plan.py
48 lazy_frame07_fetch.py přečtení výseku dat z líného datového rámce https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame07_fetch.py
49 lazy_frame08_group_by.py operace groupby následovaná agregací pro líný datový rámec https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame08_group_by.py
50 lazy_frame09_group_by_fetch2.py zjištění, jak vlastně přesně pracuje operace fetch https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame09_group_by_fetch.py
51 lazy_frame10_group_by_len_sor­t_reverse_head.py „pipeline“ operací aplikovaných na líný datový rámec https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame10_group_by_len_sor­t_reverse_head.py
52 lazy_frame11_branching.py rozvětvení plánů https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame11_branching.py
53 lazy_frame12_visualization.py vizualizace plánů https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame12_visualization.py
54 lazy_frame13_head_tail.py kombinace operací head a tail https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame13_head_tail.py
55 lazy_frame14_head_tail_vi­sualization.py kombinace operací head a tail, vizualizace výsledného plánu https://github.com/tisnik/most-popular-python-libs/blob/master/polars/la­zy_frame14_head_tail_visu­alization.py

19. Odkazy na Internetu

  1. Projekt Polars na GitHubu
    https://github.com/pola-rs/polars
  2. Dokumentace k projektu Polars (popis API)
    https://pola-rs.github.io/polars/py-polars/html/reference/index.html
  3. Polars: The Next Big Python Data Science Library… written in RUST?
    https://www.youtube.com/wat­ch?v=VHqn7ufiilE
  4. Polars API: funkce pro načtení datového rámce z CSV
    https://pola-rs.github.io/polars/py-polars/html/reference/api/po­lars.read_csv.html
  5. Polars API: funkce pro načtení datového rámce z relační databáze
    https://pola-rs.github.io/polars/py-polars/html/reference/api/po­lars.read_sql.html
  6. Python’s Pandas vs Polars: Who Wins this Fight in Library 
    https://analyticsindiamag.com/pythons-pandas-vs-polars-who-wins-this-fight-in-library/
  7. Polars vs Pandas: what is more convenient?
    https://medium.com/@ilia.oz­hmegov/polars-vs-pandas-what-is-more-convenient-331956742a69
  8. A Gentle Introduction to Pandas Data Analysis (on Kaggle)
    https://www.youtube.com/wat­ch?v=_Eb0utIRdkw&list=PL7RwtdVQXQ8o­YpuIIDWR0SaaSCe8ZeZ7t&index=4
  9. Speed Up Your Pandas Dataframes
    https://www.youtube.com/wat­ch?v=u4_c2LDi4b8&list=PL7RwtdVQXQ8o­YpuIIDWR0SaaSCe8ZeZ7t&index=5
  10. pandas.read_csv
    https://pandas.pydata.org/pandas-docs/stable/reference/api/pan­das.read_csv.html
  11. How to define format when using pandas to_datetime?
    https://stackoverflow.com/qu­estions/36848514/how-to-define-format-when-using-pandas-to-datetime
  12. Pandas : skip rows while reading csv file to a Dataframe using read_csv() in Python
    https://thispointer.com/pandas-skip-rows-while-reading-csv-file-to-a-dataframe-using-read_csv-in-python/
  13. Skip rows during csv import pandas
    https://stackoverflow.com/qu­estions/20637439/skip-rows-during-csv-import-pandas
  14. Denni kurz
    https://www.cnb.cz/cs/finan­cni_trhy/devizovy_trh/kur­zy_devizoveho_trhu/denni_kur­z.txt
  15. UUID objects according to RFC 4122 (knihovna pro Python)
    https://docs.python.org/3­.5/library/uuid.html#uuid­.uuid4
  16. Object identifier (Wikipedia)
    https://en.wikipedia.org/wi­ki/Object_identifier
  17. Digital object identifier (Wikipedia)
    https://en.wikipedia.org/wi­ki/Digital_object_identifi­er
  18. voluptuous na (na PyPi)
    https://pypi.python.org/py­pi/voluptuous
  19. Repositář knihovny voluptuous na GitHubu
    https://github.com/alectho­mas/voluptuous
  20. pytest-voluptuous 1.0.2 (na PyPi)
    https://pypi.org/project/pytest-voluptuous/
  21. pytest-voluptuous (na GitHubu)
    https://github.com/F-Secure/pytest-voluptuous
  22. schemagic 0.9.1 (na PyPi)
    https://pypi.python.org/py­pi/schemagic/0.9.1
  23. Schemagic / Schemagic.web (na GitHubu)
    https://github.com/Mechrop­hile/schemagic
  24. schema 0.6.7 (na PyPi)
    https://pypi.python.org/pypi/schema
  25. schema (na GitHubu)
    https://github.com/keleshev/schema
  26. KX v DBOps Benchmark Results by Ferenc Bodon
    https://community.kx.com/t5/Community-Blogs/KX-v-DBOps-Benchmark-Results-by-Ferenc-Bodon/ba-p/12182
  27. TIOBE Index for January 2023
    https://www.tiobe.com/tiobe-index/
  28. Lazy evaluation
    https://en.wikipedia.org/wi­ki/Lazy_evaluation
Seriál: Knihovna Pandas

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.