Hlavní navigace

Knihovna Pandas: pokročilejší práce s datovými řadami (series)

17. 12. 2020
Doba čtení: 40 minut

Sdílet

Ve čtvrtém článku o knihovně Pandas dokončíme popis práce s datovými řadami neboli s typem Series. Zabývat se budeme především transformací dat, jejich filtrací a také se seskupováním dat podle zadaných kritérií.

Obsah

1. Knihovna Pandas: pokročilejší práce s datovými řadami (series)

2. Iterace přes všechny prvky datové řady

3. Postupná aplikace vybrané funkce na všechny prvky datové řady

4. Použití slovníku ve funkci mapy

5. Transformace dat v datové řadě

6. Vytvoření více sloupců s transformovanými daty

7. Agregace informací z datové řady

8. Použití jmen funkcí namísto jejich referencí v metodě Series.aggregate

9. Kombinace údajů ze dvou datových řad, popř. datové řady a skalární hodnoty

10. Výběr hodnot na základě zadané podmínky metodou Series.mask

11. Vliv nepovinného parametru inplace na metodu Series.mask

12. Výběr hodnot na základě zadané podmínky metodou Series.where

13. Vliv nepovinného parametru inplace na metodu Series.where

14. Skutečná filtrace dat kombinující Series.where a Series.dropna

15. Alternativní způsob založený na kombinaci Series.mask a Series.dropna

16. Výběr prvků metodou Series.filter

17. Jedna z variant metody Series.groupby aplikovaná na datovou řadu

18. Obsah následující části seriálu

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

20. Odkazy na Internetu

1. Knihovna Pandas: pokročilejší práce s datovými řadami (series)

Ve čtvrtém pokračování miniseriálu o knihovně Pandas dokončíme popis práce s datovými řadami neboli s typem Series. Zabývat se budeme především transformací dat, jejich filtrací a v neposlední řadě také se seskupováním dat podle zadaných kritérií. Připomeňme si, že tento datový typ slouží v knihovně Pandas pro uložení jednoho sloupce hodnot, přičemž celá datová řada může být pojmenována a současně mohou mít jednotlivé řádky datové řady přiřazen index – v případě indexu se přitom nemusí jednat o celé číslo (jako by tomu bylo u polí či seznamů), ale například o řetězec nebo faktor, resp. přesněji řečeno o kategorii (což je poměrně často využíváno v praxi).

Většina dnes použitých demonstračních příkladů bude používat tento zdrojový soubor s tabulkou:

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
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

2. Iterace přes všechny prvky datové řady

Nejprve si ukažme, jakým způsobem je možné procházet všemi prvky datové řady. K tomuto účelu slouží metoda nazvaná Series.items, která v každé iteraci vrací dvojici (tuple) s indexem i hodnotou příslušného prvku. Základní způsob použití je ukázán na dnešním prvním demonstračním příkladu, který vypadá následovně:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu Series
print(s)
 
# iterace nad prvky rady
for index, value in s.items():
    print("Index: {:20}  Value: {:5.3}".format(index, value))

Výsledek získaný po spuštění tohoto příkladu:

Samotný datový rámec:

                   Sep 2020  Sep 2019  Change  Ratings  Changep
Language
C                         1         2  change    15.95     0.74
Java                      2         1  change    13.48    -3.18
Python                    3         3     NaN    10.47     0.59
C++                       4         4     NaN     7.11     1.48
C#                        5         5     NaN     4.58     1.18
Visual Basic              6         6     NaN     4.12     0.83
JavaScript                7         7     NaN     2.54     0.41
PHP                       8         9  change     2.49     0.62
R                         9        19  change     2.37     1.33
SQL                      10         8  change     1.76    -0.19
Go                       11        14  change     1.46     0.24
Swift                    12        16  change     1.38     0.28
Perl                     13        20  change     1.30     0.26
Assembly language        14        12  change     1.30    -0.08
Ruby                     15        15     NaN     1.24     0.03
MATLAB                   16        18  change     1.10     0.04
Groovy                   17        11  change     0.99    -0.52
Rust                     18        33  change     0.92     0.55
Objective-C              19        10  change     0.85    -0.99
Dart                     20        24  change     0.77     0.13

Jedna datová řada přečtená z datového rámce:

Language
C                    15.95
Java                 13.48
Python               10.47
C++                   7.11
C#                    4.58
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   1.76
Go                    1.46
Swift                 1.38
Perl                  1.30
Assembly language     1.30
Ruby                  1.24
MATLAB                1.10
Groovy                0.99
Rust                  0.92
Objective-C           0.85
Dart                  0.77
Name: Ratings, dtype: float64

Výsledek průchodu všemi prvky datového rámce:

Index: C                     Value:  15.9
Index: Java                  Value:  13.5
Index: Python                Value:  10.5
Index: C++                   Value:  7.11
Index: C#                    Value:  4.58
Index: Visual Basic          Value:  4.12
Index: JavaScript            Value:  2.54
Index: PHP                   Value:  2.49
Index: R                     Value:  2.37
Index: SQL                   Value:  1.76
Index: Go                    Value:  1.46
Index: Swift                 Value:  1.38
Index: Perl                  Value:   1.3
Index: Assembly language     Value:   1.3
Index: Ruby                  Value:  1.24
Index: MATLAB                Value:   1.1
Index: Groovy                Value:  0.99
Index: Rust                  Value:  0.92
Index: Objective-C           Value:  0.85
Index: Dart                  Value:  0.77

Alternativně je možné namísto metody Series.items použít metodu nazvanou Series.iteritems:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu Series
print(s)
 
# iterace nad prvky rady
for index, value in s.iteritems():
    print("Index: {:20}  Value: {:5.3}".format(index, value))
Poznámka: výsledky jsou totožné s prvním demonstračním příkladem, takže si je zde nemusíme uvádět.

3. Postupná aplikace vybrané funkce na všechny prvky datové řady

Poměrně často se setkáme s nutností aplikovat nějakou funkci (postupně) na všechny prvky datové řady. V knihovně Pandas k tomuto účelu slouží metoda nazvaná Series.map, které se předá funkce či anonymní funkce, jenž je následně volána pro jednotlivé prvky datové řady. Výsledkem je nová datová řada – je tedy zvolen funkcionální přístup. V dalším příkladu nahradíme hodnoty reprezentované v procentech za podíly/poměry:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print("In percents")
print(s)
print()
 
# převod na skutečný poměr <0, 1>
s2 = s.map(lambda x: x/100.0)
 
# tisk obsahu nové datové řady
print("As ratios")
print(s2)

Výsledek – nová datová řada:

