Hlavní navigace

Knihovna Pandas: základy práce s datovými rámci

26. 11. 2020
Doba čtení: 31 minut

Sdílet

V dnešním článku se stručně seznámíme s takzvanými datovými rámci (data frame) používanými v knihovně Pandas. Budeme se zabývat načtením dat z externích souborů i přímo z internetu a jejich převodem na datový rámec.

Obsah

1. Knihovna Pandas: základy práce s datovými rámci

2. Načtení obsahu jednoduché tabulky ze souboru typu CSV

3. Zpracování prázdných hodnot v tabulce

4. Načtení tabulky obsahující časová razítka

5. Korektní parsing časových razítek

6. Problematika vlastního či specifického formátu data a/nebo času

7. Vlastní parsovací funkce pro časová razítka

8. Čtení tabulky uložené ve formátu TSV

9. Specifikace oddělovače sloupců

10. Import dat z textových souborů

11. Explicitní specifikace šířky sloupců

12. Zpracování souborů s nestandardním formátem

13. Pokus o načtení souboru s nestandardním formátem

14. Specifikace oddělovače

15. Přeskok prvního řádku, který neobsahuje data tabulky ani hlavičku

16. Převod záznamů s desetinnou čárkou na číselné hodnoty

17. Načtení dat přímo z webu

18. Repositář s demonstračními příklady a datovými soubory

19. Články s informacemi o různých způsobech validace datových struktur

20. Odkazy na Internetu

1. Knihovna Pandas: základy práce s datovými rámci

V dnešním článku se – prozatím ve stručnosti – seznámíme s takzvanými datovými rámci (data frame) používanými v knihovně Pandas v programovacím jazyku Python. Jedná se o velmi důležitý datový typ používaný zejména (ale nejenom) při statistických výpočtech. Datové rámce se v určitém ohledu podobají tabulkám používaným v relačních databázích: jednotlivé sloupce jsou pojmenované a současně může být každý sloupec jiného datového typu (všechny prvky ve sloupci toto kritérium musí splňovat, což ovšem vede k určitým problémům, o nichž si řekneme v navazujících kapitolách). Tato vlastnost odlišuje datové rámce od dvourozměrných polí masivně využívaných například v knihovně Numpy; na druhou stranu je ovšem možné s jednotlivými sloupci datového rámce pracovat jako s jednorozměrným polem kompatibilním právě s knihovnou Numpy a jejími datovými typy.

Dnes si popíšeme především na způsob načtení dat do datového rámce. Knihovna Pandas podporuje využití různých datových zdrojů, především pak:

  1. Souborů CSV (Comma-Separated Values)
  2. Souborů TSV (Tab-Separated Values)
  3. Textových souborů s volitelným oddělovačem a formátem sloupců
  4. Tabulek z tabulkových procesorů (xls, xlsx, xlsm, xlsb, odf, ods, odt)
  5. Souborů JSON se strukturovanými daty
  6. Načítání z relačních databází s využitím SQL driverů
  7. Načítání z Parquet souborů
  8. atd.

Zaměříme se na první čtyři formáty, které sice vypadají primitivně, ovšem při načítání je mnohdy nutné řešit mnoho „maličkostí“ typu různé formáty dat, chybějící hodnoty ve sloupcích atd.

2. Načtení obsahu jednoduché tabulky ze souboru typu CSV

CSV neboli Comma-Separated Values [1] je jedním z nejčastěji používaných souborových formátů v této oblasti, a to přesto, že je export a import CSV v některých případech problematický (například některé české mutace Excelu namísto čárek používají středníky, problémy nastávají s buňkami obsahujícími znaky pro konec řádku atd.). Tyto soubory jsou mnohdy obrovské a i z tohoto důvodu se začínají v některých oblastech nahrazovat například za Parquet soubory atd. I přesto se ale s CSV setkáme, a to poměrně často. Příkladem může být export dat z Promethea atd.

Jeden z nejjednodušších příkladů používajících knihovnu Pandas bude načítat soubor CSV (Comma-Separated Values), jehož obsah lze najít na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/in­teger_values.csv. V tomto souboru je uložena tabulka se dvěma sloupci, přičemž soubor má i řádek s hlavičkou (ta někdy může chybět):

Block size,Time to read
1,672512695
2,338152789
3,280886198
4,261732244
5,241726381
6,222869657
7,214296698
8,202491102
9,182263641
10,177141401

V příkladu provedeme načtení souboru s využitím funkce pandas.read_csv, které prozatím předáme jediný parametr obsahující název souboru. Vytvořený datový rámec zobrazíme funkcí print a navíc si necháme vypsat i datové typy přiřazené jednotlivým sloupcům:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading CSV file that contains column with integer values."""
 
import pandas
 
df = pandas.read_csv("integer_values.csv")
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

Povšimněte si, že Pandas korektně vyhodnotila, že CSV obsahuje řádek s hlavičkou. Dokonce byl i korektně odvozen typ dat ve sloupcích (int64):

Data frame
---------------------------
   Block size  Time to read
0           1     672512695
1           2     338152789
2           3     280886198
3           4     261732244
4           5     241726381
5           6     222869657
6           7     214296698
7           8     202491102
8           9     182263641
9          10     177141401
 
Column types
---------------------------
Block size      int64
Time to read    int64
dtype: object
Poznámka: to, že má každý sloupec vlastní datový typ, je možná v Pythonu poněkud neobvyklé (například n-tice nebo seznam používá dynamické typy prvků), ovšem nutné pro zajištění rychlých výpočtů a zmenšení spotřeby operační paměti. Ostatně naprosto stejný přístup nalezneme v knihovně Numpy.

3. Zpracování prázdných hodnot v tabulce

Nyní se pokusme o načtení prakticky stejné tabulky, která se ovšem od první tabulky odlišuje v tom, že jedna hodnota chybí (viz též https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/mis­sing_integer_values.csv). V praxi se s takovými tabulkami pochopitelně setkáme velmi často:

Block size,Time to read
1,672512695
2,338152789
3,280886198
4,261732244
5,
6,222869657
7,214296698
8,202491102
9,182263641
10,177141401

Pokusme se použít stejný kód, jako tomu bylo v předchozí kapitole, pouze změníme jméno vstupního souboru:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading CSV file that contains column with integer values (some are missing)."""
 
