Obsah
1. Knihovna Polars: problematika spojování datových rámců
2. Vertikální spojení datových rámců
3. Spojení datových rámců po řádcích funkcí concat
4. Explicitní specifikace vertikálního spojení ve funkci concat
5. Horizontální spojení datových rámců
6. První (nefunkční) skript pro vertikální spojení datových rámců
7. Explicitní výběr sloupců z druhého datového rámce pro operaci spojení
8. Spojení dvou datových rámců operací typu join
9. Datové soubory použité v příkladech ukazujících operaci join
10. Realizace operace inner join (vnitřního spojení)
11. Left join (vnější spojení „zleva“)
12. Outer join (vnější spojení)
13. Křížové spojení (kartézský součin)
14. Ukázka realizace kartézského součinu pro datové rámce s pěti a čtyřmi záznamy
15. Kartézský součin pro datové rámce použité v předchozích příkladech
19. Repositář s demonstračními příklady
1. Knihovna Polars: problematika spojování datových rámců
Před vlastní datovou analýzou či před statistickým zpracováním dat s využitím knihovny Polars je v mnoha případech nutné data nejdříve získat z několika samostatných zdrojů. Vzhledem k tomu, že většina operací (transformace, selekce, filtrace, seskupení, agregace) probíhá nad jediným datovým rámcem, je zapotřebí datové rámce se zdrojovými daty nějakým způsobem spojit. A právě těmito mnohdy relativně složitými operacemi, mezi něž se řadí i různé varianty operace join, se budeme zabývat v dnešním článku o knihovně Polars, jenž je současně i článkem závěrečným.
2. Vertikální spojení datových rámců
V knihovně Polars je možné datové 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í. Nejdříve si ukážeme, jakým způsobem je možné spojit dva datové rámce „po řádcích“. K tomu využijeme datové soubory tiobeC.tsv a tiobeD.tsv.
První z těchto souborů tiobeC.tsv obsahuje horní polovinu tabulky, konkrétně prvních deset řádků a současně i hlavičku sloupců:
Sep 2020 Sep 2019 Change Language Ratings Changep 1 2 change C 15.95 +0.74 2 1 change Java 13.48 -3.18 3 3 Python 10.47 +0.59 4 4 C++ 7.11 +1.48 5 5 C# 4.58 +1.18 6 6 Visual Basic 4.12 +0.83 7 7 JavaScript 2.54 +0.41 8 9 change PHP 2.49 +0.62 9 19 change R 2.37 +1.33 10 8 change SQL 1.76 -0.19
Druhý soubor tiobeD.tsv taktéž obsahuje hlavičky sloupců a dále spodní polovinu tabulky, tedy dolních dvacet řádků:
Sep 2020 Sep 2019 Change Language Ratings Changep 11 14 change Go 1.46 +0.24 12 16 change Swift 1.38 +0.28 13 20 change Perl 1.30 +0.26 14 12 change Assembly language 1.30 -0.08 15 15 Ruby 1.24 +0.03 16 18 change MATLAB 1.10 +0.04 17 11 change Groovy 0.99 -0.52 18 33 change Rust 0.92 +0.55 19 10 change Objective-C 0.85 -0.99 20 24 change Dart 0.77 +0.13
3. Spojení datových rámců po řádcích funkcí concat
Spojení dvou nebo i většího množství datových rámců nabízí funkce nazvaná concat, která je aplikovatelná pro libovolný počet instancí třídy DataFrame. Tato funkce dokáže datové rámce spojit buď po sloupcích nebo po řádcích, a to v závislosti na hodnotě parametru how, který by měl obsahovat hodnotu „horizontal“ nebo „vertical“ (popř. nebýt vůbec uveden):
Vyzkoušejme si nejprve použití této funkce s neuvedením typu spojení:
#!/usr/bin/env python3 # vim: set fileencoding=utf-8 import polars # maximální počet zobrazených řádků polars.Config.set_tbl_rows(100) # přečtení zdrojových dat df1 = polars.read_csv("tiobeC.tsv", sep="\t") df2 = polars.read_csv("tiobeD.tsv", sep="\t") # datové rámce zobrazíme print(df1) print() print(df2) print() # spojení obou datových rámců # bez uvedení parametru „how“ concatenated = polars.concat([df1, df2]) # výpis výsledku print(concatenated)
Výsledkem činnosti tohoto skriptu bude skutečně nový datový rámec, který vznikne spojením obou zdrojových datových rámců. Skript nejdříve vypíše obsah obou zdrojových rámců a pak i rámec cílový:
shape: (10, 6) ┌──────────┬──────────┬────────┬──────────────┬─────────┬─────────┐ │ Sep 2020 ┆ Sep 2019 ┆ Change ┆ Language ┆ Ratings ┆ Changep │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ str ┆ str ┆ f64 ┆ f64 │ ╞══════════╪══════════╪════════╪══════════════╪═════════╪═════════╡ │ 1 ┆ 2 ┆ change ┆ C ┆ 15.95 ┆ 0.74 │ │ 2 ┆ 1 ┆ change ┆ Java ┆ 13.48 ┆ -3.18 │ │ 3 ┆ 3 ┆ null ┆ Python ┆ 10.47 ┆ 0.59 │ │ 4 ┆ 4 ┆ null ┆ C++ ┆ 7.11 ┆ 1.48 │ │ 5 ┆ 5 ┆ null ┆ C# ┆ 4.58 ┆ 1.18 │ │ 6 ┆ 6 ┆ null ┆ Visual Basic ┆ 4.12 ┆ 0.83 │ │ 7 ┆ 7 ┆ null ┆ JavaScript ┆ 2.54 ┆ 0.41 │ │ 8 ┆ 9 ┆ change ┆ PHP ┆ 2.49 ┆ 0.62 │ │ 9 ┆ 19 ┆ change ┆ R ┆ 2.37 ┆ 1.33 │ │ 10 ┆ 8 ┆ change ┆ SQL ┆ 1.76 ┆ -0.19 │ └──────────┴──────────┴────────┴──────────────┴─────────┴─────────┘ shape: (10, 6) ┌──────────┬──────────┬────────┬───────────────────┬─────────┬─────────┐ │ Sep 2020 ┆ Sep 2019 ┆ Change ┆ Language ┆ Ratings ┆ Changep │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ str ┆ str ┆ f64 ┆ f64 │ ╞══════════╪══════════╪════════╪═══════════════════╪═════════╪═════════╡ │ 11 ┆ 14 ┆ change ┆ Go ┆ 1.46 ┆ 0.24 │ │ 12 ┆ 16 ┆ change ┆ Swift ┆ 1.38 ┆ 0.28 │ │ 13 ┆ 20 ┆ change ┆ Perl ┆ 1.3 ┆ 0.26 │ │ 14 ┆ 12 ┆ change ┆ Assembly language ┆ 1.3 ┆ -0.08 │ │ 15 ┆ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ 0.03 │ │ 16 ┆ 18 ┆ change ┆ MATLAB ┆ 1.1 ┆ 0.04 │ │ 17 ┆ 11 ┆ change ┆ Groovy ┆ 0.99 ┆ -0.52 │ │ 18 ┆ 33 ┆ change ┆ Rust ┆ 0.92 ┆ 0.55 │ │ 19 ┆ 10 ┆ change ┆ Objective-C ┆ 0.85 ┆ -0.99 │ │ 20 ┆ 24 ┆ change ┆ Dart ┆ 0.77 ┆ 0.13 │ └──────────┴──────────┴────────┴───────────────────┴─────────┴─────────┘ shape: (20, 6) ┌──────────┬──────────┬────────┬───────────────────┬─────────┬─────────┐ │ Sep 2020 ┆ Sep 2019 ┆ Change ┆ Language ┆ Ratings ┆ Changep │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ str ┆ str ┆ f64 ┆ f64 │ ╞══════════╪══════════╪════════╪═══════════════════╪═════════╪═════════╡ │ 1 ┆ 2 ┆ change ┆ C ┆ 15.95 ┆ 0.74 │ │ 2 ┆ 1 ┆ change ┆ Java ┆ 13.48 ┆ -3.18 │ │ 3 ┆ 3 ┆ null ┆ Python ┆ 10.47 ┆ 0.59 │ │ 4 ┆ 4 ┆ null ┆ C++ ┆ 7.11 ┆ 1.48 │ │ 5 ┆ 5 ┆ null ┆ C# ┆ 4.58 ┆ 1.18 │ │ 6 ┆ 6 ┆ null ┆ Visual Basic ┆ 4.12 ┆ 0.83 │ │ 7 ┆ 7 ┆ null ┆ JavaScript ┆ 2.54 ┆ 0.41 │ │ 8 ┆ 9 ┆ change ┆ PHP ┆ 2.49 ┆ 0.62 │ │ 9 ┆ 19 ┆ change ┆ R ┆ 2.37 ┆ 1.33 │ │ 10 ┆ 8 ┆ change ┆ SQL ┆ 1.76 ┆ -0.19 │ │ 11 ┆ 14 ┆ change ┆ Go ┆ 1.46 ┆ 0.24 │ │ 12 ┆ 16 ┆ change ┆ Swift ┆ 1.38 ┆ 0.28 │ │ 13 ┆ 20 ┆ change ┆ Perl ┆ 1.3 ┆ 0.26 │ │ 14 ┆ 12 ┆ change ┆ Assembly language ┆ 1.3 ┆ -0.08 │ │ 15 ┆ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ 0.03 │ │ 16 ┆ 18 ┆ change ┆ MATLAB ┆ 1.1 ┆ 0.04 │ │ 17 ┆ 11 ┆ change ┆ Groovy ┆ 0.99 ┆ -0.52 │ │ 18 ┆ 33 ┆ change ┆ Rust ┆ 0.92 ┆ 0.55 │ │ 19 ┆ 10 ┆ change ┆ Objective-C ┆ 0.85 ┆ -0.99 │ │ 20 ┆ 24 ┆ change ┆ Dart ┆ 0.77 ┆ 0.13 │ └──────────┴──────────┴────────┴───────────────────┴─────────┴─────────┘
4. Explicitní specifikace vertikálního spojení ve funkci concat
Vzhledem k tomu, že funkce concat dokáže rámce spojit jak po řádcích, tak i po sloupcích, je vhodné vždy uvádět (nepovinný) parametr how a nastavit ho na hodnotu „vertical“ (po řádcích) nebo „horizontal“ (po sloupcích):
#!/usr/bin/env python3 # vim: set fileencoding=utf-8 import polars # maximální počet zobrazených řádků polars.Config.set_tbl_rows(100) # přečtení zdrojových dat df1 = polars.read_csv("tiobeC.tsv", sep="\t") df2 = polars.read_csv("tiobeD.tsv", sep="\t") # datové rámce zobrazíme print(df1) print() print(df2) print() # spojení obou datových rámců concatenated = polars.concat([df1, df2], how="vertical") # výpis výsledku print(concatenated)
Výsledek by měl být totožný s předchozím demonstračním příkladem:
shape: (10, 6) ┌──────────┬──────────┬────────┬──────────────┬─────────┬─────────┐ │ Sep 2020 ┆ Sep 2019 ┆ Change ┆ Language ┆ Ratings ┆ Changep │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ str ┆ str ┆ f64 ┆ f64 │ ╞══════════╪══════════╪════════╪══════════════╪═════════╪═════════╡ │ 1 ┆ 2 ┆ change ┆ C ┆ 15.95 ┆ 0.74 │ │ 2 ┆ 1 ┆ change ┆ Java ┆ 13.48 ┆ -3.18 │ │ 3 ┆ 3 ┆ null ┆ Python ┆ 10.47 ┆ 0.59 │ │ 4 ┆ 4 ┆ null ┆ C++ ┆ 7.11 ┆ 1.48 │ │ 5 ┆ 5 ┆ null ┆ C# ┆ 4.58 ┆ 1.18 │ │ 6 ┆ 6 ┆ null ┆ Visual Basic ┆ 4.12 ┆ 0.83 │ │ 7 ┆ 7 ┆ null ┆ JavaScript ┆ 2.54 ┆ 0.41 │ │ 8 ┆ 9 ┆ change ┆ PHP ┆ 2.49 ┆ 0.62 │ │ 9 ┆ 19 ┆ change ┆ R ┆ 2.37 ┆ 1.33 │ │ 10 ┆ 8 ┆ change ┆ SQL ┆ 1.76 ┆ -0.19 │ └──────────┴──────────┴────────┴──────────────┴─────────┴─────────┘ shape: (10, 6) ┌──────────┬──────────┬────────┬───────────────────┬─────────┬─────────┐ │ Sep 2020 ┆ Sep 2019 ┆ Change ┆ Language ┆ Ratings ┆ Changep │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ str ┆ str ┆ f64 ┆ f64 │ ╞══════════╪══════════╪════════╪═══════════════════╪═════════╪═════════╡ │ 11 ┆ 14 ┆ change ┆ Go ┆ 1.46 ┆ 0.24 │ │ 12 ┆ 16 ┆ change ┆ Swift ┆ 1.38 ┆ 0.28 │ │ 13 ┆ 20 ┆ change ┆ Perl ┆ 1.3 ┆ 0.26 │ │ 14 ┆ 12 ┆ change ┆ Assembly language ┆ 1.3 ┆ -0.08 │ │ 15 ┆ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ 0.03 │ │ 16 ┆ 18 ┆ change ┆ MATLAB ┆ 1.1 ┆ 0.04 │ │ 17 ┆ 11 ┆ change ┆ Groovy ┆ 0.99 ┆ -0.52 │ │ 18 ┆ 33 ┆ change ┆ Rust ┆ 0.92 ┆ 0.55 │ │ 19 ┆ 10 ┆ change ┆ Objective-C ┆ 0.85 ┆ -0.99 │ │ 20 ┆ 24 ┆ change ┆ Dart ┆ 0.77 ┆ 0.13 │ └──────────┴──────────┴────────┴───────────────────┴─────────┴─────────┘ shape: (20, 6) ┌──────────┬──────────┬────────┬───────────────────┬─────────┬─────────┐ │ Sep 2020 ┆ Sep 2019 ┆ Change ┆ Language ┆ Ratings ┆ Changep │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ str ┆ str ┆ f64 ┆ f64 │ ╞══════════╪══════════╪════════╪═══════════════════╪═════════╪═════════╡ │ 1 ┆ 2 ┆ change ┆ C ┆ 15.95 ┆ 0.74 │ │ 2 ┆ 1 ┆ change ┆ Java ┆ 13.48 ┆ -3.18 │ │ 3 ┆ 3 ┆ null ┆ Python ┆ 10.47 ┆ 0.59 │ │ 4 ┆ 4 ┆ null ┆ C++ ┆ 7.11 ┆ 1.48 │ │ 5 ┆ 5 ┆ null ┆ C# ┆ 4.58 ┆ 1.18 │ │ 6 ┆ 6 ┆ null ┆ Visual Basic ┆ 4.12 ┆ 0.83 │ │ 7 ┆ 7 ┆ null ┆ JavaScript ┆ 2.54 ┆ 0.41 │ │ 8 ┆ 9 ┆ change ┆ PHP ┆ 2.49 ┆ 0.62 │ │ 9 ┆ 19 ┆ change ┆ R ┆ 2.37 ┆ 1.33 │ │ 10 ┆ 8 ┆ change ┆ SQL ┆ 1.76 ┆ -0.19 │ │ 11 ┆ 14 ┆ change ┆ Go ┆ 1.46 ┆ 0.24 │ │ 12 ┆ 16 ┆ change ┆ Swift ┆ 1.38 ┆ 0.28 │ │ 13 ┆ 20 ┆ change ┆ Perl ┆ 1.3 ┆ 0.26 │ │ 14 ┆ 12 ┆ change ┆ Assembly language ┆ 1.3 ┆ -0.08 │ │ 15 ┆ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ 0.03 │ │ 16 ┆ 18 ┆ change ┆ MATLAB ┆ 1.1 ┆ 0.04 │ │ 17 ┆ 11 ┆ change ┆ Groovy ┆ 0.99 ┆ -0.52 │ │ 18 ┆ 33 ┆ change ┆ Rust ┆ 0.92 ┆ 0.55 │ │ 19 ┆ 10 ┆ change ┆ Objective-C ┆ 0.85 ┆ -0.99 │ │ 20 ┆ 24 ┆ change ┆ Dart ┆ 0.77 ┆ 0.13 │ └──────────┴──────────┴────────┴───────────────────┴─────────┴─────────┘
5. Horizontální spojení datových rámců
V další části článku si vysvětlíme, jak probíhá spojování datových rámců „po sloupcích“ neboli horizontálně. K tomuto účelu budou použity odlišné datové soubory – tiobeE.tsv a tiobeF.tsv.
Soubor tiobeE.tsv obsahuje pouze tři vybrané sloupce z původního rámce (tabulky). Mimochodem – žádný z těchto sloupců by nemohl sloužit jako index resp. primární klíč:
Language Ratings Changep C 15.95 +0.74 Java 13.48 -3.18 Python 10.47 +0.59 C++ 7.11 +1.48 C# 4.58 +1.18 Visual Basic 4.12 +0.83 JavaScript 2.54 +0.41 PHP 2.49 +0.62 R 2.37 +1.33 SQL 1.76 -0.19 Go 1.46 +0.24 Swift 1.38 +0.28 Perl 1.30 +0.26 Assembly language 1.30 -0.08 Ruby 1.24 +0.03 MATLAB 1.10 +0.04 Groovy 0.99 -0.52 Rust 0.92 +0.55 Objective-C 0.85 -0.99 Dart 0.77 +0.13
Soubor nazvaný tiobeF.tsv taktéž obsahuje pouze vybrané datové sloupce z původní tabulky:
Sep 2020 Sep 2019 Change Language 1 2 change C 2 1 change Java 3 3 Python 4 4 C++ 5 5 C# 6 6 Visual Basic 7 7 JavaScript 8 9 change PHP 9 19 change R 10 8 change SQL 11 14 change Go 12 16 change Swift 13 20 change Perl 14 12 change Assembly language 15 15 Ruby 16 18 change MATLAB 17 11 change Groovy 18 33 change Rust 19 10 change Objective-C 20 24 change Dart
6. První (nefunkční) skript pro vertikální spojení datových rámců
Nejprve si ukažme, jak se teoreticky provede spojení dvou datových rámců (které nejsou dále upraveny) „po sloupcích“ s využitím funkce concat. V tomto případě je nutné funkci concat předat seznam nebo n-tici, jejímiž prvky jsou reference na spojované datové rámce. A samozřejmě nesmíme zapomenout na parametr how, kterým určujeme, zda se spojení má provést po řádcích nebo po sloupcích:
#!/usr/bin/env python3 # vim: set fileencoding=utf-8 import polars # maximální počet zobrazených řádků polars.Config.set_tbl_rows(100) # přečtení zdrojových dat df1 = polars.read_csv("tiobeE.tsv", sep="\t") df2 = polars.read_csv("tiobeF.tsv", sep="\t") # datové rámce zobrazíme print(df1) print() print(df2) print() # spojení obou datových rámců concatenated = polars.concat([df1, df2], how="horizontal") # výpis výsledku print(concatenated)
Tento skript po svém spuštění nejdříve zobrazí oba načtené zdrojové datové rámce:
shape: (20, 3) ┌───────────────────┬─────────┬─────────┐ │ Language ┆ Ratings ┆ Changep │ │ --- ┆ --- ┆ --- │ │ str ┆ f64 ┆ f64 │ ╞═══════════════════╪═════════╪═════════╡ │ C ┆ 15.95 ┆ 0.74 │ │ Java ┆ 13.48 ┆ -3.18 │ │ Python ┆ 10.47 ┆ 0.59 │ │ C++ ┆ 7.11 ┆ 1.48 │ │ C# ┆ 4.58 ┆ 1.18 │ │ Visual Basic ┆ 4.12 ┆ 0.83 │ │ JavaScript ┆ 2.54 ┆ 0.41 │ │ PHP ┆ 2.49 ┆ 0.62 │ │ R ┆ 2.37 ┆ 1.33 │ │ SQL ┆ 1.76 ┆ -0.19 │ │ Go ┆ 1.46 ┆ 0.24 │ │ Swift ┆ 1.38 ┆ 0.28 │ │ Perl ┆ 1.3 ┆ 0.26 │ │ Assembly language ┆ 1.3 ┆ -0.08 │ │ Ruby ┆ 1.24 ┆ 0.03 │ │ MATLAB ┆ 1.1 ┆ 0.04 │ │ Groovy ┆ 0.99 ┆ -0.52 │ │ Rust ┆ 0.92 ┆ 0.55 │ │ Objective-C ┆ 0.85 ┆ -0.99 │ │ Dart ┆ 0.77 ┆ 0.13 │ └───────────────────┴─────────┴─────────┘ shape: (20, 4) ┌──────────┬──────────┬────────┬───────────────────┐ │ Sep 2020 ┆ Sep 2019 ┆ Change ┆ Language │ │ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ str ┆ str │ ╞══════════╪══════════╪════════╪═══════════════════╡ │ 1 ┆ 2 ┆ change ┆ C │ │ 2 ┆ 1 ┆ change ┆ Java │ │ 3 ┆ 3 ┆ null ┆ Python │ │ 4 ┆ 4 ┆ null ┆ C++ │ │ 5 ┆ 5 ┆ null ┆ C# │ │ 6 ┆ 6 ┆ null ┆ Visual Basic │ │ 7 ┆ 7 ┆ null ┆ JavaScript │ │ 8 ┆ 9 ┆ change ┆ PHP │ │ 9 ┆ 19 ┆ change ┆ R │ │ 10 ┆ 8 ┆ change ┆ SQL │ │ 11 ┆ 14 ┆ change ┆ Go │ │ 12 ┆ 16 ┆ change ┆ Swift │ │ 13 ┆ 20 ┆ change ┆ Perl │ │ 14 ┆ 12 ┆ change ┆ Assembly language │ │ 15 ┆ 15 ┆ null ┆ Ruby │ │ 16 ┆ 18 ┆ change ┆ MATLAB │ │ 17 ┆ 11 ┆ change ┆ Groovy │ │ 18 ┆ 33 ┆ change ┆ Rust │ │ 19 ┆ 10 ┆ change ┆ Objective-C │ │ 20 ┆ 24 ┆ change ┆ Dart │ └──────────┴──────────┴────────┴───────────────────┘
V dalším kroku by mělo dojít ke spojení obou datových rámců. To se však nepovede, a to z toho důvodu, že oba spojované rámce obsahují stejný sloupec nazvaný „Language“:
Traceback (most recent call last): File "data_frame_concat_horizontally_1.py", line 32, in <module> concatenated = polars.concat([df1, df2], how="horizontal") File "/home/ptisnovs/.local/lib/python3.8/site-packages/polars/internals/functions.py", line 232, in concat out = pli.wrap_df(_hor_concat_df(items)) exceptions.DuplicateError: Cannot do hstack operation. Column with name: Language already exists
7. Explicitní výběr sloupců z druhého datového rámce pro operaci spojení
Oprava předchozího skriptu může proběhnout mnoha různými způsoby. Jeden z možných způsobů spočívá v tom, že z prvního nebo druhého datového rámce odstraníme sloupec „Language“. Například provedeme odstranění tohoto sloupce ze druhého datového rámce:
df2 = df2.select(["Sep 2020", "Sep 2019", "Change"])
Upravený skript vypadá následovně:
#!/usr/bin/env python3 # vim: set fileencoding=utf-8 import polars # maximální počet zobrazených řádků polars.Config.set_tbl_rows(100) # přečtení zdrojových dat df1 = polars.read_csv("tiobeE.tsv", sep="\t") df2 = polars.read_csv("tiobeF.tsv", sep="\t") df2 = df2.select(["Sep 2020", "Sep 2019", "Change"]) # datové rámce zobrazíme print(df1) print() print(df2) print() # spojení obou datových rámců concatenated = polars.concat([df1, df2], how="horizontal") # výpis výsledku print(concatenated)
Výsledek (zobrazíme si pouze výsledný datový rámec) již nyní odpovídá očekávání – skutečně došlo ke spojení obou zdrojových rámců po sloupcích:
shape: (20, 6) ┌───────────────────┬─────────┬─────────┬──────────┬──────────┬────────┐ │ Language ┆ Ratings ┆ Changep ┆ Sep 2020 ┆ Sep 2019 ┆ Change │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ str ┆ f64 ┆ f64 ┆ i64 ┆ i64 ┆ str │ ╞═══════════════════╪═════════╪═════════╪══════════╪══════════╪════════╡ │ C ┆ 15.95 ┆ 0.74 ┆ 1 ┆ 2 ┆ change │ │ Java ┆ 13.48 ┆ -3.18 ┆ 2 ┆ 1 ┆ change │ │ Python ┆ 10.47 ┆ 0.59 ┆ 3 ┆ 3 ┆ null │ │ C++ ┆ 7.11 ┆ 1.48 ┆ 4 ┆ 4 ┆ null │ │ C# ┆ 4.58 ┆ 1.18 ┆ 5 ┆ 5 ┆ null │ │ Visual Basic ┆ 4.12 ┆ 0.83 ┆ 6 ┆ 6 ┆ null │ │ JavaScript ┆ 2.54 ┆ 0.41 ┆ 7 ┆ 7 ┆ null │ │ PHP ┆ 2.49 ┆ 0.62 ┆ 8 ┆ 9 ┆ change │ │ R ┆ 2.37 ┆ 1.33 ┆ 9 ┆ 19 ┆ change │ │ SQL ┆ 1.76 ┆ -0.19 ┆ 10 ┆ 8 ┆ change │ │ Go ┆ 1.46 ┆ 0.24 ┆ 11 ┆ 14 ┆ change │ │ Swift ┆ 1.38 ┆ 0.28 ┆ 12 ┆ 16 ┆ change │ │ Perl ┆ 1.3 ┆ 0.26 ┆ 13 ┆ 20 ┆ change │ │ Assembly language ┆ 1.3 ┆ -0.08 ┆ 14 ┆ 12 ┆ change │ │ Ruby ┆ 1.24 ┆ 0.03 ┆ 15 ┆ 15 ┆ null │ │ MATLAB ┆ 1.1 ┆ 0.04 ┆ 16 ┆ 18 ┆ change │ │ Groovy ┆ 0.99 ┆ -0.52 ┆ 17 ┆ 11 ┆ change │ │ Rust ┆ 0.92 ┆ 0.55 ┆ 18 ┆ 33 ┆ change │ │ Objective-C ┆ 0.85 ┆ -0.99 ┆ 19 ┆ 10 ┆ change │ │ Dart ┆ 0.77 ┆ 0.13 ┆ 20 ┆ 24 ┆ change │ └───────────────────┴─────────┴─────────┴──────────┴──────────┴────────┘
8. Spojení dvou datových rámců operací typu join
Velmi často se setkáme s nutností spojit dvě tabulky, které sice obsahují shodné sloupce, ovšem ne všechny řádky (resp. záznamy) nalezneme v obou spojovaných tabulkách. Taková operace je zcela běžná v oblasti relačních databází (přesněji řečeno v SQL databázích), kde pro ni existuje i klauzule JOIN. Podle toho, jakým způsobem jsou do výsledku zařazeny ty záznamy, které nejsou nalezeny v obou spojovaných tabulkách, rozlišujeme:
- vnitřní spojení (inner join)
- vnější spojení (outer join)
Vnější spojení je dále děleno na:
- úplné vnější spojení (outer join)
- vnější spojení zleva (left join)
- vnější spojení zprava (right join)
Tato operace je v knihovně Polars realizována metodou datového rámce nazvanou join; současně se jedná o jednu z funkcí, která dokáže do značné míry konfigurovat přesný postup operace spojení dvou datových rámců.
class DataFrame: def join( self, other: DataFrame, left_on: str | pli.Expr | Sequence[str | pli.Expr] | None = None, right_on: str | pli.Expr | Sequence[str | pli.Expr] | None = None, on: str | pli.Expr | Sequence[str | pli.Expr] | None = None, how: JoinStrategy = "inner", suffix: str = "_right", ) -> DataFrame:
9. Datové soubory použité v příkladech ukazujících operaci join
Vzhledem k velké univerzálnosti metody
join
si ukážeme její použití na několika demonstračních příkladech. Použijeme přitom datové rámce, které vzniknou načtením dvojice tabulek, které mají některé řádky shodné a jiné naopak v první či druhé tabulce zcela chybí.V první tabulce je uloženo patnáct řádků původně získaných z Tiobe indexu:
Sep 2019 Change Language Ratings Changep 2 change C 15.95 +0.74 1 change Java 13.48 -3.18 3 Python 10.47 +0.59 4 C++ 7.11 +1.48 5 C# 4.58 +1.18 6 Visual Basic 4.12 +0.83 7 JavaScript 2.54 +0.41 9 change PHP 2.49 +0.62 19 change R 2.37 +1.33 8 change SQL 1.76 -0.19 14 change Go 1.46 +0.24 16 change Swift 1.38 +0.28 20 change Perl 1.30 +0.26 12 change Assembly language 1.30 -0.08 15 Ruby 1.24 +0.03
Ve druhé tabulce je taktéž patnáct řádků původně získaných z Tiobe indexu, ovšem posledních pět řádků je od předchozí tabulky odlišných:
Sep 2020 Change Language Ratings Changep 1 change C 15.95 +0.74 2 change Java 13.48 -3.18 3 Python 10.47 +0.59 4 C++ 7.11 +1.48 5 C# 4.58 +1.18 6 Visual Basic 4.12 +0.83 7 JavaScript 2.54 +0.41 8 change PHP 2.49 +0.62 9 change R 2.37 +1.33 10 change SQL 1.76 -0.19 16 change MATLAB 1.10 +0.04 17 change Groovy 0.99 -0.52 18 change Rust 0.92 +0.55 19 change Objective-C 0.85 -0.99 20 change Dart 0.77 +0.13
A takto vypadají datové rámce načtené demonstračními příklady z navazujících kapitol (už tyto výpisy nebudeme kvůli místu opakovat):
shape: (15, 5) ┌──────────┬────────┬───────────────────┬─────────┬─────────┐ │ Sep 2019 ┆ Change ┆ Language ┆ Ratings ┆ Changep │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ str ┆ str ┆ f64 ┆ f64 │ ╞══════════╪════════╪═══════════════════╪═════════╪═════════╡ │ 2 ┆ change ┆ C ┆ 15.95 ┆ 0.74 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ -3.18 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ 0.59 │ │ 4 ┆ null ┆ C++ ┆ 7.11 ┆ 1.48 │ │ 5 ┆ null ┆ C# ┆ 4.58 ┆ 1.18 │ │ 6 ┆ null ┆ Visual Basic ┆ 4.12 ┆ 0.83 │ │ 7 ┆ null ┆ JavaScript ┆ 2.54 ┆ 0.41 │ │ 9 ┆ change ┆ PHP ┆ 2.49 ┆ 0.62 │ │ 19 ┆ change ┆ R ┆ 2.37 ┆ 1.33 │ │ 8 ┆ change ┆ SQL ┆ 1.76 ┆ -0.19 │ │ 14 ┆ change ┆ Go ┆ 1.46 ┆ 0.24 │ │ 16 ┆ change ┆ Swift ┆ 1.38 ┆ 0.28 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ 0.26 │ │ 12 ┆ change ┆ Assembly language ┆ 1.3 ┆ -0.08 │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ 0.03 │ └──────────┴────────┴───────────────────┴─────────┴─────────┘
shape: (15, 5) ┌──────────┬────────┬──────────────┬─────────┬─────────┐ │ Sep 2020 ┆ Change ┆ Language ┆ Ratings ┆ Changep │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ str ┆ str ┆ f64 ┆ f64 │ ╞══════════╪════════╪══════════════╪═════════╪═════════╡ │ 1 ┆ change ┆ C ┆ 15.95 ┆ 0.74 │ │ 2 ┆ change ┆ Java ┆ 13.48 ┆ -3.18 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ 0.59 │ │ 4 ┆ null ┆ C++ ┆ 7.11 ┆ 1.48 │ │ 5 ┆ null ┆ C# ┆ 4.58 ┆ 1.18 │ │ 6 ┆ null ┆ Visual Basic ┆ 4.12 ┆ 0.83 │ │ 7 ┆ null ┆ JavaScript ┆ 2.54 ┆ 0.41 │ │ 8 ┆ change ┆ PHP ┆ 2.49 ┆ 0.62 │ │ 9 ┆ change ┆ R ┆ 2.37 ┆ 1.33 │ │ 10 ┆ change ┆ SQL ┆ 1.76 ┆ -0.19 │ │ 16 ┆ change ┆ MATLAB ┆ 1.1 ┆ 0.04 │ │ 17 ┆ change ┆ Groovy ┆ 0.99 ┆ -0.52 │ │ 18 ┆ change ┆ Rust ┆ 0.92 ┆ 0.55 │ │ 19 ┆ change ┆ Objective-C ┆ 0.85 ┆ -0.99 │ │ 20 ┆ change ┆ Dart ┆ 0.77 ┆ 0.13 │ └──────────┴────────┴──────────────┴─────────┴─────────┘
10. Realizace operace inner join (vnitřního spojení)
Operace vnitřního spojení neboli inner join dokáže automaticky spojit ty řádky tabulek, které mají totožný obsah vybraného sloupce nebo sloupců (tyto sloupce jsou tedy použity ve funkci klíčů). Současně jsou i identifikovány sloupce se shodným názvem a typem (pokud neurčíme jinak). Podívejme se nyní na způsob provedení této operace u datových rámců, které mají implicitní (celočíselné) indexy, což je ostatně v Polars jediná varianta (na rozdíl od knihovny Pandas):
#!/usr/bin/env python3 # vim: set fileencoding=utf-8 import polars # maximální počet zobrazených řádků polars.Config.set_tbl_rows(100) # přečtení zdrojových dat df1 = polars.read_csv("tiobeA.tsv", sep="\t") df2 = polars.read_csv("tiobeB.tsv", sep="\t") # datové rámce zobrazíme print(df1) print() print(df2) print() # spojení obou datových rámců merged = df1.join(df2, on="Language", how="inner") # výpis výsledku print(merged)
Výsledný datový rámec obsahuje pouze deset řádků obsažených v levém i pravém rámci vstupujícím do operace JOIN. Zbylých deset řádků (pět z levého rámce, jiných pět z rámce druhého) zde nenalezneme:
shape: (10, 9) ┌──────────┬────────┬──────────────┬─────────┬─────┬──────────┬──────────────┬───────────────┬───────────────┐ │ Sep 2019 ┆ Change ┆ Language ┆ Ratings ┆ ... ┆ Sep 2020 ┆ Change_right ┆ Ratings_right ┆ Changep_right │ │ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ str ┆ str ┆ f64 ┆ ┆ i64 ┆ str ┆ f64 ┆ f64 │ ╞══════════╪════════╪══════════════╪═════════╪═════╪══════════╪══════════════╪═══════════════╪═══════════════╡ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ 1 ┆ change ┆ 15.95 ┆ 0.74 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ 2 ┆ change ┆ 13.48 ┆ -3.18 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ 3 ┆ null ┆ 10.47 ┆ 0.59 │ │ 4 ┆ null ┆ C++ ┆ 7.11 ┆ ... ┆ 4 ┆ null ┆ 7.11 ┆ 1.48 │ │ 5 ┆ null ┆ C# ┆ 4.58 ┆ ... ┆ 5 ┆ null ┆ 4.58 ┆ 1.18 │ │ 6 ┆ null ┆ Visual Basic ┆ 4.12 ┆ ... ┆ 6 ┆ null ┆ 4.12 ┆ 0.83 │ │ 7 ┆ null ┆ JavaScript ┆ 2.54 ┆ ... ┆ 7 ┆ null ┆ 2.54 ┆ 0.41 │ │ 9 ┆ change ┆ PHP ┆ 2.49 ┆ ... ┆ 8 ┆ change ┆ 2.49 ┆ 0.62 │ │ 19 ┆ change ┆ R ┆ 2.37 ┆ ... ┆ 9 ┆ change ┆ 2.37 ┆ 1.33 │ │ 8 ┆ change ┆ SQL ┆ 1.76 ┆ ... ┆ 10 ┆ change ┆ 1.76 ┆ -0.19 │ └──────────┴────────┴──────────────┴─────────┴─────┴──────────┴──────────────┴───────────────┴───────────────┘
11. Left join (vnější spojení „zleva“)
Ukažme si nyní způsob provedení vnějšího spojení dvou datových rámců zleva. Toto spojení je specifikováno parametrem how nastaveným na hodnotu „left“ (jedná se o řetězec). Ve výsledném datovém rámci budou za všech okolností všechny řádky z levého rámce, a to i ve chvíli, kdy k nim nebyly nalezeny odpovídající řádky v pravém rámci:
#!/usr/bin/env python3 # vim: set fileencoding=utf-8 import polars # maximální počet zobrazených řádků polars.Config.set_tbl_rows(100) # přečtení zdrojových dat df1 = polars.read_csv("tiobeA.tsv", sep="\t") df2 = polars.read_csv("tiobeB.tsv", sep="\t") # datové rámce zobrazíme print(df1) print() print(df2) print() # spojení obou datových rámců merged = df1.join(df2, on="Language", how="left") # výpis výsledku print(merged)
Ve výsledném datovém rámci je po spojení uloženo celkem patnáct řádků, protože byly přidány i všechny řádky z prvního (levého) datového rámce, které ovšem nemají všechny potřebné údaje ve sloupci Sep 2020. Proto je namísto těchto hodnot použita null, kterou Polars plně podporuje u všech datových typů:
shape: (15, 9) ┌──────────┬────────┬───────────────────┬─────────┬─────┬──────────┬──────────────┬───────────────┬───────────────┐ │ Sep 2019 ┆ Change ┆ Language ┆ Ratings ┆ ... ┆ Sep 2020 ┆ Change_right ┆ Ratings_right ┆ Changep_right │ │ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ str ┆ str ┆ f64 ┆ ┆ i64 ┆ str ┆ f64 ┆ f64 │ ╞══════════╪════════╪═══════════════════╪═════════╪═════╪══════════╪══════════════╪═══════════════╪═══════════════╡ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ 1 ┆ change ┆ 15.95 ┆ 0.74 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ 2 ┆ change ┆ 13.48 ┆ -3.18 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ 3 ┆ null ┆ 10.47 ┆ 0.59 │ │ 4 ┆ null ┆ C++ ┆ 7.11 ┆ ... ┆ 4 ┆ null ┆ 7.11 ┆ 1.48 │ │ 5 ┆ null ┆ C# ┆ 4.58 ┆ ... ┆ 5 ┆ null ┆ 4.58 ┆ 1.18 │ │ 6 ┆ null ┆ Visual Basic ┆ 4.12 ┆ ... ┆ 6 ┆ null ┆ 4.12 ┆ 0.83 │ │ 7 ┆ null ┆ JavaScript ┆ 2.54 ┆ ... ┆ 7 ┆ null ┆ 2.54 ┆ 0.41 │ │ 9 ┆ change ┆ PHP ┆ 2.49 ┆ ... ┆ 8 ┆ change ┆ 2.49 ┆ 0.62 │ │ 19 ┆ change ┆ R ┆ 2.37 ┆ ... ┆ 9 ┆ change ┆ 2.37 ┆ 1.33 │ │ 8 ┆ change ┆ SQL ┆ 1.76 ┆ ... ┆ 10 ┆ change ┆ 1.76 ┆ -0.19 │ │ 14 ┆ change ┆ Go ┆ 1.46 ┆ ... ┆ null ┆ null ┆ null ┆ null │ │ 16 ┆ change ┆ Swift ┆ 1.38 ┆ ... ┆ null ┆ null ┆ null ┆ null │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ null ┆ null ┆ null ┆ null │ │ 12 ┆ change ┆ Assembly language ┆ 1.3 ┆ ... ┆ null ┆ null ┆ null ┆ null │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ null ┆ null ┆ null ┆ null │ └──────────┴────────┴───────────────────┴─────────┴─────┴──────────┴──────────────┴───────────────┴───────────────┘
12. Outer join (vnější spojení)
Zbývá nám popis poslední klasické varianty spojení datových rámců – plný outer join specifikovaný hodnotou „outer“ předanou do pojmenovaného parametru how. Zdrojový kód příkladu tedy opět upravíme, a to konkrétně do této podoby:
#!/usr/bin/env python3 # vim: set fileencoding=utf-8 import polars # maximální počet zobrazených řádků polars.Config.set_tbl_rows(100) # přečtení zdrojových dat df1 = polars.read_csv("tiobeA.tsv", sep="\t") df2 = polars.read_csv("tiobeB.tsv", sep="\t") # datové rámce zobrazíme print(df1) print() print(df2) print() # spojení obou datových rámců merged = df1.join(df2, on="Language", how="outer") # výpis výsledku print(merged)
Nyní bude výsledný datový rámec obsahovat všech dvacet řádků, ovšem některé sloupce musely být doplněny hodnotami null, protože je nebylo možné získat ani z jednoho datového rámce:
shape: (20, 9) ┌──────────┬────────┬───────────────────┬─────────┬─────┬──────────┬──────────────┬───────────────┬───────────────┐ │ Sep 2019 ┆ Change ┆ Language ┆ Ratings ┆ ... ┆ Sep 2020 ┆ Change_right ┆ Ratings_right ┆ Changep_right │ │ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ str ┆ str ┆ f64 ┆ ┆ i64 ┆ str ┆ f64 ┆ f64 │ ╞══════════╪════════╪═══════════════════╪═════════╪═════╪══════════╪══════════════╪═══════════════╪═══════════════╡ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ 1 ┆ change ┆ 15.95 ┆ 0.74 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ 2 ┆ change ┆ 13.48 ┆ -3.18 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ 3 ┆ null ┆ 10.47 ┆ 0.59 │ │ 4 ┆ null ┆ C++ ┆ 7.11 ┆ ... ┆ 4 ┆ null ┆ 7.11 ┆ 1.48 │ │ 5 ┆ null ┆ C# ┆ 4.58 ┆ ... ┆ 5 ┆ null ┆ 4.58 ┆ 1.18 │ │ 6 ┆ null ┆ Visual Basic ┆ 4.12 ┆ ... ┆ 6 ┆ null ┆ 4.12 ┆ 0.83 │ │ 7 ┆ null ┆ JavaScript ┆ 2.54 ┆ ... ┆ 7 ┆ null ┆ 2.54 ┆ 0.41 │ │ 9 ┆ change ┆ PHP ┆ 2.49 ┆ ... ┆ 8 ┆ change ┆ 2.49 ┆ 0.62 │ │ 19 ┆ change ┆ R ┆ 2.37 ┆ ... ┆ 9 ┆ change ┆ 2.37 ┆ 1.33 │ │ 8 ┆ change ┆ SQL ┆ 1.76 ┆ ... ┆ 10 ┆ change ┆ 1.76 ┆ -0.19 │ │ null ┆ null ┆ MATLAB ┆ null ┆ ... ┆ 16 ┆ change ┆ 1.1 ┆ 0.04 │ │ null ┆ null ┆ Groovy ┆ null ┆ ... ┆ 17 ┆ change ┆ 0.99 ┆ -0.52 │ │ null ┆ null ┆ Rust ┆ null ┆ ... ┆ 18 ┆ change ┆ 0.92 ┆ 0.55 │ │ null ┆ null ┆ Objective-C ┆ null ┆ ... ┆ 19 ┆ change ┆ 0.85 ┆ -0.99 │ │ null ┆ null ┆ Dart ┆ null ┆ ... ┆ 20 ┆ change ┆ 0.77 ┆ 0.13 │ │ 12 ┆ change ┆ Assembly language ┆ 1.3 ┆ ... ┆ null ┆ null ┆ null ┆ null │ │ 16 ┆ change ┆ Swift ┆ 1.38 ┆ ... ┆ null ┆ null ┆ null ┆ null │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ null ┆ null ┆ null ┆ null │ │ 14 ┆ change ┆ Go ┆ 1.46 ┆ ... ┆ null ┆ null ┆ null ┆ null │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ null ┆ null ┆ null ┆ null │ └──────────┴────────┴───────────────────┴─────────┴─────┴──────────┴──────────────┴───────────────┴───────────────┘
13. Křížové spojení (kartézský součin)
Další variantou operace join je takzvaný cross join neboli česky „křížové spojení“. Výsledkem křížového spojování je kartézský součin položek z obou vstupních datových rámců. Výsledný datový rámec bude obsahovat všechny uspořádané dvojice, ve kterých je první položka prvkem z prvního datového rámce (všechny sloupce) a druhá položka je prvkem druhého datového rámce. Kartézský součin obsahuje všechny takové kombinace těchto prvků, což znamená, že pokud má první rámec n záznamů a druhý rámec m záznamů, bude výsledný datový rámec obsahovat m×n záznamů.
14. Ukázka realizace kartézského součinu pro datové rámce s pěti a čtyřmi záznamy
Vyzkoušejme si nyní, jak vlastně bude vypadat kartézský součin dvou datových rámců, z nichž první rámec obsahuje pět záznamů (vlastnost jazyka) a druhý rámec obsahuje čtyři záznamy (jméno programovacího jazyka). Kartézským součinem by měl vzniknout nový datový rámec s 5×4=20 záznamy, tedy se všemi možnými kombinacemi vlastnost:jazyk:
#!/usr/bin/env python3 # vim: set fileencoding=utf-8 import polars # maximální počet zobrazených řádků polars.Config.set_tbl_rows(100) # přečtení zdrojových dat df1 = polars.DataFrame(["wonderful", "terible", "popular", "fast", "slow"]) df2 = polars.DataFrame(["Python", "Perl", "Java", "Go"]) # datové rámce zobrazíme print(df1) print() print(df2) print() # spojení obou datových rámců merged = df1.join(df2, on="Language", how="cross") # výpis výsledku print(merged)
Tento skript po svém spuštění nejdříve vypíše oba zdrojové datové rámce:
shape: (5, 1) ┌───────────┐ │ column_0 │ │ --- │ │ str │ ╞═══════════╡ │ wonderful │ │ terible │ │ popular │ │ fast │ │ slow │ └───────────┘ shape: (4, 1) ┌──────────┐ │ column_0 │ │ --- │ │ str │ ╞══════════╡ │ Python │ │ Perl │ │ Java │ │ Go │ └──────────┘
Následně se vypíše obsah datového rámce, který vznikl kartézským součinem obou zdrojových datových rámců:
shape: (20, 2) ┌───────────┬────────────────┐ │ column_0 ┆ column_0_right │ │ --- ┆ --- │ │ str ┆ str │ ╞═══════════╪════════════════╡ │ wonderful ┆ Python │ │ wonderful ┆ Perl │ │ wonderful ┆ Java │ │ wonderful ┆ Go │ │ terible ┆ Python │ │ terible ┆ Perl │ │ terible ┆ Java │ │ terible ┆ Go │ │ popular ┆ Python │ │ popular ┆ Perl │ │ popular ┆ Java │ │ popular ┆ Go │ │ fast ┆ Python │ │ fast ┆ Perl │ │ fast ┆ Java │ │ fast ┆ Go │ │ slow ┆ Python │ │ slow ┆ Perl │ │ slow ┆ Java │ │ slow ┆ Go │ └───────────┴────────────────┘
15. Kartézský součin pro datové rámce použité v předchozích příkladech
Pro zajímavost si můžeme ukázat, jaký výsledek získáme po kartézském součinu (resp. křížovém spojení) dvou datových rámců používaných v předchozích kapitolách. Každý z těchto datových rámců obsahuje 15 záznamů, takže výsledkem by měl být datový rámec s 15×15=225 záznamy:
#!/usr/bin/env python3 # vim: set fileencoding=utf-8 import polars # maximální počet zobrazených řádků polars.Config.set_tbl_rows(100) # přečtení zdrojových dat df1 = polars.read_csv("tiobeA.tsv", sep="\t") df2 = polars.read_csv("tiobeB.tsv", sep="\t") # datové rámce zobrazíme print(df1) print() print(df2) print() # spojení obou datových rámců merged = df1.join(df2, on="Language", how="cross") # výpis výsledku print(merged)
Tento skript nejdříve vypíše oba zdrojové datové rámce, z nichž každý obsahuje již výše zmíněných patnáct záznamů:
shape: (15, 5) ┌──────────┬────────┬───────────────────┬─────────┬─────────┐ │ Sep 2019 ┆ Change ┆ Language ┆ Ratings ┆ Changep │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ str ┆ str ┆ f64 ┆ f64 │ ╞══════════╪════════╪═══════════════════╪═════════╪═════════╡ │ 2 ┆ change ┆ C ┆ 15.95 ┆ 0.74 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ -3.18 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ 0.59 │ │ 4 ┆ null ┆ C++ ┆ 7.11 ┆ 1.48 │ │ 5 ┆ null ┆ C# ┆ 4.58 ┆ 1.18 │ │ 6 ┆ null ┆ Visual Basic ┆ 4.12 ┆ 0.83 │ │ 7 ┆ null ┆ JavaScript ┆ 2.54 ┆ 0.41 │ │ 9 ┆ change ┆ PHP ┆ 2.49 ┆ 0.62 │ │ 19 ┆ change ┆ R ┆ 2.37 ┆ 1.33 │ │ 8 ┆ change ┆ SQL ┆ 1.76 ┆ -0.19 │ │ 14 ┆ change ┆ Go ┆ 1.46 ┆ 0.24 │ │ 16 ┆ change ┆ Swift ┆ 1.38 ┆ 0.28 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ 0.26 │ │ 12 ┆ change ┆ Assembly language ┆ 1.3 ┆ -0.08 │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ 0.03 │ └──────────┴────────┴───────────────────┴─────────┴─────────┘
a:
shape: (15, 5) ┌──────────┬────────┬──────────────┬─────────┬─────────┐ │ Sep 2020 ┆ Change ┆ Language ┆ Ratings ┆ Changep │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ str ┆ str ┆ f64 ┆ f64 │ ╞══════════╪════════╪══════════════╪═════════╪═════════╡ │ 1 ┆ change ┆ C ┆ 15.95 ┆ 0.74 │ │ 2 ┆ change ┆ Java ┆ 13.48 ┆ -3.18 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ 0.59 │ │ 4 ┆ null ┆ C++ ┆ 7.11 ┆ 1.48 │ │ 5 ┆ null ┆ C# ┆ 4.58 ┆ 1.18 │ │ 6 ┆ null ┆ Visual Basic ┆ 4.12 ┆ 0.83 │ │ 7 ┆ null ┆ JavaScript ┆ 2.54 ┆ 0.41 │ │ 8 ┆ change ┆ PHP ┆ 2.49 ┆ 0.62 │ │ 9 ┆ change ┆ R ┆ 2.37 ┆ 1.33 │ │ 10 ┆ change ┆ SQL ┆ 1.76 ┆ -0.19 │ │ 16 ┆ change ┆ MATLAB ┆ 1.1 ┆ 0.04 │ │ 17 ┆ change ┆ Groovy ┆ 0.99 ┆ -0.52 │ │ 18 ┆ change ┆ Rust ┆ 0.92 ┆ 0.55 │ │ 19 ┆ change ┆ Objective-C ┆ 0.85 ┆ -0.99 │ │ 20 ┆ change ┆ Dart ┆ 0.77 ┆ 0.13 │ └──────────┴────────┴──────────────┴─────────┴─────────┘
Křížovým spojením skutečně vznikne již relativně rozsáhlý datový rámec s 225 záznamy:
shape: (225, 10) ┌──────────┬────────┬──────────┬─────────┬─────┬────────────┬────────────┬────────────┬────────────┐ │ Sep 2019 ┆ Change ┆ Language ┆ Ratings ┆ ... ┆ Change_rig ┆ Language_r ┆ Ratings_ri ┆ Changep_ri │ │ --- ┆ --- ┆ --- ┆ --- ┆ ┆ ht ┆ ight ┆ ght ┆ ght │ │ i64 ┆ str ┆ str ┆ f64 ┆ ┆ --- ┆ --- ┆ --- ┆ --- │ │ ┆ ┆ ┆ ┆ ┆ str ┆ str ┆ f64 ┆ f64 │ ╞══════════╪════════╪══════════╪═════════╪═════╪════════════╪════════════╪════════════╪════════════╡ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ change ┆ C ┆ 15.95 ┆ 0.74 │ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ change ┆ Java ┆ 13.48 ┆ -3.18 │ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ null ┆ Python ┆ 10.47 ┆ 0.59 │ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ null ┆ C++ ┆ 7.11 ┆ 1.48 │ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ null ┆ C# ┆ 4.58 ┆ 1.18 │ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ null ┆ Visual ┆ 4.12 ┆ 0.83 │ │ ┆ ┆ ┆ ┆ ┆ ┆ Basic ┆ ┆ │ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ null ┆ JavaScript ┆ 2.54 ┆ 0.41 │ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ change ┆ PHP ┆ 2.49 ┆ 0.62 │ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ change ┆ R ┆ 2.37 ┆ 1.33 │ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ change ┆ SQL ┆ 1.76 ┆ -0.19 │ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ change ┆ MATLAB ┆ 1.1 ┆ 0.04 │ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ change ┆ Groovy ┆ 0.99 ┆ -0.52 │ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ change ┆ Rust ┆ 0.92 ┆ 0.55 │ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ change ┆ Objective- ┆ 0.85 ┆ -0.99 │ │ ┆ ┆ ┆ ┆ ┆ ┆ C ┆ ┆ │ │ 2 ┆ change ┆ C ┆ 15.95 ┆ ... ┆ change ┆ Dart ┆ 0.77 ┆ 0.13 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ change ┆ C ┆ 15.95 ┆ 0.74 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ change ┆ Java ┆ 13.48 ┆ -3.18 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ null ┆ Python ┆ 10.47 ┆ 0.59 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ null ┆ C++ ┆ 7.11 ┆ 1.48 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ null ┆ C# ┆ 4.58 ┆ 1.18 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ null ┆ Visual ┆ 4.12 ┆ 0.83 │ │ ┆ ┆ ┆ ┆ ┆ ┆ Basic ┆ ┆ │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ null ┆ JavaScript ┆ 2.54 ┆ 0.41 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ change ┆ PHP ┆ 2.49 ┆ 0.62 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ change ┆ R ┆ 2.37 ┆ 1.33 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ change ┆ SQL ┆ 1.76 ┆ -0.19 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ change ┆ MATLAB ┆ 1.1 ┆ 0.04 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ change ┆ Groovy ┆ 0.99 ┆ -0.52 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ change ┆ Rust ┆ 0.92 ┆ 0.55 │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ change ┆ Objective- ┆ 0.85 ┆ -0.99 │ │ ┆ ┆ ┆ ┆ ┆ ┆ C ┆ ┆ │ │ 1 ┆ change ┆ Java ┆ 13.48 ┆ ... ┆ change ┆ Dart ┆ 0.77 ┆ 0.13 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ change ┆ C ┆ 15.95 ┆ 0.74 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ change ┆ Java ┆ 13.48 ┆ -3.18 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ null ┆ Python ┆ 10.47 ┆ 0.59 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ null ┆ C++ ┆ 7.11 ┆ 1.48 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ null ┆ C# ┆ 4.58 ┆ 1.18 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ null ┆ Visual ┆ 4.12 ┆ 0.83 │ │ ┆ ┆ ┆ ┆ ┆ ┆ Basic ┆ ┆ │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ null ┆ JavaScript ┆ 2.54 ┆ 0.41 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ change ┆ PHP ┆ 2.49 ┆ 0.62 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ change ┆ R ┆ 2.37 ┆ 1.33 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ change ┆ SQL ┆ 1.76 ┆ -0.19 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ change ┆ MATLAB ┆ 1.1 ┆ 0.04 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ change ┆ Groovy ┆ 0.99 ┆ -0.52 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ change ┆ Rust ┆ 0.92 ┆ 0.55 │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ change ┆ Objective- ┆ 0.85 ┆ -0.99 │ │ ┆ ┆ ┆ ┆ ┆ ┆ C ┆ ┆ │ │ 3 ┆ null ┆ Python ┆ 10.47 ┆ ... ┆ change ┆ Dart ┆ 0.77 ┆ 0.13 │ │ 4 ┆ null ┆ C++ ┆ 7.11 ┆ ... ┆ change ┆ C ┆ 15.95 ┆ 0.74 │ │ 4 ┆ null ┆ C++ ┆ 7.11 ┆ ... ┆ change ┆ Java ┆ 13.48 ┆ -3.18 │ │ 4 ┆ null ┆ C++ ┆ 7.11 ┆ ... ┆ null ┆ Python ┆ 10.47 ┆ 0.59 │ │ 4 ┆ null ┆ C++ ┆ 7.11 ┆ ... ┆ null ┆ C++ ┆ 7.11 ┆ 1.48 │ │ 4 ┆ null ┆ C++ ┆ 7.11 ┆ ... ┆ null ┆ C# ┆ 4.58 ┆ 1.18 │ │ ... ┆ ... ┆ ... ┆ ... ┆ ... ┆ ... ┆ ... ┆ ... ┆ ... │ │ 16 ┆ change ┆ Swift ┆ 1.38 ┆ ... ┆ change ┆ MATLAB ┆ 1.1 ┆ 0.04 │ │ 16 ┆ change ┆ Swift ┆ 1.38 ┆ ... ┆ change ┆ Groovy ┆ 0.99 ┆ -0.52 │ │ 16 ┆ change ┆ Swift ┆ 1.38 ┆ ... ┆ change ┆ Rust ┆ 0.92 ┆ 0.55 │ │ 16 ┆ change ┆ Swift ┆ 1.38 ┆ ... ┆ change ┆ Objective- ┆ 0.85 ┆ -0.99 │ │ ┆ ┆ ┆ ┆ ┆ ┆ C ┆ ┆ │ │ 16 ┆ change ┆ Swift ┆ 1.38 ┆ ... ┆ change ┆ Dart ┆ 0.77 ┆ 0.13 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ change ┆ C ┆ 15.95 ┆ 0.74 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ change ┆ Java ┆ 13.48 ┆ -3.18 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ null ┆ Python ┆ 10.47 ┆ 0.59 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ null ┆ C++ ┆ 7.11 ┆ 1.48 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ null ┆ C# ┆ 4.58 ┆ 1.18 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ null ┆ Visual ┆ 4.12 ┆ 0.83 │ │ ┆ ┆ ┆ ┆ ┆ ┆ Basic ┆ ┆ │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ null ┆ JavaScript ┆ 2.54 ┆ 0.41 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ change ┆ PHP ┆ 2.49 ┆ 0.62 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ change ┆ R ┆ 2.37 ┆ 1.33 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ change ┆ SQL ┆ 1.76 ┆ -0.19 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ change ┆ MATLAB ┆ 1.1 ┆ 0.04 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ change ┆ Groovy ┆ 0.99 ┆ -0.52 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ change ┆ Rust ┆ 0.92 ┆ 0.55 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ change ┆ Objective- ┆ 0.85 ┆ -0.99 │ │ ┆ ┆ ┆ ┆ ┆ ┆ C ┆ ┆ │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ ... ┆ change ┆ Dart ┆ 0.77 ┆ 0.13 │ │ 12 ┆ change ┆ Assembly ┆ 1.3 ┆ ... ┆ change ┆ C ┆ 15.95 ┆ 0.74 │ │ ┆ ┆ language ┆ ┆ ┆ ┆ ┆ ┆ │ │ 12 ┆ change ┆ Assembly ┆ 1.3 ┆ ... ┆ change ┆ Java ┆ 13.48 ┆ -3.18 │ │ ┆ ┆ language ┆ ┆ ┆ ┆ ┆ ┆ │ │ 12 ┆ change ┆ Assembly ┆ 1.3 ┆ ... ┆ null ┆ Python ┆ 10.47 ┆ 0.59 │ │ ┆ ┆ language ┆ ┆ ┆ ┆ ┆ ┆ │ │ 12 ┆ change ┆ Assembly ┆ 1.3 ┆ ... ┆ null ┆ C++ ┆ 7.11 ┆ 1.48 │ │ ┆ ┆ language ┆ ┆ ┆ ┆ ┆ ┆ │ │ 12 ┆ change ┆ Assembly ┆ 1.3 ┆ ... ┆ null ┆ C# ┆ 4.58 ┆ 1.18 │ │ ┆ ┆ language ┆ ┆ ┆ ┆ ┆ ┆ │ │ 12 ┆ change ┆ Assembly ┆ 1.3 ┆ ... ┆ null ┆ Visual ┆ 4.12 ┆ 0.83 │ │ ┆ ┆ language ┆ ┆ ┆ ┆ Basic ┆ ┆ │ │ 12 ┆ change ┆ Assembly ┆ 1.3 ┆ ... ┆ null ┆ JavaScript ┆ 2.54 ┆ 0.41 │ │ ┆ ┆ language ┆ ┆ ┆ ┆ ┆ ┆ │ │ 12 ┆ change ┆ Assembly ┆ 1.3 ┆ ... ┆ change ┆ PHP ┆ 2.49 ┆ 0.62 │ │ ┆ ┆ language ┆ ┆ ┆ ┆ ┆ ┆ │ │ 12 ┆ change ┆ Assembly ┆ 1.3 ┆ ... ┆ change ┆ R ┆ 2.37 ┆ 1.33 │ │ ┆ ┆ language ┆ ┆ ┆ ┆ ┆ ┆ │ │ 12 ┆ change ┆ Assembly ┆ 1.3 ┆ ... ┆ change ┆ SQL ┆ 1.76 ┆ -0.19 │ │ ┆ ┆ language ┆ ┆ ┆ ┆ ┆ ┆ │ │ 12 ┆ change ┆ Assembly ┆ 1.3 ┆ ... ┆ change ┆ MATLAB ┆ 1.1 ┆ 0.04 │ │ ┆ ┆ language ┆ ┆ ┆ ┆ ┆ ┆ │ │ 12 ┆ change ┆ Assembly ┆ 1.3 ┆ ... ┆ change ┆ Groovy ┆ 0.99 ┆ -0.52 │ │ ┆ ┆ language ┆ ┆ ┆ ┆ ┆ ┆ │ │ 12 ┆ change ┆ Assembly ┆ 1.3 ┆ ... ┆ change ┆ Rust ┆ 0.92 ┆ 0.55 │ │ ┆ ┆ language ┆ ┆ ┆ ┆ ┆ ┆ │ │ 12 ┆ change ┆ Assembly ┆ 1.3 ┆ ... ┆ change ┆ Objective- ┆ 0.85 ┆ -0.99 │ │ ┆ ┆ language ┆ ┆ ┆ ┆ C ┆ ┆ │ │ 12 ┆ change ┆ Assembly ┆ 1.3 ┆ ... ┆ change ┆ Dart ┆ 0.77 ┆ 0.13 │ │ ┆ ┆ language ┆ ┆ ┆ ┆ ┆ ┆ │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ change ┆ C ┆ 15.95 ┆ 0.74 │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ change ┆ Java ┆ 13.48 ┆ -3.18 │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ null ┆ Python ┆ 10.47 ┆ 0.59 │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ null ┆ C++ ┆ 7.11 ┆ 1.48 │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ null ┆ C# ┆ 4.58 ┆ 1.18 │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ null ┆ Visual ┆ 4.12 ┆ 0.83 │ │ ┆ ┆ ┆ ┆ ┆ ┆ Basic ┆ ┆ │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ null ┆ JavaScript ┆ 2.54 ┆ 0.41 │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ change ┆ PHP ┆ 2.49 ┆ 0.62 │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ change ┆ R ┆ 2.37 ┆ 1.33 │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ change ┆ SQL ┆ 1.76 ┆ -0.19 │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ change ┆ MATLAB ┆ 1.1 ┆ 0.04 │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ change ┆ Groovy ┆ 0.99 ┆ -0.52 │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ change ┆ Rust ┆ 0.92 ┆ 0.55 │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ change ┆ Objective- ┆ 0.85 ┆ -0.99 │ │ ┆ ┆ ┆ ┆ ┆ ┆ C ┆ ┆ │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ ... ┆ change ┆ Dart ┆ 0.77 ┆ 0.13 │ └──────────┴────────┴──────────┴─────────┴─────┴────────────┴────────────┴────────────┴────────────┘
16. Anti join
Posledním typem operace join, s níž se v dnešním článku alespoň ve stručnosti seznámíme, je takzvaný „anti join“. Tato operace opět porovná obsahy dvou (či většího množství) datových rámců, přičemž obsah zvoleného sloupce vystupuje v roli klíčů. Anti join vytvoří nový datový rámec obsahující ty záznamy, které jsou nalezeny v prvním vstupním datovém rámci, ale nikoli v ostatních rámcích. Touto operací tedy můžeme získat ty záznamy, které jsou odstraněny operací inner join, tedy klasickým vnitřním spojením.
17. „Levý“ anti join
V dnešním předposledním demonstračním příkladu je ukázán způsob realizace operace „levého“ anti joinu, tj. operace, která vrátí datový rámec s těmi záznamy, které jsou obsaženy pouze v levém zdrojovém rámci, ale nikoli v rámci pravém. Záznamy jsou přitom spojeny přes obsah sloupce Language, který zde vystupuje v roli primárního klíče:
#!/usr/bin/env python3 # vim: set fileencoding=utf-8 import polars # maximální počet zobrazených řádků polars.Config.set_tbl_rows(100) # přečtení zdrojových dat df1 = polars.read_csv("tiobeA.tsv", sep="\t") df2 = polars.read_csv("tiobeB.tsv", sep="\t") # datové rámce zobrazíme print(df1) print() print(df2) print() # spojení obou datových rámců merged = df1.join(df2, on="Language", how="anti") # výpis výsledku print(merged)
Výsledný datový rámec obsahuje pouze pět záznamů. Konkrétně se jedná o záznamy z prvního zdrojového datového rámce, které nejsou obsaženy v datovém rámci druhém:
shape: (5, 5) ┌──────────┬────────┬───────────────────┬─────────┬─────────┐ │ Sep 2019 ┆ Change ┆ Language ┆ Ratings ┆ Changep │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ str ┆ str ┆ f64 ┆ f64 │ ╞══════════╪════════╪═══════════════════╪═════════╪═════════╡ │ 14 ┆ change ┆ Go ┆ 1.46 ┆ 0.24 │ │ 16 ┆ change ┆ Swift ┆ 1.38 ┆ 0.28 │ │ 20 ┆ change ┆ Perl ┆ 1.3 ┆ 0.26 │ │ 12 ┆ change ┆ Assembly language ┆ 1.3 ┆ -0.08 │ │ 15 ┆ null ┆ Ruby ┆ 1.24 ┆ 0.03 │ └──────────┴────────┴───────────────────┴─────────┴─────────┘
18. „Pravý“ anti join
„Pravý“ anti join resp. anti join zprava lze realizovat snadno – pouze prohodíme první rámec s rámcem druhým při volání metody join. Tj. namísto:
merged = df1.join(df2, on="Language", how="anti")
použijeme volání:
merged = df2.join(df1, on="Language", how="anti")
Celý skript provádějící tuto operaci vypadá následovně:
#!/usr/bin/env python3 # vim: set fileencoding=utf-8 import polars # maximální počet zobrazených řádků polars.Config.set_tbl_rows(100) # přečtení zdrojových dat df1 = polars.read_csv("tiobeA.tsv", sep="\t") df2 = polars.read_csv("tiobeB.tsv", sep="\t") # datové rámce zobrazíme print(df1) print() print(df2) print() # spojení obou datových rámců merged = df2.join(df1, on="Language", how="anti") # výpis výsledku print(merged)
Výsledný datový rámec v tomto případě opět obsahuje pouze pět záznamů. Konkrétně se jedná o záznamy ze druhého zdrojového datového rámce, které nejsou obsaženy v datovém rámci prvním:
shape: (5, 5) ┌──────────┬────────┬─────────────┬─────────┬─────────┐ │ Sep 2020 ┆ Change ┆ Language ┆ Ratings ┆ Changep │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ str ┆ str ┆ f64 ┆ f64 │ ╞══════════╪════════╪═════════════╪═════════╪═════════╡ │ 16 ┆ change ┆ MATLAB ┆ 1.1 ┆ 0.04 │ │ 17 ┆ change ┆ Groovy ┆ 0.99 ┆ -0.52 │ │ 18 ┆ change ┆ Rust ┆ 0.92 ┆ 0.55 │ │ 19 ┆ change ┆ Objective-C ┆ 0.85 ┆ -0.99 │ │ 20 ┆ change ┆ Dart ┆ 0.77 ┆ 0.13 │ └──────────┴────────┴─────────────┴─────────┴─────────┘
19. 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:
20. Odkazy na Internetu
- Projekt Polars na GitHubu
https://github.com/pola-rs/polars - Dokumentace k projektu Polars (popis API)
https://pola-rs.github.io/polars/py-polars/html/reference/index.html - Polars: The Next Big Python Data Science Library… written in RUST?
https://www.youtube.com/watch?v=VHqn7ufiilE - Polars API: funkce pro načtení datového rámce z CSV
https://pola-rs.github.io/polars/py-polars/html/reference/api/polars.read_csv.html - 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/polars.read_sql.html - Python’s Pandas vs Polars: Who Wins this Fight in Library
https://analyticsindiamag.com/pythons-pandas-vs-polars-who-wins-this-fight-in-library/ - Polars vs Pandas: what is more convenient?
https://medium.com/@ilia.ozhmegov/polars-vs-pandas-what-is-more-convenient-331956742a69 - A Gentle Introduction to Pandas Data Analysis (on Kaggle)
https://www.youtube.com/watch?v=_Eb0utIRdkw&list=PL7RwtdVQXQ8oYpuIIDWR0SaaSCe8ZeZ7t&index=4 - Speed Up Your Pandas Dataframes
https://www.youtube.com/watch?v=u4_c2LDi4b8&list=PL7RwtdVQXQ8oYpuIIDWR0SaaSCe8ZeZ7t&index=5 - pandas.read_csv
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html - How to define format when using pandas to_datetime?
https://stackoverflow.com/questions/36848514/how-to-define-format-when-using-pandas-to-datetime - 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/ - Skip rows during csv import pandas
https://stackoverflow.com/questions/20637439/skip-rows-during-csv-import-pandas - Denni kurz
https://www.cnb.cz/cs/financni_trhy/devizovy_trh/kurzy_devizoveho_trhu/denni_kurz.txt - UUID objects according to RFC 4122 (knihovna pro Python)
https://docs.python.org/3.5/library/uuid.html#uuid.uuid4 - Object identifier (Wikipedia)
https://en.wikipedia.org/wiki/Object_identifier - Digital object identifier (Wikipedia)
https://en.wikipedia.org/wiki/Digital_object_identifier - voluptuous na (na PyPi)
https://pypi.python.org/pypi/voluptuous - Repositář knihovny voluptuous na GitHubu
https://github.com/alecthomas/voluptuous - pytest-voluptuous 1.0.2 (na PyPi)
https://pypi.org/project/pytest-voluptuous/ - pytest-voluptuous (na GitHubu)
https://github.com/F-Secure/pytest-voluptuous - schemagic 0.9.1 (na PyPi)
https://pypi.python.org/pypi/schemagic/0.9.1 - Schemagic / Schemagic.web (na GitHubu)
https://github.com/Mechrophile/schemagic - schema 0.6.7 (na PyPi)
https://pypi.python.org/pypi/schema - schema (na GitHubu)
https://github.com/keleshev/schema - 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 - TIOBE Index for January 2023
https://www.tiobe.com/tiobe-index/ - Lazy evaluation
https://en.wikipedia.org/wiki/Lazy_evaluation