As ratios
Language
C                    0.1595
Java                 0.1348
Python               0.1047
C++                  0.0711
C#                   0.0458
Visual Basic         0.0412
JavaScript           0.0254
PHP                  0.0249
R                    0.0237
SQL                  0.0176
Go                   0.0146
Swift                0.0138
Perl                 0.0130
Assembly language    0.0130
Ruby                 0.0124
MATLAB               0.0110
Groovy               0.0099
Rust                 0.0092
Objective-C          0.0085
Dart                 0.0077
Name: Ratings, dtype: float64

Alternativně je možné namísto anonymní funkce předat referenci na funkci, v našem konkrétním případě na metodu String.format objektu string (první parametr self je tedy naplněn automaticky):

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print("In percents")
print(s)
print()
 
# formát hodnot v datové řadě
s2 = s.map("Rating is {:4.1f} %".format)
 
# tisk obsahu nové datové řady
print("As ratings")
print(s2)

Po spuštění tohoto příkladu by se měl zobrazit obsah nové datové řady:

As ratings
Language
C                    Rating is 15.9 %
Java                 Rating is 13.5 %
Python               Rating is 10.5 %
C++                  Rating is  7.1 %
C#                   Rating is  4.6 %
Visual Basic         Rating is  4.1 %
JavaScript           Rating is  2.5 %
PHP                  Rating is  2.5 %
R                    Rating is  2.4 %
SQL                  Rating is  1.8 %
Go                   Rating is  1.5 %
Swift                Rating is  1.4 %
Perl                 Rating is  1.3 %
Assembly language    Rating is  1.3 %
Ruby                 Rating is  1.2 %
MATLAB               Rating is  1.1 %
Groovy               Rating is  1.0 %
Rust                 Rating is  0.9 %
Objective-C          Rating is  0.8 %
Dart                 Rating is  0.8 %
Name: Ratings, dtype: object

4. Použití slovníku ve funkci mapy

V případě, že metodě Series.map nepředáme funkci, ale slovník, bude tento slovník použit pro přemapování prvků na nové hodnoty. Pokud prvek ve slovníku nebude nalezen, vrátí se hodnota NaN. Ukažme si jednoduchý příklad převzatý z oficiální dokumentace knihovny Pandas:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
import numpy as np
 
# přečtení zdrojových dat
s = pandas.Series(['cat', 'dog', np.nan, 'rabbit'])
 
# tisk obsahu původní datové řady
print(s)
print()
 
mapping = {'cat': 'kitten',
           'dog': 'puppy'}
 
# mapování hodnot
s2 = s.map(mapping)
 
# tisk obsahu nové datové řady
print(s2)

Z výpisu je patrné, jak se původní prvky přemapovaly na prvky nové, přičemž u posledního prvku nebylo mapování nalezeno, takže se vrátila hodnota NaN:

0       cat
1       dog
2       NaN
3    rabbit
dtype: object
 
0    kitten
1     puppy
2       NaN
3       NaN
dtype: object

Celý příklad lze samozřejmě zkrátit a zapsat mapu přímo do volání metody Series.map, například následujícím způsobem:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
import numpy as np
 
# přečtení zdrojových dat
s = pandas.Series(['cat', 'dog', np.nan, 'rabbit'])
 
# tisk obsahu původní datové řady
print(s)
print()
 
# mapování hodnot
s2 = s.map({'cat': 'kitten',
            'dog': 'puppy'})
 
# tisk obsahu nové datové řady
print(s2)

Výsledek by měl být totožný s předchozím příkladem:

0       cat
1       dog
2       NaN
3    rabbit
dtype: object
 
0    kitten
1     puppy
2       NaN
3       NaN
dtype: object

5. Transformace dat v datové řadě

Kromě metody Series.map lze použít i obecnější metodu Series.transform, která taktéž slouží k transformaci údajů v datové řadě. Ukažme si nejdříve použití této metody, které vychází z předchozích demonstračních příkladů:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print("In percents")
print(s)
print()
 
# převod na skutečný poměr <0, 1>
s2 = s.transform(lambda x: x/100.0)
 
# tisk obsahu nové datové řady
print("As ratios")
print(s2)

S výsledkem:

Sep 2020  Sep 2019  Change  Ratings  Changep
Language
C                         1         2  change    15.95     0.74
Java                      2         1  change    13.48    -3.18
Python                    3         3     NaN    10.47     0.59
C++                       4         4     NaN     7.11     1.48
C#                        5         5     NaN     4.58     1.18
Visual Basic              6         6     NaN     4.12     0.83
JavaScript                7         7     NaN     2.54     0.41
PHP                       8         9  change     2.49     0.62
R                         9        19  change     2.37     1.33
SQL                      10         8  change     1.76    -0.19
Go                       11        14  change     1.46     0.24
Swift                    12        16  change     1.38     0.28
Perl                     13        20  change     1.30     0.26
Assembly language        14        12  change     1.30    -0.08
Ruby                     15        15     NaN     1.24     0.03
MATLAB                   16        18  change     1.10     0.04
Groovy                   17        11  change     0.99    -0.52
Rust                     18        33  change     0.92     0.55
Objective-C              19        10  change     0.85    -0.99
Dart                     20        24  change     0.77     0.13
 
In percents
Language
C                    15.95
Java                 13.48
Python               10.47
C++                   7.11
C#                    4.58
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   1.76
Go                    1.46
Swift                 1.38
Perl                  1.30
Assembly language     1.30
Ruby                  1.24
MATLAB                1.10
Groovy                0.99
Rust                  0.92
Objective-C           0.85
Dart                  0.77
Name: Ratings, dtype: float64
 
As ratios
Language
C                    0.1595
Java                 0.1348
Python               0.1047
C++                  0.0711
C#                   0.0458
Visual Basic         0.0412
JavaScript           0.0254
PHP                  0.0249
R                    0.0237
SQL                  0.0176
Go                   0.0146
Swift                0.0138
Perl                 0.0130
Assembly language    0.0130
Ruby                 0.0124
MATLAB               0.0110
Groovy               0.0099
Rust                 0.0092
Objective-C          0.0085
Dart                 0.0077
Name: Ratings, dtype: float64

6. Vytvoření více sloupců s transformovanými daty

Ve skutečnosti mohou být transformace obecnější a můžeme díky nim vytvořit z datové řady datový rámec s větším množstvím sloupců. Transformace může vypadat následovně:

# převod na skutečný poměr <0, 1>
s2 = s.transform([lambda x: x, lambda x: x/100.0])
Poznámka: povšimněte si, že obě anonymní funkce jsou zapsány v seznamu, tedy uvnitř hranatých závorek.

Výsledkem bude nikoli jeden sloupec (tedy klasická datová řada), ale sloupce dva, které sdílí společný index:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print("In percents")
print(s)
print()
 
# převod na skutečný poměr <0, 1>
s2 = s.transform([lambda x: x, lambda x: x/100.0])
 
# tisk obsahu nové datové řady
print("In percents and also as ratios")
print(s2)

Výsledek bude vypadat následovně:

In percents and also as ratios
                   <lambda>  <lambda>