import pandas
 
df = pandas.read_csv("missing_integer_values.csv")
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

Výsledek bude překvapivý – celý druhý sloupec byl převeden na hodnoty typu float64:

Data frame
---------------------------
   Block size  Time to read
0           1   672512695.0
1           2   338152789.0
2           3   280886198.0
3           4   261732244.0
4           5           NaN
5           6   222869657.0
6           7   214296698.0
7           8   202491102.0
8           9   182263641.0
9          10   177141401.0
 
Column types
---------------------------
Block size        int64
Time to read    float64
dtype: object

Proč tomu tak je? Knihovna Pandas musí nějakým způsobem reprezentovat chybějící hodnotu a pro tento účel lze (mj.) použít i datový typ float64 neboli double, který podporuje reprezentaci hodnoty NaN neboli Not a Number, viz též https://www.root.cz/clanky/norma-ieee-754-a-pribuzni-formaty-plovouci-radove-tecky/#k03. Což vlastně znamená, že Not a Number je number :-)

Ovšem toto chování nám nemusí z mnoha důvodů vyhovovat, už jen z toho důvodu, že u float64 není splněna vlastnost asociativity u aritmetických operací. Jednou z možností nápravy je použití typu Int64 (nikoli int64), která dokáže uložit i informaci o neexistující hodnotě. Musíme tedy explicitně specifikovat datový typ sloupce nazvaného „Time to read“:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading CSV file that contains column with integer values (some are missing)."""
 
import pandas
 
df = pandas.read_csv("missing_integer_values.csv", dtype={"Time to read": "Int64"})
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

Nyní již dosáhneme očekávaného chování:

Data frame
---------------------------
   Block size  Time to read
0           1     672512695
1           2     338152789
2           3     280886198
3           4     261732244
4           5          <NA>
5           6     222869657
6           7     214296698
7           8     202491102
8           9     182263641
9          10     177141401
 
Column types
---------------------------
Block size      int64
Time to read    Int64
dtype: object

4. Načtení tabulky obsahující časová razítka

Pokusme se nyní načíst tabulku, která ve svém druhém sloupci obsahuje časová razítka, tedy jak plné datum, tak i čas. Jedná se konkrétně o tento soubor:

n,Timestamp
1,2020-01-15 03:59:47
2,2020-01-15 08:19:25
3,2020-01-15 11:42:07
4,2020-01-15 14:58:48
5,2020-01-15 18:21:56
6,2020-01-15 21:10:01
7,2020-01-15 23:13:58
8,2020-01-16 01:51:52
9,2020-01-16 05:55:55
10,2020-01-16 10:11:54
11,2020-01-16 14:02:32
12,2020-01-16 17:35:25
13,2020-01-16 19:35:43
14,2020-01-16 22:29:24

Prozatím při načtení nebudeme žádným způsobem specifikovat typy sloupců, takže vlastně zopakujeme zdrojový kód prvního příkladu:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading CSV with timestamps without parsing."""
 
import pandas
 
df = pandas.read_csv("timestamps.csv")
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

Ovšem z výsledku je patrné, že knihovna Pandas hodnoty ve druhém sloupci načetla a zjistila, že se jedná o typ „objekt“ a nikoli časové razítko:

Data frame
---------------------------
     n            Timestamp
0    1  2020-01-15 03:59:47
1    2  2020-01-15 08:19:25
2    3  2020-01-15 11:42:07
3    4  2020-01-15 14:58:48
4    5  2020-01-15 18:21:56
5    6  2020-01-15 21:10:01
6    7  2020-01-15 23:13:58
7    8  2020-01-16 01:51:52
8    9  2020-01-16 05:55:55
9   10  2020-01-16 10:11:54
10  11  2020-01-16 14:02:32
11  12  2020-01-16 17:35:25
12  13  2020-01-16 19:35:43
13  14  2020-01-16 22:29:24
 
Column types
---------------------------
n             int64
Timestamp    object
dtype: object

5. Korektní parsing časových razítek

Výše uvedené chování nám samozřejmě nebude v mnoha případech vyhovovat, protože budeme chtít s časovými údaji provádět různé operace. Jedno z možných řešení tohoto problému spočívá v tom, že při načítání tabulky funkcí pandas.read_csv použijeme parametr parse_dates, kterému předáme buď hodnotu True (nové verze Pandas) nebo explicitně názvy sloupců, u nichž se má datum zpracovat:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading CSV with timestamps with parsing."""
 
import pandas
 
df = pandas.read_csv("timestamps.csv", parse_dates=["Timestamp"])
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

Ze zobrazeného výsledku je patrné, že se nyní hodnoty ve druhém sloupci tabulky skutečně zpracovaly korektně a jsou reprezentovány typem datetime64 (viz též https://numpy.org/doc/sta­ble/reference/arrays.date­time.html):

Data frame
---------------------------
     n           Timestamp
0    1 2020-01-15 03:59:47
1    2 2020-01-15 08:19:25
2    3 2020-01-15 11:42:07
3    4 2020-01-15 14:58:48
4    5 2020-01-15 18:21:56
5    6 2020-01-15 21:10:01
6    7 2020-01-15 23:13:58
7    8 2020-01-16 01:51:52
8    9 2020-01-16 05:55:55
9   10 2020-01-16 10:11:54
10  11 2020-01-16 14:02:32
11  12 2020-01-16 17:35:25
12  13 2020-01-16 19:35:43
13  14 2020-01-16 22:29:24

Column types
---------------------------
n                     int64
Timestamp    datetime64[ns]
dtype: object

6. Problematika vlastního či specifického formátu data a/nebo času

Nyní se pokusme vyřešit složitější, ale možná o to častější problém – načtení tabulky, v níž se používá specifický formát data a/nebo času. Budeme načítat následující tabulku, v níž je jako oddělovač měsíců a dnů použito lomítko a pro oddělení hodin a minut pak pomlčka (lidská vynalézavost v těchto oblastech je velká, nemluvě již o americkém formátu zápisu data):

n,Timestamp
1,2020/01/15 03-59-47
2,2020/01/15 08-19-25
3,2020/01/15 11-42-07
4,2020/01/15 14-58-48
5,2020/01/15 18-21-56
6,2020/01/15 21-10-01
7,2020/01/15 23-13-58
8,2020/01/16 01-51-52
9,2020/01/16 05-55-55
10,2020/01/16 10-11-54
11,2020/01/16 14-02-32
12,2020/01/16 17-35-25
13,2020/01/16 19-35-43
14,2020/01/16 22-29-24

První varianta skriptu, který se pokusí tuto tabulku načíst a vytvořit z ní datový rámec, může vypadat následovně:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading CSV with custom timestamps format."""
 