Language
C                     15.95    0.1595
Java                  13.48    0.1348
Python                10.47    0.1047
C++                    7.11    0.0711
C#                     4.58    0.0458
Visual Basic           4.12    0.0412
JavaScript             2.54    0.0254
PHP                    2.49    0.0249
R                      2.37    0.0237
SQL                    1.76    0.0176
Go                     1.46    0.0146
Swift                  1.38    0.0138
Perl                   1.30    0.0130
Assembly language      1.30    0.0130
Ruby                   1.24    0.0124
MATLAB                 1.10    0.0110
Groovy                 0.99    0.0099
Rust                   0.92    0.0092
Objective-C            0.85    0.0085
Dart                   0.77    0.0077

Namísto anonymních funkcí nám samozřejmě nic nebrání použít již existující (neanonymní) funkci, například numpy.round:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
  import pandas
import numpy as np
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print("In percents")
print(s)
print()
 
# převod na skutečný poměr <0, 1>
s2 = s.transform([lambda x: x, lambda x: x/100.0, np.round])
 
# tisk obsahu nové datové řady
print("In percents and also as ratios")
print(s2)

Opět si ukažme výsledek:

In percents and also as ratios
                   <lambda>  <lambda>  round_
Language
C                     15.95    0.1595    16.0
Java                  13.48    0.1348    13.0
Python                10.47    0.1047    10.0
C++                    7.11    0.0711     7.0
C#                     4.58    0.0458     5.0
Visual Basic           4.12    0.0412     4.0
JavaScript             2.54    0.0254     3.0
PHP                    2.49    0.0249     2.0
R                      2.37    0.0237     2.0
SQL                    1.76    0.0176     2.0
Go                     1.46    0.0146     1.0
Swift                  1.38    0.0138     1.0
Perl                   1.30    0.0130     1.0
Assembly language      1.30    0.0130     1.0
Ruby                   1.24    0.0124     1.0
MATLAB                 1.10    0.0110     1.0
Groovy                 0.99    0.0099     1.0
Rust                   0.92    0.0092     1.0
Objective-C            0.85    0.0085     1.0
Dart                   0.77    0.0077     1.0

Dokonce můžeme potřebnou transformační funkci předat formou jména (řetězce), což může být užitečné při tvorbě těch aplikací, které umožňují výběr funkce přes uživatelské rozhraní, přečtení funkce z konfiguračního souboru atd.:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print("In percents")
print(s)
print()
 
# transformace řady
s2 = s.transform(["round"])
 
# tisk obsahu nové datové řady
print("Rounded")
print(s2)

Nyní bude výsledek vypadat takto:

Rounded
                   round
Language
C                   16.0
Java                13.0
Python              10.0
C++                  7.0
C#                   5.0
Visual Basic         4.0
JavaScript           3.0
PHP                  2.0
R                    2.0
SQL                  2.0
Go                   1.0
Swift                1.0
Perl                 1.0
Assembly language    1.0
Ruby                 1.0
MATLAB               1.0
Groovy               1.0
Rust                 1.0
Objective-C          1.0
Dart                 1.0

7. Agregace informací z datové řady

Další velmi často vyžadovanou operací je agregace informací z datové řady. Agregací se myslí například nalezení největšího prvku, výpočet průměru, součtu (sumy) či součinu (produktu) všech prvků atd. Výsledkem přitom bude nová datová řada. Podívejme se nyní na příklad, který možnosti agregace informací dobře ilustruje:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
import numpy as np
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print("In percents")
print(s)
print()
 
# agregace výsledků
results = s.aggregate([np.min, np.max, np.sum, np.mean])
 
# tisk výsledku
print("Results")
print(results)

Po spuštění by se měla vypsat nová datová řada s minimální a maximální nalezenou hodnotou, se součtem prvků a taktéž s jejich průměrem:

Results
min      0.770
max     15.950
sum     76.180
mean     3.809
Name: Ratings, dtype: float64

8. Použití jmen funkcí namísto jejich referencí v metodě Series.aggregate

V metodě Series.aggregate je možné, ostatně podobně jako tomu bylo i v případě metody Series.transform, použít namísto anonymních funkcí či referencí na pojmenované funkce i přímo jména funkcí reprezentovaná řetězcem. Předchozí demonstrační příklad by tedy bylo možné přepsat i tímto způsobem:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print("In percents")
print(s)
print()
 
# agregace výsledků
results = s.aggregate(["min", "max", "sum", "mean"])
 
# tisk výsledku
print("Results")
print(results)

S výsledkem:

Results
min      0.770
max     15.950
sum     76.180
mean     3.809
Name: Ratings, dtype: float64

Namísto metody Series.aggregate můžete použít i zkrácené jméno této metody Series.agg:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print("In percents")
print(s)
print()
 
# agregace výsledků
results = s.agg(["min", "max", "sum", "mean"])
 
# tisk výsledku
print("Results")
print(results)

S výsledkem:

Results
amin     0.770
amax    15.950
sum     76.180
mean     3.809
Name: Ratings, dtype: float64

9. Kombinace údajů ze dvou datových řad, popř. datové řady a skalární hodnoty

Další užitečná metoda určená pro zpracování hodnot v datových řadách je metoda nazvaná Series.combine. Tato metoda umožňuje zkombinovat prvky dvou řad (pokud jsou jejich indexy kompatibilní), popř. prvky jedné řady se skalární hodnotou. Ukažme si nyní druhý zmíněný případ, kdy zkombinujeme (postupně) hodnotu prvků z datové řady s hodnotou 2, resp. 10, přičemž kombinace bude provedena funkcemi min a max. V prvním případě tedy nahradíme ty prvky z řady, které jsou větší než 10 hodnotou 10 a následně ty prvky z řady, které jsou menší než 2 právě hodnotou 2:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print(s)
print()
 
# omezení hodnot
results = s.combine(10, min)
 
# tisk výsledku
print("Bound (max)")
print(results)
 
# omezení hodnot
results = results.combine(2, max)
 
# tisk výsledku
print("Bound (min)")
print(results)

Postupná tvorba výsledné datové řady je ukázána na výpisu získaného po spuštění tohoto demonstračního příkladu:

Obsah původní datové řady:

Language
C                    15.95
Java                 13.48
Python               10.47
C++                   7.11
C#                    4.58
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   1.76
Go                    1.46
Swift                 1.38
Perl                  1.30
Assembly language     1.30
Ruby                  1.24
MATLAB                1.10
Groovy                0.99
Rust                  0.92
Objective-C           0.85
Dart                  0.77
Name: Ratings, dtype: float64

Nahrazení prvků s hodnotou vyšší než 10 za hodnotu 10:

Bound (max)
Language
C                    10.00
Java                 10.00
Python               10.00
C++                   7.11
C#                    4.58
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   1.76
Go                    1.46
Swift                 1.38
Perl                  1.30
Assembly language     1.30
Ruby                  1.24
MATLAB                1.10
Groovy                0.99
Rust                  0.92
Objective-C           0.85
Dart                  0.77
Name: Ratings, dtype: float64

Nahrazení prvků s hodnotou menší než 2 za hodnotu 2:

Bound (min)
Language
C                    10.00
Java                 10.00
Python               10.00
C++                   7.11
C#                    4.58
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   2.00
Go                    2.00
Swift                 2.00
Perl                  2.00
Assembly language     2.00
Ruby                  2.00
MATLAB                2.00
Groovy                2.00
Rust                  2.00
Objective-C           2.00
Dart                  2.00
Name: Ratings, dtype: float64

10. Výběr hodnot na základě zadané podmínky metodou Series.mask

Mnohdy je nutné vybrat pouze některé hodnoty z datové řady, a to na základě určité podmínky. Knihovna Pandas nabízí více způsobů řešení tohoto požadavku. Můžeme například použít metodu nazvanou Series.mask, v níž lze podmínku pro výběr prvků zapsat způsobem:

# maskování hodnot
results = results.mask(s < 2)

Tato metoda vrátí novou datovou řadu, v níž budou prvky odpovídající zadané podmínce maskovány hodnotou NA nebo NaN, kterou je možné později odstranit.

Poznámka: prvky je možné nahradit i jinou hodnotou než NA/NaN, což si ukážeme v dalším textu na příkladu „inverzní“ metody Series.where.

Úplný kód příkladu vypadá takto:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print(s)
print()
 
# maskování hodnot
results = s.mask(s > 10)
 
# tisk výsledku
print("Masked (max)")
print(results)
 
# maskování hodnot
results = results.mask(s < 2)
 
# tisk výsledku
print("Masked (min)")
print(results)

Výsledky dvojí aplikace masky postavené na podmínce budou vypadat takto:

                   Sep 2020  Sep 2019  Change  Ratings  Changep
Language
C                         1         2  change    15.95     0.74
Java                      2         1  change    13.48    -3.18
Python                    3         3     NaN    10.47     0.59
C++                       4         4     NaN     7.11     1.48
C#                        5         5     NaN     4.58     1.18
Visual Basic              6         6     NaN     4.12     0.83
JavaScript                7         7     NaN     2.54     0.41
PHP                       8         9  change     2.49     0.62
R                         9        19  change     2.37     1.33
SQL                      10         8  change     1.76    -0.19
Go                       11        14  change     1.46     0.24
Swift                    12        16  change     1.38     0.28
Perl                     13        20  change     1.30     0.26
Assembly language        14        12  change     1.30    -0.08
Ruby                     15        15     NaN     1.24     0.03
MATLAB                   16        18  change     1.10     0.04
Groovy                   17        11  change     0.99    -0.52
Rust                     18        33  change     0.92     0.55
Objective-C              19        10  change     0.85    -0.99
Dart                     20        24  change     0.77     0.13

Původní řada:

Language
C                    15.95
Java                 13.48
Python               10.47
C++                   7.11
C#                    4.58
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   1.76
Go                    1.46
Swift                 1.38
Perl                  1.30
Assembly language     1.30
Ruby                  1.24
MATLAB                1.10
Groovy                0.99
Rust                  0.92
Objective-C           0.85
Dart                  0.77
Name: Ratings, dtype: float64

Maska pro prvky větší než 10:

Masked (max)
Language
C                     NaN
Java                  NaN
Python                NaN
C++                  7.11
C#                   4.58
Visual Basic         4.12
JavaScript           2.54
PHP                  2.49
R                    2.37
SQL                  1.76
Go                   1.46
Swift                1.38
Perl                 1.30
Assembly language    1.30
Ruby                 1.24
MATLAB               1.10
Groovy               0.99
Rust                 0.92
Objective-C          0.85
Dart                 0.77
Name: Ratings, dtype: float64

Druhá maska pro prvky menší než 2:

Masked (min)
Language
C                     NaN
Java                  NaN
Python                NaN
C++                  7.11
C#                   4.58
Visual Basic         4.12
JavaScript           2.54
PHP                  2.49
R                    2.37
SQL                   NaN
Go                    NaN
Swift                 NaN
Perl                  NaN
Assembly language     NaN
Ruby                  NaN
MATLAB                NaN
Groovy                NaN
Rust                  NaN
Objective-C           NaN
Dart                  NaN
Name: Ratings, dtype: float64
Poznámka: možné je i zřetězení operací:
# maskování hodnot
results = s.mask(s > 10).mask(s < 2)

11. Vliv nepovinného parametru inplace na metodu Series.mask

V předchozí kapitole jsme si ukázali základní použití metody Series.mask aplikované na datovou řadu, která se nijak nezměnila – metoda Series.mask „pouze“ vrátila novou datovou řadu jako svůj výsledek. To je sice velmi užitečné chování (funkcionální styl), ovšem u rozsáhlých datových řad je mnohdy výhodnější provádět maskování prvků přímo v dané datové řadě bez kopírování. I tuto funkcionalitu v knihovně Pandas nalezneme – musíme použít nepovinný parametr inplace a přiřadit mu hodnotu True:

# maskování hodnot
s.mask(s < 2, inplace=True)

V následujícím demonstračním příkladu se provádí maskování prvků přímo v dané datové sérii – Series.mask je tedy v tomto případě „mutátorem“:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print(s)
print()
 
# maskování hodnot
s.mask(s > 10, inplace=True)
 
# tisk výsledku
print("Masked (max)")
print(s)
 
# maskování hodnot
s.mask(s < 2, inplace=True)
 
# tisk výsledku
print("Masked (min)")
print(s)

Výsledkem je postupně modifikovaná datová řada:

Masked (max)
Language
C                     NaN
Java                  NaN
Python                NaN
C++                  7.11
C#                   4.58
Visual Basic         4.12
JavaScript           2.54
PHP                  2.49
R                    2.37
SQL                  1.76
Go                   1.46
Swift                1.38
Perl                 1.30
Assembly language    1.30
Ruby                 1.24
MATLAB               1.10
Groovy               0.99
Rust                 0.92
Objective-C          0.85
Dart                 0.77
Name: Ratings, dtype: float64
 
Masked (min)
Language
C                     NaN
Java                  NaN
Python                NaN
C++                  7.11
C#                   4.58
Visual Basic         4.12
JavaScript           2.54
PHP                  2.49
R                    2.37
SQL                   NaN
Go                    NaN
Swift                 NaN
Perl                  NaN
Assembly language     NaN
Ruby                  NaN
MATLAB                NaN
Groovy                NaN
Rust                  NaN
Objective-C           NaN
Dart                  NaN
Name: Ratings, dtype: float64

Pokud ovšem nepovinný parametr inplace explicitně nastavíme na hodnotu False, k modifikaci původních prvků datové řady nedojde:

# maskování hodnot
s.mask(s > 10, inplace=False)