import pandas
 
df = pandas.read_csv("custom_timestamps.csv", parse_dates=["Timestamp"])
 
pandas.to_datetime(df.Timestamp)
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

Výsledek ovšem v tomto případě nedopadne nejlépe, protože se Pandas sice pokusí o rozpoznání časových údajů (což jsme ostatně vyžadovali), ale specifický formát nedokáže správně rozkódovat:

Traceback (most recent call last):
  File "/home/ptisnovs/.local/lib/python3.6/site-packages/pandas/core/arrays/datetimes.py", line 2054, in objects_to_datetime64ns
    values, tz_parsed = conversion.datetime_to_datetime64(data)
  File "pandas/_libs/tslibs/conversion.pyx", line 335, in pandas._libs.tslibs.conversion.datetime_to_datetime64
ValueError: Array must be all same time zone
 
During handling of the above exception, another exception occurred:
 
Traceback (most recent call last):
  File "read_custom_timestamps_1.py", line 10, in <module>
    pandas.to_datetime(df.Timestamp)
  File "/home/ptisnovs/.local/lib/python3.6/site-packages/pandas/core/tools/datetimes.py", line 803, in to_datetime
    values = convert_listlike(arg._values, format)
  File "/home/ptisnovs/.local/lib/python3.6/site-packages/pandas/core/tools/datetimes.py", line 466, in _convert_listlike_datetimes
    allow_object=True,
  File "/home/ptisnovs/.local/lib/python3.6/site-packages/pandas/core/arrays/datetimes.py", line 2059, in objects_to_datetime64ns
    raise e
  File "/home/ptisnovs/.local/lib/python3.6/site-packages/pandas/core/arrays/datetimes.py", line 2050, in objects_to_datetime64ns
    require_iso8601=require_iso8601,
  File "pandas/_libs/tslib.pyx", line 352, in pandas._libs.tslib.array_to_datetime
  File "pandas/_libs/tslib.pyx", line 435, in pandas._libs.tslib.array_to_datetime
ValueError: Tz-aware datetime.datetime cannot be converted to datetime64 unless utc=True

7. Vlastní parsovací funkce pro časová razítka

V případě specifických formátů musíme knihovně Pandas předat vlastní parsovací funkci. Ta bude prozatím velmi jednoduchá, protože v ní využijeme možností nabízených standardní knihovnou datetime:

def datetime_parser(raw_data):
    return datetime.datetime.strptime(raw_data, "%Y/%m/%d %H-%M-%S")

Funkce datetime_parser získá zdrojová data (poskytnutá přímo knihovnou Pandas) a pokusí se z těchto údajů vytvořit časové razítko.

Příklad použití této parsovací funkce při načítání datového rámce:

df = pandas.read_csv("custom_timestamps.csv",
                     date_parser=datetime_parser,
                     parse_dates=["Timestamp"])

Úplný zdrojový kód skriptu pro načtení tabulky:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading CSV with custom timestamps format using custom parser."""
 
import pandas
import datetime
 
 
def datetime_parser(raw_data):
    return datetime.datetime.strptime(raw_data, "%Y/%m/%d %H-%M-%S")
 
 
df = pandas.read_csv("custom_timestamps.csv",
                     date_parser=datetime_parser,
                     parse_dates=["Timestamp"])
 
 
pandas.to_datetime(df.Timestamp)
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

Výsledek již vypadá použitelně:

Data frame
---------------------------
     n           Timestamp
0    1 2020-01-15 03:59:47
1    2 2020-01-15 08:19:25
2    3 2020-01-15 11:42:07
3    4 2020-01-15 14:58:48
4    5 2020-01-15 18:21:56
5    6 2020-01-15 21:10:01
6    7 2020-01-15 23:13:58
7    8 2020-01-16 01:51:52
8    9 2020-01-16 05:55:55
9   10 2020-01-16 10:11:54
10  11 2020-01-16 14:02:32
11  12 2020-01-16 17:35:25
12  13 2020-01-16 19:35:43
13  14 2020-01-16 22:29:24
 
Column types
---------------------------
n                     int64
Timestamp    datetime64[ns]
dtype: object

Alternativně je možné kód pro parsing zapsat formou lambda výrazu:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading CSV with custom timestamps format using custom parser."""
 
import pandas
import datetime
 
 
df = pandas.read_csv("custom_timestamps.csv",
                     date_parser=lambda raw_data: datetime.datetime.strptime(raw_data, "%Y/%m/%d %H-%M-%S"),
                     parse_dates=["Timestamp"])
 
 
pandas.to_datetime(df.Timestamp)
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

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

Data frame
---------------------------
     n           Timestamp
0    1 2020-01-15 03:59:47
1    2 2020-01-15 08:19:25
2    3 2020-01-15 11:42:07
3    4 2020-01-15 14:58:48
4    5 2020-01-15 18:21:56
5    6 2020-01-15 21:10:01
6    7 2020-01-15 23:13:58
7    8 2020-01-16 01:51:52
8    9 2020-01-16 05:55:55
9   10 2020-01-16 10:11:54
10  11 2020-01-16 14:02:32
11  12 2020-01-16 17:35:25
12  13 2020-01-16 19:35:43
13  14 2020-01-16 22:29:24
 