Můžeme se o tom ostatně velmi jednoduše přesvědčit:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print(s)
print()
 
# maskování hodnot
s.mask(s > 10, inplace=False)
 
# tisk výsledku
print("Masked (max)")
print(s)
 
# maskování hodnot
s.mask(s < 2, inplace=False)
 
# tisk výsledku
print("Masked (min)")
print(s)

Datová řada obsahuje i po zavolání metody Series.mask původní hodnoty, resp. přesněji řečeno prvky s původní hodnotou:

Masked (max)
Language
C                    15.95
Java                 13.48
Python               10.47
C++                   7.11
C#                    4.58
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   1.76
Go                    1.46
Swift                 1.38
Perl                  1.30
Assembly language     1.30
Ruby                  1.24
MATLAB                1.10
Groovy                0.99
Rust                  0.92
Objective-C           0.85
Dart                  0.77
Name: Ratings, dtype: float64
 
Masked (min)
Language
C                    15.95
Java                 13.48
Python               10.47
C++                   7.11
C#                    4.58
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   1.76
Go                    1.46
Swift                 1.38
Perl                  1.30
Assembly language     1.30
Ruby                  1.24
MATLAB                1.10
Groovy                0.99
Rust                  0.92
Objective-C           0.85
Dart                  0.77
Name: Ratings, dtype: float64

12. Výběr hodnot na základě zadané podmínky metodou Series.where

Alternativou k metodě Series.mask je metoda nazvaná Series.where, která dokáže změnit vybrané prvky na určitou hodnotu – je tedy přesným opakem metody Series.mask. Použití je přímočaré – nejdříve zaměníme ty prvky, jejichž hodnota je menší než 2:

# maskování hodnot
results = results.where(s > 2, "Nic moc")

Poté (v nové datové řadě) pro změnu zaměníme ty prvky, jejichž hodnota je větší než 10:

# maskování hodnot
results = s.where(s < 10, "Dobře")

Lze použít i zřetězení operací:

# maskování hodnot
results = s.where(s < 10, "Dobře").where(s > 2, "Nic moc")

Úplný kód příkladu:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print(s)
print()
 
# maskování hodnot
results = s.where(s < 10, "Dobře")
 
# tisk výsledku
print(results)
 
# maskování hodnot
results = results.where(s > 2, "Nic moc")
 
# tisk výsledku
print(results)

S tímto výsledkem:

Language
C                    15.95
Java                 13.48
Python               10.47
C++                   7.11
C#                    4.58
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   1.76
Go                    1.46
Swift                 1.38
Perl                  1.30
Assembly language     1.30
Ruby                  1.24
MATLAB                1.10
Groovy                0.99
Rust                  0.92
Objective-C           0.85
Dart                  0.77
Name: Ratings, dtype: float64

První náhrada prvků:

Language
C                    Dobře
Java                 Dobře
Python               Dobře
C++                   7.11
C#                    4.58
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   1.76
Go                    1.46
Swift                 1.38
Perl                   1.3
Assembly language      1.3
Ruby                  1.24
MATLAB                 1.1
Groovy                0.99
Rust                  0.92
Objective-C           0.85
Dart                  0.77
Name: Ratings, dtype: object

Navazující náhrada prvků:

Language
C                      Dobře
Java                   Dobře
Python                 Dobře
C++                     7.11
C#                      4.58
Visual Basic            4.12
JavaScript              2.54
PHP                     2.49
R                       2.37
SQL                  Nic moc
Go                   Nic moc
Swift                Nic moc
Perl                 Nic moc
Assembly language    Nic moc
Ruby                 Nic moc
MATLAB               Nic moc
Groovy               Nic moc
Rust                 Nic moc
Objective-C          Nic moc
Dart                 Nic moc
Name: Ratings, dtype: object

13. Vliv nepovinného parametru inplace na metodu Series.where

Metoda Series.where je v mnoha ohledech podobná metodě Series.mask, takže asi není velkým překvapením, že i v ní je možné použít parametr inplace, který zajistí (pokud je nastaven na True), že se změní přímo hodnoty prvků ve zdrojové datové řadě:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print(s)
print()
 
# maskování hodnot
s.where(s < 10, "Dobře", inplace=True)
 
# tisk výsledku
print(s)

Výsledek:

                   Sep 2020  Sep 2019  Change  Ratings  Changep
Language
C                         1         2  change    15.95     0.74
Java                      2         1  change    13.48    -3.18
Python                    3         3     NaN    10.47     0.59
C++                       4         4     NaN     7.11     1.48
C#                        5         5     NaN     4.58     1.18
Visual Basic              6         6     NaN     4.12     0.83
JavaScript                7         7     NaN     2.54     0.41
PHP                       8         9  change     2.49     0.62
R                         9        19  change     2.37     1.33
SQL                      10         8  change     1.76    -0.19
Go                       11        14  change     1.46     0.24
Swift                    12        16  change     1.38     0.28
Perl                     13        20  change     1.30     0.26
Assembly language        14        12  change     1.30    -0.08
Ruby                     15        15     NaN     1.24     0.03
MATLAB                   16        18  change     1.10     0.04
Groovy                   17        11  change     0.99    -0.52
Rust                     18        33  change     0.92     0.55
Objective-C              19        10  change     0.85    -0.99
Dart                     20        24  change     0.77     0.13

Původní datová řada:

Language
C                    15.95
Java                 13.48
Python               10.47
C++                   7.11
C#                    4.58
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   1.76
Go                    1.46
Swift                 1.38
Perl                  1.30
Assembly language     1.30
Ruby                  1.24
MATLAB                1.10
Groovy                0.99
Rust                  0.92
Objective-C           0.85
Dart                  0.77
Name: Ratings, dtype: float64

První úprava prvků (in-place):

Language
C                    Dobře
Java                 Dobře
Python               Dobře
C++                   7.11
C#                    4.58
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   1.76
Go                    1.46
Swift                 1.38
Perl                   1.3
Assembly language      1.3
Ruby                  1.24
MATLAB                 1.1
Groovy                0.99
Rust                  0.92
Objective-C           0.85
Dart                  0.77
Name: Ratings, dtype: object

Pochopitelně ve chvíli, kdy je inplace=False, nebude původní datová řada modifikována:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print(s)
print()
 
# maskování hodnot
s.where(s < 10, "Dobře", inplace=False)
 
# tisk výsledku
print(s)

Výsledek:

Language
C                    15.95
Java                 13.48
Python               10.47
C++                   7.11
C#                    4.58
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   1.76
Go                    1.46
Swift                 1.38
Perl                  1.30
Assembly language     1.30
Ruby                  1.24
MATLAB                1.10
Groovy                0.99
Rust                  0.92
Objective-C           0.85
Dart                  0.77
Name: Ratings, dtype: float64
Language
C                    15.95
Java                 13.48
Python               10.47
C++                   7.11
C#                    4.58
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   1.76
Go                    1.46
Swift                 1.38
Perl                  1.30
Assembly language     1.30
Ruby                  1.24
MATLAB                1.10
Groovy                0.99
Rust                  0.92
Objective-C           0.85
Dart                  0.77
Name: Ratings, dtype: float64

14. Skutečná filtrace dat kombinující Series.where a Series.dropna

V předchozích příkladech jsme „pouze“ nahrazovali prvky na základě splnění či nesplnění podmínky za hodnoty NaN, popř. NA. Tyto hodnoty je možné snadno z datové řady odstranit, a to s využitím metody dropna:

# maskování hodnot
results = s.where(s < 10)
 
results = results.dropna()

Popř. v jediném výrazu:

# maskování hodnot
results = s.where(s < 10).dropna()

Jedná se tedy vlastně o obdobu funkce typu filter známou z jiných jazyků či knihoven – ovšem pro větší zmatení má Series.filter odlišný význam!

Poznámka: i tato metoda podporuje nepovinný parametr inplace=True s významem, který již známe z předchozího textu.

Ukažme si použití v praxi:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print(s)
print()
 
# maskování hodnot
results = s.where(s < 10)
 
# tisk výsledku
print(results)
 
results = results.dropna()
 
# tisk nového výsledku
print(results)

Mezivýsledek po zavolání Series.where:

Language
C                     NaN
Java                  NaN
Python                NaN
C++                  7.11
C#                   4.58
Visual Basic         4.12
JavaScript           2.54
PHP                  2.49
R                    2.37
SQL                  1.76
Go                   1.46
Swift                1.38
Perl                 1.30
Assembly language    1.30
Ruby                 1.24
MATLAB               1.10
Groovy               0.99
Rust                 0.92
Objective-C          0.85
Dart                 0.77
Name: Ratings, dtype: float64

Konečný výsledek po zavolání dropna:

Language
C++                  7.11
C#                   4.58
Visual Basic         4.12
JavaScript           2.54
PHP                  2.49
R                    2.37
SQL                  1.76
Go                   1.46
Swift                1.38
Perl                 1.30
Assembly language    1.30
Ruby                 1.24
MATLAB               1.10
Groovy               0.99
Rust                 0.92
Objective-C          0.85
Dart                 0.77
Name: Ratings, dtype: float64

15. Alternativní způsob založený na kombinaci Series.mask a Series.dropna

Odstranění prvků splňujících, popř. naopak nesplňujících nějakou podmínku lze zajistit i kombinací metod Series.mask a Series.dropna:

# maskování hodnot
results = s.mask(s < 10)
 
results = results.dropna()

Popř. v jediném příkazu připomínajícím kolonu (pipe):

# maskování hodnot
results = s.mask(s < 10).dropna()

Pro úplnost si uvedeme celý příklad, který je na této kombinaci metod založen:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print(s)
print()
 
# maskování hodnot
results = s.mask(s < 10)
 
# tisk výsledku
print(results)
 
results = results.dropna()
 
# tisk nového výsledku
print(results)

S výsledkem:

Původní datová řada:

Language
C                    15.95
Java                 13.48
Python               10.47
C++                   7.11
C#                    4.58
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   1.76
Go                    1.46
Swift                 1.38
Perl                  1.30
Assembly language     1.30
Ruby                  1.24
MATLAB                1.10
Groovy                0.99
Rust                  0.92
Objective-C           0.85
Dart                  0.77
Name: Ratings, dtype: float64

První krok filtrace dat:

Language
C                    15.95
Java                 13.48
Python               10.47
C++                    NaN
C#                     NaN
Visual Basic           NaN
JavaScript             NaN
PHP                    NaN
R                      NaN
SQL                    NaN
Go                     NaN
Swift                  NaN
Perl                   NaN
Assembly language      NaN
Ruby                   NaN
MATLAB                 NaN
Groovy                 NaN
Rust                   NaN
Objective-C            NaN
Dart                   NaN
Name: Ratings, dtype: float64

Druhý krok filtrace dat:

Language
C         15.95
Java      13.48
Python    10.47
Name: Ratings, dtype: float64

16. Výběr prvků metodou Series.filter

O metodě Series.filter jsme se zmínili v předchozím textu. Tato metoda slouží pro výběr prvků na základě jejich indexu. Například je možné vybrat všechny prvky, jejichž index odpovídá nějakému regulárnímu výrazu (viz zvýrazněná část kódu):

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
print()
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print(s)
print()
 
# maskování hodnot
results = s.filter(regex="C.*")
 
# tisk výsledku
print(results)

Výsledkem bude datová řada obsahující pouze ty prvky, jejichž indexy obsahují znak „C“ následovaný dalším nepovinným textem:

Language
C              15.95
C++             7.11
C#              4.58
Objective-C     0.85
Name: Ratings, dtype: float64

Jazyky nezačínající na „C“:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
print()
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print(s)
print()
 
# maskování hodnot
results = s.filter(regex=r"^[^C].*")
 
# tisk výsledku
print(results)

Výsledek:

Language
Java                 13.48
Python               10.47
Visual Basic          4.12
JavaScript            2.54
PHP                   2.49
R                     2.37
SQL                   1.76
Go                    1.46
Swift                 1.38
Perl                  1.30
Assembly language     1.30
Ruby                  1.24
MATLAB                1.10
Groovy                0.99
Rust                  0.92
Objective-C           0.85
Dart                  0.77
Name: Ratings, dtype: float64

17. Jedna z variant metody Series.groupby aplikovaná na datovou řadu

V závěru dnešního článku si alespoň ve stručnosti popíšeme jednu z variant metody Series.groupby aplikovanou na datovou řadu (protože podobná metoda existuje i pro celé datové rámce). Tato metoda slouží k rozdělení prvků do dvou skupin na základě zadané podmínky:

# rozdělení hodnot
results = s.groupby(s > 10)

S rozdělenými prvky lze provádět různé operace, například vypočítat průměr obou skupin:

# tisk výsledku
print(results.mean())

S výsledkem:

Ratings
False     2.134118
True     13.300000
Name: Ratings, dtype: float64
Poznámka: povšimněte si, že došlo k rozdělení prvků na dvě skupiny – první skupina prvků neodpovídá zadané podmínce, druhá naopak podmínce odpovídá.

Následuje úplný zdrojový kód dnešního posledního demonstračního příkladu:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
import pandas
 
# přečtení zdrojových dat
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
# specifikace indexu - má se získat ze sloupce Language
df.set_index("Language", inplace=True)
 
# pro jistotu si datový rámec zobrazíme
print(df)
 
# konstrukce datové struktury Series (datové řady) z datového rámce
s = pandas.Series(df["Ratings"])
 
# tisk obsahu původní datové řady
print(s)
print()
 
# rozdělení hodnot
results = s.groupby(s > 10)
 