Column types
---------------------------
n                     int64
Timestamp    datetime64[ns]
dtype: object

8. Čtení tabulky uložené ve formátu TSV

V dalším kroku se pokusíme načíst soubor https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/tiobe.tsv. TSV neboli Tab-Separated Values [2] [3] je velmi podobným formátem jako CSV, ovšem s tím rozdílem, že oddělovačem jednotlivých buněk je znak tabulátoru (tím současně odpadají mnohé problémy CSV). Podobně jako v případě CSV i zde možnost ukládat na první řádek souboru hlavičku:

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

Při běžném použití importní funkce pandas.read_csv není tento formát správně rozpoznán:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading TSV file that contains column with various values."""
 
import pandas
 
df = pandas.read_csv("tiobe.tsv")
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

Povšimněte si, že se tabulka načetla do jediného sloupce, který obsahuje mj. i znaky TAB, které by měly sloužit jako oddělovače:

Data frame
---------------------------
   Sep 2020\tSep 2019\tChange\tLanguage\tRatings\tChangep
0                       1\t2\tchange\tC\t15.95\t+0.74
1                    2\t1\tchange\tJava\t13.48\t-3.18
2                        3\t3\t\tPython\t10.47\t+0.59
3                            4\t4\t\tC++\t7.11\t+1.48
4                             5\t5\t\tC#\t4.58\t+1.18
5                   6\t6\t\tVisual Basic\t4.12\t+0.83
6                     7\t7\t\tJavaScript\t2.54\t+0.41
7                      8\t9\tchange\tPHP\t2.49\t+0.62
8                       9\t19\tchange\tR\t2.37\t+1.33
9                     10\t8\tchange\tSQL\t1.76\t-0.19
10                    11\t14\tchange\tGo\t1.46\t+0.24
11                 12\t16\tchange\tSwift\t1.38\t+0.28
12                  13\t20\tchange\tPerl\t1.30\t+0.26
13     14\t12\tchange\tAssembly language\t1.30\t-0.08
14                        15\t15\t\tRuby\t1.24\t+0.03
15                16\t18\tchange\tMATLAB\t1.10\t+0.04
16                17\t11\tchange\tGroovy\t0.99\t-0.52
17                  18\t33\tchange\tRust\t0.92\t+0.55
18           19\t10\tchange\tObjective-C\t0.85\t-0.99
19                  20\t24\tchange\tDart\t0.77\t+0.13
 
Column types
---------------------------
Sep 2020\tSep 2019\tChange\tLanguage\tRatings\tChangep    object
dtype: object

9. Specifikace oddělovače sloupců

Soubory TSV lze načíst tak, že nepovinným (pojmenovaným) parametrem sep specifikujeme oddělovač mezi záznamy. V tomto případě se jedná o znak „\t“ (Python používá céčkovský způsob zápisu řídicích znaků):

df = pandas.read_csv("tiobe.tsv", sep="\t")

Upravený příklad:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading TSV file that contains column with various values using custom separator."""
 
import pandas
 
# separator/delimiter specification
df = pandas.read_csv("tiobe.tsv", sep="\t")
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

Nyní již vypadá datový rámec použitelněji (i když bude nutné upravit minimálně obsah sloupce „Change“, například převodem na True/False):

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

10. Import dat z textových souborů

Existuje i mnoho aplikací, v nichž jsou tabulková data uložena ve formě běžných textových souborů s nějakými oddělovači odlišnými od výše zmíněného tabulátoru (relativně často se jedná o středníky, dvojtečky nebo o znak |). Buď se jedná o zobecnění formátů CSV a TSV [4], nebo může mít textový soubor podobu naformátovaných sloupců s pevnou délkou (a tedy bez problémů čitelných uživatelem).

A právě takový soubor je připraven na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/tiobe.txt (povšimněte si toho, že nyní se skutečně mezi buňkami nachází proměnný počet mezer a některé buňky jsou nevyplněny):

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

Pokusme se nyní tento soubor načíst, tentokrát však nikoli funkcí pandas.read_csv, ale funkcí pandas.read_fwf, kde „fwf“ znamená „fixed-width formatted“:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading text file that contains columns with fixed width."""
 
import pandas
 
# separator/delimiter specification not needed there
df = pandas.read_fwf("tiobe.txt")
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

Výsledek ovšem není zcela dokonalý, protože u sloupců, jejichž jména obsahují mezery, došlo k rozdělení na dva sloupce a tím pádem nám vznikly dvě série hodnot NaN:

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

11. Explicitní specifikace šířky sloupců

Předchozí příklad můžeme opravit tak, že explicitně uvedeme šířky sloupců. To konkrétně znamená, že namísto:

df = pandas.read_fwf("tiobe.txt")

Použijeme nepovinný parametr widths, kde šířky nastavíme:

df = pandas.read_fwf("tiobe.txt", widths=(20, 20, 20, 20, 20, 20))

Ostatní části příkladu mohou zůstat nezměněné:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading text file that contains columns with fixed width."""
 
import pandas
 
# separator/delimiter specification not needed there
df = pandas.read_fwf("tiobe.txt", widths=(20, 20, 20, 20, 20, 20))
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

Výsledek je již téměř dokonalý, pokud nám nebudou vadit hodnoty NaN ve sloupci „Change“:

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

12. Zpracování souborů s nestandardním formátem

Mnohé soubory s tabulkovými daty mají ještě jiný formát (což opět odkazuje na velkou lidskou tvořivost a znovuobjevování kola). Příkladem mohou být data, která nalezneme na adrese https://www.cnb.cz/cs/finan­cni_trhy/devizovy_trh/kur­zy_devizoveho_trhu/denni_kur­z.txt. Evidentně se jedná o tabulková a velmi dobře strukturovaná data, která by bylo vhodné umět automaticky zpracovat:

20.11.2020 #224
země|měna|množství|kód|kurz
Austrálie|dolar|1|AUD|16,231
Brazílie|real|1|BRL|4,160
Bulharsko|lev|1|BGN|13,467
Čína|žen-min-pi|1|CNY|3,381
Dánsko|koruna|1|DKK|3,536
EMU|euro|1|EUR|26,340
Filipíny|peso|100|PHP|46,038
Hongkong|dolar|1|HKD|2,864
Chorvatsko|kuna|1|HRK|3,481
Indie|rupie|100|INR|29,950
Indonesie|rupie|1000|IDR|1,567
Island|koruna|100|ISK|16,330
Izrael|nový šekel|1|ILS|6,649
Japonsko|jen|100|JPY|21,383
Jižní Afrika|rand|1|ZAR|1,445
Kanada|dolar|1|CAD|17,011
Korejská republika|won|100|KRW|1,990
Maďarsko|forint|100|HUF|7,328
Malajsie|ringgit|1|MYR|5,425
Mexiko|peso|1|MXN|1,104
MMF|ZPČ|1|XDR|31,598
Norsko|koruna|1|NOK|2,471
Nový Zéland|dolar|1|NZD|15,416
Polsko|zlotý|1|PLN|5,900
Rumunsko|leu|1|RON|5,405
Rusko|rubl|100|RUB|29,180
Singapur|dolar|1|SGD|16,530
Švédsko|koruna|1|SEK|2,577
Švýcarsko|frank|1|CHF|24,363
Thajsko|baht|100|THB|73,313
Turecko|lira|1|TRY|2,911
USA|dolar|1|USD|22,201
Velká Británie|libra|1|GBP|29,464

Problémy, které musíme vyřešit v rámci dalších kapitol:

  1. Ignorování prvního řádku
  2. Specifikace oddělovačů
  3. Zpracování hodnot s desetinnou čárkou (protože bývá zvykem používat zápis s tečkou, s čímž počítají i Pythonovské knihovny)

13. Pokus o načtení souboru s nestandardním formátem

Vzhledem k tomu, že soubor zmíněný v předchozí kapitole obsahuje znaky „|“ ve formě oddělovače, použijeme pro jeho načtení funkci pandas.read_csv a nikoli pandas.read_fwf (ta se totiž hodí pro načítání sloupců s pevnou šířkou). Pro začátek si vyzkoušejme, jak dokáže Pandas rozpoznat či naopak nerozpoznat neznámý formát:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading data file with custom format."""
 
import pandas
 
df = pandas.read_csv("denni_kurz.txt")
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

Výsledek není v žádném případě dokonalý, což značí, že budeme muset lépe a přesněji specifikovat konkrétní použitý formát dat:

Traceback (most recent call last):
  File "read_custom_data_format_1.py", line 8, in <module>
    df = pandas.read_csv("denni_kurz.txt")
  File "/home/ptisnovs/.local/lib/python3.6/site-packages/pandas/io/parsers.py", line 688, in read_csv
    return _read(filepath_or_buffer, kwds)
  File "/home/ptisnovs/.local/lib/python3.6/site-packages/pandas/io/parsers.py", line 460, in _read
    data = parser.read(nrows)
  File "/home/ptisnovs/.local/lib/python3.6/site-packages/pandas/io/parsers.py", line 1198, in read
    ret = self._engine.read(nrows)
  File "/home/ptisnovs/.local/lib/python3.6/site-packages/pandas/io/parsers.py", line 2157, in read
    data = self._reader.read(nrows)
  File "pandas/_libs/parsers.pyx", line 847, in pandas._libs.parsers.TextReader.read
  File "pandas/_libs/parsers.pyx", line 862, in pandas._libs.parsers.TextReader._read_low_memory
  File "pandas/_libs/parsers.pyx", line 918, in pandas._libs.parsers.TextReader._read_rows
  File "pandas/_libs/parsers.pyx", line 905, in pandas._libs.parsers.TextReader._tokenize_rows
  File "pandas/_libs/parsers.pyx", line 2042, in pandas._libs.parsers.raise_parser_error
pandas.errors.ParserError: Error tokenizing data. C error: Expected 1 fields in line 3, saw 2

14. Specifikace oddělovače

Nejprve se pokusme specifikovat oddělovač jednotlivých záznamů, kterým je znak „|“. Použijeme tedy pojmenovaný parametr sep předaný funkci pandas.read_csv:

df = pandas.read_csv("denni_kurz.txt", sep="|")

Úplný zdrojový kód příkladu:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading data file with custom format. separator specification."""
 
import pandas
 
df = pandas.read_csv("denni_kurz.txt", sep="|")
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

Výsledek ovšem prozatím nebude uspokojivý, a to z toho důvodu, že první řádek „rozhodí“ logiku pro detekci začátku sloupců a všechna data budou uložena do jediného sloupce:

Data frame
---------------------------
                                           20.11.2020 #224
země               měna       množství kód            kurz
Austrálie          dolar      1        AUD          16,231
Brazílie           real       1        BRL           4,160
Bulharsko          lev        1        BGN          13,467
Čína               žen-min-pi 1        CNY           3,381
Dánsko             koruna     1        DKK           3,536
EMU                euro       1        EUR          26,340
Filipíny           peso       100      PHP          46,038
Hongkong           dolar      1        HKD           2,864
Chorvatsko         kuna       1        HRK           3,481
Indie              rupie      100      INR          29,950
Indonesie          rupie      1000     IDR           1,567
Island             koruna     100      ISK          16,330
Izrael             nový šekel 1        ILS           6,649
Japonsko           jen        100      JPY          21,383
Jižní Afrika       rand       1        ZAR           1,445
Kanada             dolar      1        CAD          17,011
Korejská republika won        100      KRW           1,990
Maďarsko           forint     100      HUF           7,328
Malajsie           ringgit    1        MYR           5,425
Mexiko             peso       1        MXN           1,104
MMF                ZPČ        1        XDR          31,598
Norsko             koruna     1        NOK           2,471
Nový Zéland        dolar      1        NZD          15,416
Polsko             zlotý      1        PLN           5,900
Rumunsko           leu        1        RON           5,405
Rusko              rubl       100      RUB          29,180
Singapur           dolar      1        SGD          16,530
Švédsko            koruna     1        SEK           2,577
Švýcarsko          frank      1        CHF          24,363
Thajsko            baht       100      THB          73,313
Turecko            lira       1        TRY           2,911
USA                dolar      1        USD          22,201
Velká Británie     libra      1        GBP          29,464
 