# tisk výsledku
print(results.mean())
Poznámka: možnosti metody Series.groupby jsou ve skutečnosti mnohem větší; více (užitečnějších) operací realizovaných pomocí groupby si popíšeme příště v souvislosti s popisem operací prováděných nad datovými rámci.

18. Obsah následující části seriálu

V navazující části tohoto seriálu se budeme podrobněji zabývat způsobem práce s datovými rámci. Uvidíme, že některé výše popsané metody jsou použitelné i společně s datovými rámci, kde mají shodný či alespoň podobný význam. Taktéž si ukážeme přístup k databázím, tj. čtení či zápis celých datových rámců s využitím rozhraní k databázím (což je opět operace velmi často používaná v praxi).

DT2021 tip

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

Zdrojové kódy všech dnes popsaných demonstračních příkladů určených pro Python 3 a nejnovější stabilní verzi knihovny Pandas 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:

iterace přes všechny prvky datové řady založená na metodě iteritems
# Demonstrační příklad Stručný popis příkladu Cesta
1 data_frame_info1.py výpis obsahu datového rámce https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/da­ta_frame_info1.py
2 data_frame_info2.py výpis prvních pěti řádků z datového rámce https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/da­ta_frame_info2.py
3 data_frame_info3.py výpis informace o typech sloupců v datovém rámci https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/da­ta_frame_info3.py
4 data_frame_info4.py výpis uspořádaného seznamu jmen všech sloupců https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/da­ta_frame_info4.py
5 data_frame_info5.py podrobnější informace o datovém rámci, obsazení paměti atd. https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/da­ta_frame_info5.py
6 data_frame_info6.py podrobnější informace o datovém rámci, obsazení paměti atd. https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/da­ta_frame_info6.py
7 data_frame_info7.py popis os, počtu dimenzí, tvaru a velikosti datového rámce https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/da­ta_frame_info7.py
8 data_frame_info8.py základní statistické informace o datech uložených v rámci https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/da­ta_frame_info8.py
9 data_frame_info9.py výsledkem metody info je nový datový rámec https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/da­ta_frame_info9.py
       
10 plot_kafka_lags.py zobrazení jednoduchého grafu bez použití knihovny Pandas https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_kaf­ka_lags.py
11 plot_kafka_lags_pandas.py zobrazení jednoduchého grafu s použitím knihovny Pandas https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_kaf­ka_lags_pandas.py
12 plot_kafka_lags_pandas2.py snazší způsob vykreslení grafu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_kaf­ka_lags_pandas2.py
13 plot_kafka_lags_pandas_sma3.py přidání klouzavého průměru do grafu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_kaf­ka_lags_pandas_sma3.py
14 plot_kafka_lags_pandas_sma3_.py vylepšení předchozího příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_kaf­ka_lags_pandas_sma3_.py
15 plot_kafka_lags_pandas_sma10.py klouzavý průměr přes deset hodnot https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_kaf­ka_lags_pandas_sma10.py
16 plot_benchmark_results_line_chart.py liniový graf https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_ben­chmark_results_line_chart­.py
17 plot_benchmark_results_bar_chart1.py sloupcový graf https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_ben­chmark_results_bar_chart.py
18 plot_benchmark_results_bar_chart2.py výběr části datového rámce při vykreslování grafu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_ben­chmark_results_bar_chart.py
19 plot_benchmark_results_bar_chart3.py zobecnění předchozího příkladu – zpracování numerických dat ve všech sloupcích https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_ben­chmark_results_bar_chart.py
       
20 check_types1.py kontrola typů sloupců s využitím knihovny Voluptuous https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/chec­k_types1.py
21 check_types2.py kontrola typů sloupců s využitím knihovny Voluptuous https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/chec­k_types2.py
22 check_types3.py kontrola typů sloupců s využitím knihovny Voluptuous https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/chec­k_types3.py
23 check_types4.py kontrola typů sloupců s využitím knihovny Voluptuous https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/chec­k_types4.py
24 check_types5.py kontrola typů sloupců s využitím knihovny Voluptuous https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/chec­k_types5.py
25 opulent_pandas1.py kontrola typů sloupců s využitím knihovny opulent-pandas https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/o­pulent_pandas1.py
26 opulent_pandas2.py kontrola typů sloupců s využitím knihovny opulent-pandas https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/o­pulent_pandas2.py
27 opulent_pandas3.py kontrola typů sloupců s využitím knihovny opulent-pandas https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/o­pulent_pandas3.py
28 opulent_pandas4.py kontrola typů sloupců s využitím knihovny opulent-pandas https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/o­pulent_pandas4.py
       
29 series01.py konstrukce datové řady z n-tice https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series01.py
30 series02.py konstrukce datové řady z n-tice, specifikace indexů https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series02.py
31 series03.py konstrukce datové řady generátorem, specifikace indexů https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series03.py
32 series04.py příliš malý počet indexů předaných konstruktoru https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series04.py
33 series05.py konstrukce datové řady ze slovníku https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series05.py
34 series06.py konstrukce datové řady ze slovníku, vliv pořadí klíčů https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series06.py
35 series07.py konstrukce datové řady z datového typu OrderedDict https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series07.py
36 series08.py vytvoření nové datové řady z řady stávající – výběr prvků na základě jejich indexů https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series08.py
37 series09.py základní statistické informace o prvcích uložených v datové řadě https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series09.py
38 series10.py vektorové operace nad všemi prvky datové řady https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series10.py
39 series11.py vektorové operace nad všemi prvky datové řady – predikáty https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series11.py
40 series12.py vektorové operace nad dvojicí datových řad https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series12.py
41 series13.py výběr prvků na základě podmínky https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series13.py
42 series14.py výběr prvků na základě podmínky https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series14.py
43 series15.py převody mezi různými datovými typy https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series15.py
44 series16.py převody mezi různými datovými typy https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series16.py
45 series17.py převody mezi různými datovými typy https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series17.py
46 series18.py převody mezi různými datovými typy – s hodnotami None https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series18.py
47 series19.py převody mezi různými datovými typy – s hodnotami None https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series19.py
48 series20.py převody mezi různými datovými typy – s hodnotami NaN https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/series20.py
       
49 plot_series01.py vykreslení průběhu funkce sin, hodnoty jsou uloženy v datové řadě https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_se­ries01.py
50 plot_series02.py odlišný typ grafu s vyplněnou plochou pod průběhem funkce https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_se­ries02.py
51 plot_series03.py sloupcový diagram s vertikálně orientovanými sloupci https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_se­ries03.py
52 plot_series04.py sloupcový diagram s horizontálně orientovanými sloupci https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_se­ries04.py
53 plot_series05.py graf s KDE – kernel density estimation https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_se­ries05.py
54 plot_series06.py vykreslení koláčového grafu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_se­ries06.py
55 plot_series07.py použití metody Series.map https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_se­ries07.py
56 plot_series08.py vyhlazení grafu s průběhem zašuměného signálu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_se­ries08.py
57 plot_series09.py vyhlazení grafu s průběhem zašuměného signálu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_se­ries09.py
58 plot_series10.py Gaussovské vyhlazení grafu s průběhem zašuměného signálu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_se­ries10.py
59 plot_series11.py vykreslení tří průběhů do jediného grafu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_se­ries11.py
60 plot_series12.py vykreslení tří podgrafů do jednoho grafu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/plot_se­ries12.py
       