Column types
---------------------------
20.11.2020 #224    object
dtype: object

15. Přeskok prvního řádku, který neobsahuje data tabulky ani hlavičku

Aby byl textový soubor správně načten, musíme zcela přeskočit první řádek, jenž není součástí tabulky. Nejjednodušší způsob spočívá v použití parametru nazvaného skiprows, pochopitelně i s dříve použitým parametrem sep. Nové načtení by tedy mělo vypadat následovně:

df = pandas.read_csv("denni_kurz.txt", sep="|", skiprows=1)

Příklad pro načtení se až na další parametr nebude lišit od předchozího demonstračního příkladu, ovšem výsledky budou mnohem použitelnější:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading data file with custom format. separator + skip rows specification."""
 
import pandas
 
df = pandas.read_csv("denni_kurz.txt", sep="|", skiprows=1)
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

Výsledkem po načtení je již plně použitelný datový rámec, jehož jedinou nevýhodou je, že poslední sloupec neobsahuje číselné hodnoty:

Data frame
---------------------------
                  země        měna  množství  kód    kurz
0            Austrálie       dolar         1  AUD  16,231
1             Brazílie        real         1  BRL   4,160
2            Bulharsko         lev         1  BGN  13,467
3                 Čína  žen-min-pi         1  CNY   3,381
4               Dánsko      koruna         1  DKK   3,536
5                  EMU        euro         1  EUR  26,340
6             Filipíny        peso       100  PHP  46,038
7             Hongkong       dolar         1  HKD   2,864
8           Chorvatsko        kuna         1  HRK   3,481
9                Indie       rupie       100  INR  29,950
10           Indonesie       rupie      1000  IDR   1,567
11              Island      koruna       100  ISK  16,330
12              Izrael  nový šekel         1  ILS   6,649
13            Japonsko         jen       100  JPY  21,383
14        Jižní Afrika        rand         1  ZAR   1,445
15              Kanada       dolar         1  CAD  17,011
16  Korejská republika         won       100  KRW   1,990
17            Maďarsko      forint       100  HUF   7,328
18            Malajsie     ringgit         1  MYR   5,425
19              Mexiko        peso         1  MXN   1,104
20                 MMF         ZPČ         1  XDR  31,598
21              Norsko      koruna         1  NOK   2,471
22         Nový Zéland       dolar         1  NZD  15,416
23              Polsko       zlotý         1  PLN   5,900
24            Rumunsko         leu         1  RON   5,405
25               Rusko        rubl       100  RUB  29,180
26            Singapur       dolar         1  SGD  16,530
27             Švédsko      koruna         1  SEK   2,577
28           Švýcarsko       frank         1  CHF  24,363
29             Thajsko        baht       100  THB  73,313
30             Turecko        lira         1  TRY   2,911
31                 USA       dolar         1  USD  22,201
32      Velká Británie       libra         1  GBP  29,464
 
Column types
---------------------------
země        object
měna        object
množství     int64
kód         object
kurz        object
dtype: object

16. Převod záznamů s desetinnou čárkou na číselné hodnoty

Poslední úpravou datového rámce, kterou musíme provést, je převod hodnot v posledním sloupci na numerické hodnoty. Tuto úpravu můžeme spustit po načtení datového rámce, a to tak, že de facto do rámce vložíme nový sloupec pojmenovaný stejně jako sloupec starý (tedy „kurz“). A hodnoty pro tento sloupec získáme nejprve řetězcovou záměnou desetinné čárky za desetinnou tečku a posléze převodem na numerické hodnoty, k čemuž použijeme konverzní funkci pandas.to_numeric:

df["kurz"] = pandas.to_numeric(df["kurz"].str.replace(',','.'), errors='coerce')

Upravený demonstrační příklad:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading data file with custom format. separator + skip rows specification."""
 
import pandas
 
df = pandas.read_csv("denni_kurz.txt", sep="|", skiprows=1)
 
df["kurz"] = pandas.to_numeric(df["kurz"].str.replace(',','.'), errors='coerce')
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

Výsledky nyní budou odpovídat požadavkům na datový rámec – čísla jsou skutečně reprezentována numerickými hodnotami atd.:

Data frame
---------------------------
                  země        měna  množství  kód    kurz
0            Austrálie       dolar         1  AUD  16.231
1             Brazílie        real         1  BRL   4.160
2            Bulharsko         lev         1  BGN  13.467
3                 Čína  žen-min-pi         1  CNY   3.381
4               Dánsko      koruna         1  DKK   3.536
5                  EMU        euro         1  EUR  26.340
6             Filipíny        peso       100  PHP  46.038
7             Hongkong       dolar         1  HKD   2.864
8           Chorvatsko        kuna         1  HRK   3.481
9                Indie       rupie       100  INR  29.950
10           Indonesie       rupie      1000  IDR   1.567
11              Island      koruna       100  ISK  16.330
12              Izrael  nový šekel         1  ILS   6.649
13            Japonsko         jen       100  JPY  21.383
14        Jižní Afrika        rand         1  ZAR   1.445
15              Kanada       dolar         1  CAD  17.011
16  Korejská republika         won       100  KRW   1.990
17            Maďarsko      forint       100  HUF   7.328
18            Malajsie     ringgit         1  MYR   5.425
19              Mexiko        peso         1  MXN   1.104
20                 MMF         ZPČ         1  XDR  31.598
21              Norsko      koruna         1  NOK   2.471
22         Nový Zéland       dolar         1  NZD  15.416
23              Polsko       zlotý         1  PLN   5.900
24            Rumunsko         leu         1  RON   5.405
25               Rusko        rubl       100  RUB  29.180
26            Singapur       dolar         1  SGD  16.530
27             Švédsko      koruna         1  SEK   2.577
28           Švýcarsko       frank         1  CHF  24.363
29             Thajsko        baht       100  THB  73.313
30             Turecko        lira         1  TRY   2.911
31                 USA       dolar         1  USD  22.201
32      Velká Británie       libra         1  GBP  29.464
 
Column types
---------------------------
země         object
měna         object
množství      int64
kód          object
kurz        float64
dtype: object

O tom, že se jedná skutečně o číselné hodnoty, se můžeme přesvědčit i provedením nějakého výpočtu:

df.describe()

S výsledkem:

          množství       kurz
count    33.000000  33.000000
mean     55.272727  14.879061
std     174.929141  15.649135
min       1.000000   1.104000
25%       1.000000   3.381000
50%       1.000000   7.328000
75%     100.000000  22.201000
max    1000.000000  73.313000

17. Načtení dat přímo z webu

Data, resp. celé tabulky je možné v případě potřeby načíst přímo z internetu, databáze atd. Ukažme si nejprve načtení z internetového zdroje. Opět se bude jednat o tabulku s denními převodními kurzy měn, která je dostupná na adrese https://www.cnb.cz/cs/finan­cni_trhy/devizovy_trh/kur­zy_devizoveho_trhu/denni_kur­z.txt. Načtení provedeme se stejnými parametry, jaké jsme si uvedli v předchozí kapitole, pouze s tím rozdílem, že se namísto jména lokálního souboru použije URL:

#!/usr/bin/env python3
# vim: set fileencoding=utf-8
 
"""Reading data file from internets."""
 
import pandas
 
url = "https://www.cnb.cz/cs/financni_trhy/devizovy_trh/kurzy_devizoveho_trhu/denni_kurz.txt"
df = pandas.read_csv(url, sep="|", skiprows=1)
 
df["kurz"] = pandas.to_numeric(df["kurz"].str.replace(',','.'), errors='coerce')
 
print("Data frame")
print("---------------------------")
print(df)
print()
 
print("Column types")
print("---------------------------")
print(df.dtypes)

S očekávaným výsledkem:

Data frame
---------------------------
                  země        měna  množství  kód    kurz
0            Austrálie       dolar         1  AUD  16.234
1             Brazílie        real         1  BRL   4.107
2            Bulharsko         lev         1  BGN  13.427
3                 Čína  žen-min-pi         1  CNY   3.360
4               Dánsko      koruna         1  DKK   3.528
5                  EMU        euro         1  EUR  26.260
6             Filipíny        peso       100  PHP  45.873
7             Hongkong       dolar         1  HKD   2.855
8           Chorvatsko        kuna         1  HRK   3.473
9                Indie       rupie       100  INR  29.861
10           Indonesie       rupie      1000  IDR   1.563
11              Island      koruna       100  ISK  16.321
12              Izrael  nový šekel         1  ILS   6.628
13            Japonsko         jen       100  JPY  21.164
14        Jižní Afrika        rand         1  ZAR   1.441
15              Kanada       dolar         1  CAD  16.934
16  Korejská republika         won       100  KRW   1.991
17            Maďarsko      forint       100  HUF   7.267
18            Malajsie     ringgit         1  MYR   5.413
19              Mexiko        peso         1  MXN   1.103
20                 MMF         ZPČ         1  XDR  31.591
21              Norsko      koruna         1  NOK   2.460
22         Nový Zéland       dolar         1  NZD  15.436
23              Polsko       zlotý         1  PLN   5.880
24            Rumunsko         leu         1  RON   5.389
25               Rusko        rubl       100  RUB  29.143
26            Singapur       dolar         1  SGD  16.471
27             Švédsko      koruna         1  SEK   2.573
28           Švýcarsko       frank         1  CHF  24.240
29             Thajsko        baht       100  THB  72.836
30             Turecko        lira         1  TRY   2.779
31                 USA       dolar         1  USD  22.128
32      Velká Británie       libra         1  GBP  29.498
 
Column types
---------------------------
země         object
měna         object
množství      int64
kód          object
kurz        float64
dtype: object
Poznámka: v navazujícím článku si ukážeme další operace s datovými rámci, a to jak operace poskytované přímo knihovnou Pandas, tak i například validaci dat s využitím externích knihoven (Voluptuous, Opulent Pandas atd).

18. Repositář s demonstračními příklady a datovými soubory

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:

DT2021 tip

# Demonstrační příklad Stručný popis příkladu Cesta
1 read_integer_values.py načtení obsahu jednoduché tabulky ze souboru typu CSV https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_integer_values.py
2 read_missing_integer_values.py zpracování prázdných hodnot v tabulce jako NaN https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_missing_integer_values­.py
3 read_missing_integer_values2.py zpracování prázdných hodnot v tabulce pomocí typu Int64 https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_missing_integer_values.py
4 read_timestamps_wo_parsing.py načtení tabulky obsahující časová razítka https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_timestamps_wo_parsing.py
5 read_timestamps_with_parsing.py korektní parsing časových razítek https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_timestamps_with_parsin­g.py
6 read_custom_timestamps1.py pokus o načtení souboru s vlastním formátem časových razítek https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_custom_timestamps1.py
7 read_custom_timestamps2.py parsing časových razítek s vlastním formátem https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_custom_timestamps2.py
8 read_custom_timestamps3.py parsing časových razítek s vlastním formátem https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_custom_timestamps3.py
9 read_tsv_default_behaviour.py čtení tabulky uložené ve formátu TSV bez uvedení oddělovače https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_tsv_default_behaviour.py
10 read_tsv_specify_separator.py čtení tabulky uložené ve formátu TSV se specifikací oddělovače https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_tsv_specify_separator.py
11 read_txt_no_widths.py import dat z textových souborů https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_txt_no_widths.py
12 read_txt_specify_widths.py explicitní specifikace šířky sloupců https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_txt_specify_widths.py
13 read_custom_data_format1.py zpracování souborů s nestandardním formátem https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_custom_data_format1.py
14 read_custom_data_format2.py specifikace oddělovače sloupců https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_custom_data_format2.py
15 read_custom_data_format3.py vynechání prvního řádku https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_custom_data_format3.py
16 read_custom_data_format4.py konverze dat používajících desetinnou čárku https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_custom_data_format4.py
17 read_data_from_internets_improper.py stažení a pokus o zpracování souboru s vlastním formátem https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_data_from_internets_im­proper.py
18 read_data_from_internets_proper.py zpracování souboru s vlastním formátem https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_data_from_internets_pro­per.py
19 read_data_from_internets_proper2.py vylepšení předchozího příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/re­ad_data_from_internets_pro­per2.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

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