61 series21_map.py postupná aplikace vybrané funkce na všechny prvky datové řady (lambda) https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries21_map.py
62 series22_map.py postupná aplikace vybrané funkce na všechny prvky datové řady (reference na funkci) https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries22_map.py
63 series23_map.py použití slovníku ve funkci mapy https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries23_map.py
64 series24_map.py použití slovníku ve funkci mapy (zkrácená varianta) https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries24_map.py
65 series25_transform.py transformace dat v datové řadě s využitím metody transform https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries25_transform.py
66 series26_transform.py vytvoření více sloupců s transformovanými daty https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries26_transform.py
67 series27_transform.py vytvoření více sloupců s transformovanými daty https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries27_transform.py
68 series28_transform.py použití jmen funkcí ve formě řetězců https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries28_transform.py
69 series29_agg.py agregace informací z datové řady: metoda agg https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries29_agg.py
70 series30_agg.py použití jmen funkcí namísto jejich referencí: metoda agg https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries30_agg.py
71 series31_aggregate.py agregace informací z datové řady: metoda aggregate https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries31_aggregate.py
72 series32_aggregate.py použití jmen funkcí namísto jejich referencí: metoda aggregate https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries32_aggregate.py
73 series33_combine.py kombinace údajů ze dvou datových řad, popř. datové řady a skalární hodnoty https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries33_combine.py
74 series34_mask.py výběr hodnot na základě zadané podmínky metodou mask https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries34_mask.py
75 series35_mask_inplace_true.py vliv nepovinného parametru inplace na metodu mask https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries35_mask_inplace_true.py
76 series36_mask_inplace_false.py vliv nepovinného parametru inplace na metodu mask https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries36_mask_inplace_false­.py 
77 series37_where.py výběr hodnot na základě zadané podmínky metodou where https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries37_where.py
78 series38_where_inplace_true.py vliv nepovinného parametru inplace na metodu where https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries38_where_inplace_true­.py
79 series39_where_inplace_false.py vliv nepovinného parametru inplace na metodu where https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries39_where_inplace_false­.py
80 series40_where_drop.py skutečná filtrace dat kombinující wheredropna https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries40_where_drop.py
81 series41_mask_drop.py alternativní způsob založený na kombinaci maskdropna https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries41_mask_drop.py
82 series42_group_by.py jedna z variant metody groupby aplikovaná na datovou řadu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries42_group_by.py
       
83 series_items.py iterace přes všechny prvky datové řady založená na metodě items https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries_items.py
84 series_iteritems.py https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­ries_iteritems.py

Některé demonstrační příklady načítají následující soubory s daty:

# Datový soubor Stručný popis souboru Cesta
1 integer_values.csv dvousloupcová tabulka s celými čísly https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/in­teger_values.csv
2 missing_integer_values.csv dvousloupcová tabulka s celými čísly, z nichž některé chybí https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/mis­sing_integer_values.csv
3 timestamps.csv tabulka s časovými údaji https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/timestamps.csv
4 custom_timestamps.csv tabulka s časovými údaji používajícími nestandardní formát https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/cus­tom_timestamps.csv
5 denni_kurz.txt semistrukturovaný soubor s nestandardními oddělovači https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/denni_kurz.txt
6 tiobe.tsv data získaná ze stránek Tiobe indexu ve formátu TSV https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/tiobe.tsv
7 tiobe.txt data získaná ze stránek Tiobe indexu v textovém formátu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/tiobe.txt
8 benchmarks1.tsv výsledky benchmarků několika implementací Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/ben­chmarks1.tsv
9 benchmarks2.tsv výsledky benchmarků několika implementací Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/ben­chmarks2.tsv

20. Odkazy na Internetu

  1. Plotting with matplotlib
    https://pandas.pydata.org/pandas-docs/version/0.13/visualization.html
  2. Plot With Pandas: Python Data Visualization for Beginners
    https://realpython.com/pandas-plot-python/
  3. Pandas Dataframe: Plot Examples with Matplotlib and Pyplot
    https://queirozf.com/entries/pandas-dataframe-plot-examples-with-matplotlib-pyplot
  4. Opulent-Pandas na PyPi
    https://pypi.org/project/opulent-pandas/
  5. pandas_validator na PyPi
    https://pypi.org/project/pan­das_validator/
  6. pandas-validator (dokumentace)
    https://pandas-validator.readthedocs.io/en/latest/
  7. 7 Best Python Libraries for Validating Data
    https://www.yeahhub.com/7-best-python-libraries-validating-data/
  8. Universally unique identifier (Wikipedia)
    https://en.wikipedia.org/wi­ki/Universally_unique_iden­tifier
  9. Nullable integer data type
    https://pandas.pydata.org/pandas-docs/stable/user_guide/integer_na.html
  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. XML Schema validator and data conversion library for Python
    https://github.com/brunato/xmlschema
  27. xmlschema 0.9.7
    https://pypi.python.org/py­pi/xmlschema/0.9.7
  28. jsonschema 2.6.0
    https://pypi.python.org/py­pi/jsonschema
  29. warlock 1.3.0
    https://pypi.python.org/pypi/warlock
  30. Python Virtual Environments – A Primer
    https://realpython.com/python-virtual-environments-a-primer/
  31. pip 1.1 documentation: Requirements files
    https://pip.readthedocs.i­o/en/1.1/requirements.html
  32. unittest.mock — mock object library
    https://docs.python.org/3­.5/library/unittest.mock.html
  33. mock 2.0.0
    https://pypi.python.org/pypi/mock
  34. An Introduction to Mocking in Python
    https://www.toptal.com/python/an-introduction-to-mocking-in-python
  35. Unit testing (Wikipedia)
    https://en.wikipedia.org/wi­ki/Unit_testing
  36. Unit testing
    https://cs.wikipedia.org/wi­ki/Unit_testing
  37. Test-driven development (Wikipedia)
    https://en.wikipedia.org/wiki/Test-driven_development
  38. Pip (dokumentace)
    https://pip.pypa.io/en/stable/
  39. 5 Differences between clojure.spec and Schema
    https://lispcast.com/clojure.spec-vs-schema/
  40. Schema: Clojure(Script) library for declarative data description and validation
    https://github.com/plumatic/schema
  41. clojure.spec – Rationale and Overview
    https://clojure.org/about/spec