19. Články s informacemi o různých způsobech validace datových struktur

V této kapitole jsou uvedeny odkazy na články, v nichž jsme se zabývali různými způsoby validace datových struktur. Pravděpodobně nejlepší přístup nalezneme v knihovně clojure.spec určené pro jazyk Clojure, ovšem i pro Python existuje několik velmi užitečných knihoven:

  1. Validace dat s využitím knihovny spec v Clojure 1.9.0
    https://www.root.cz/clanky/validace-dat-s-vyuzitim-knihovny-spec-v-clojure-1–9–0/
  2. Validace dat s využitím knihovny spec v Clojure 1.9.0 (dokončení)
    https://www.root.cz/clanky/validace-dat-s-vyuzitim-knihovny-spec-v-clojure-1–9–0-dokonceni/
  3. Validace datových struktur v Pythonu pomocí knihoven Schemagic a Schema
    https://www.root.cz/clanky/validace-datovych-struktur-v-pythonu-pomoci-knihoven-schemagic-a-schema/
  4. Validace datových struktur v Pythonu (2. část)
    https://www.root.cz/clanky/validace-datovych-struktur-v-pythonu-2-cast/
  5. Validace datových struktur v Pythonu (dokončení)
    https://www.root.cz/clanky/validace-datovych-struktur-v-pythonu-dokonceni/

20. Odkazy na Internetu

  1. Opulent-Pandas na PyPi
    https://pypi.org/project/opulent-pandas/
  2. pandas_validator na PyPi
    https://pypi.org/project/pan­das_validator/
  3. pandas-validator (dokumentace)
    https://pandas-validator.readthedocs.io/en/latest/
  4. 7 Best Python Libraries for Validating Data
    https://www.yeahhub.com/7-best-python-libraries-validating-data/
  5. Universally unique identifier (Wikipedia)
    https://en.wikipedia.org/wi­ki/Universally_unique_iden­tifier
  6. Nullable integer data type
    https://pandas.pydata.org/pandas-docs/stable/user_guide/integer_na.html
  7. pandas.read_csv
    https://pandas.pydata.org/pandas-docs/stable/reference/api/pan­das.read_csv.html
  8. How to define format when using pandas to_datetime?
    https://stackoverflow.com/qu­estions/36848514/how-to-define-format-when-using-pandas-to-datetime
  9. 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/
  10. Skip rows during csv import pandas
    https://stackoverflow.com/qu­estions/20637439/skip-rows-during-csv-import-pandas
  11. Denni kurz
    https://www.cnb.cz/cs/finan­cni_trhy/devizovy_trh/kur­zy_devizoveho_trhu/denni_kur­z.txt
  12. UUID objects according to RFC 4122 (knihovna pro Python)
    https://docs.python.org/3­.5/library/uuid.html#uuid­.uuid4
  13. Object identifier (Wikipedia)
    https://en.wikipedia.org/wi­ki/Object_identifier
  14. Digital object identifier (Wikipedia)
    https://en.wikipedia.org/wi­ki/Digital_object_identifi­er
  15. voluptuous na (na PyPi)
    https://pypi.python.org/py­pi/voluptuous
  16. Repositář knihovny voluptuous na GitHubu
    https://github.com/alectho­mas/voluptuous
  17. pytest-voluptuous 1.0.2 (na PyPi)
    https://pypi.org/project/pytest-voluptuous/
  18. pytest-voluptuous (na GitHubu)
    https://github.com/F-Secure/pytest-voluptuous
  19. schemagic 0.9.1 (na PyPi)
    https://pypi.python.org/py­pi/schemagic/0.9.1
  20. Schemagic / Schemagic.web (na GitHubu)
    https://github.com/Mechrop­hile/schemagic
  21. schema 0.6.7 (na PyPi)
    https://pypi.python.org/pypi/schema
  22. schema (na GitHubu)
    https://github.com/keleshev/schema
  23. XML Schema validator and data conversion library for Python
    https://github.com/brunato/xmlschema
  24. xmlschema 0.9.7
    https://pypi.python.org/py­pi/xmlschema/0.9.7
  25. jsonschema 2.6.0
    https://pypi.python.org/py­pi/jsonschema
  26. warlock 1.3.0
    https://pypi.python.org/pypi/warlock
  27. Python Virtual Environments – A Primer
    https://realpython.com/python-virtual-environments-a-primer/
  28. pip 1.1 documentation: Requirements files
    https://pip.readthedocs.i­o/en/1.1/requirements.html
  29. unittest.mock — mock object library
    https://docs.python.org/3­.5/library/unittest.mock.html
  30. mock 2.0.0
    https://pypi.python.org/pypi/mock
  31. An Introduction to Mocking in Python
    https://www.toptal.com/python/an-introduction-to-mocking-in-python
  32. Unit testing (Wikipedia)
    https://en.wikipedia.org/wi­ki/Unit_testing
  33. Unit testing
    https://cs.wikipedia.org/wi­ki/Unit_testing
  34. Test-driven development (Wikipedia)
    https://en.wikipedia.org/wiki/Test-driven_development
  35. Pip (dokumentace)
    https://pip.pypa.io/en/stable/
  36. 5 Differences between clojure.spec and Schema
    https://lispcast.com/clojure.spec-vs-schema/
  37. Schema: Clojure(Script) library for declarative data description and validation
    https://github.com/plumatic/schema
  38. clojure.spec – Rationale and Overview
    https://clojure.org/about/spec