Hlavní navigace

Operace s daty uloženými v binárních souborech v knihovnách NumPy a Pandas (dokončení)

4. 11. 2021
Doba čtení: 31 minut

Sdílet

 Autor: Pavel Tišnovský
Už jsme si ukázali základy práce s daty uloženými v binárních souborech v knihovnách NumPy a Pandas. Jednou z největších předností binárních souborů jsou rychlé přesuny (seek) a namapování obsahu souboru do paměti (mmap).

Obsah

1. Operace s daty uloženými v binárních souborech v knihovnách NumPy a Pandas (dokončení)

2. Krátké zopakování z minula – uložení matice do binárního souboru, opětovné načtení této matice

3. Načtení obsahu matice z binárního souboru se specifikací formátu a offsetu

4. Načtení obsahu matice z binárního souboru se specifikací formátu, offsetu a počtu prvků

5. Uložení obsahu rozsáhlejší matice do standardního binárního souboru

6. Přečtení obsahu matice ze standardního binárního souboru

7. Využití systémového volání mmap při práci s rozsáhlejšími maticemi

8. Porovnání operací použitých pro přečtení matice ze standardního binárního souboru

9. Standardní souborový formát pro uložení většího množství matic

10. Uložení většího množství matic do jediného souboru

11. Načtení většího množství matic z jediného souboru

12. Pojmenování matic v souboru NPZ

13. Komprimace obsahu matic v souboru NPZ

14. Porovnání souboru NPZ s komprimovanou a nekomprimovanou maticí

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

16. Odkazy na předchozí části seriálu o knihovně Pandas

17. Odkazy na Internetu

1. Operace s daty uloženými v binárních souborech v knihovnách NumPy a Pandas (dokončení)

Na předchozí článek, ve kterém jsme si ukázali základy práce s daty (vektory, maticemi, řadami i datovými rámci) uloženými v binárních souborech v knihovnách NumPy a Pandas, dnes navážeme. Ukážeme si totiž některé další možnosti, které nám binární soubory (ať již „raw“, tedy pouze soubory s čistými daty, nebo standardní soubory NPY) nabízí. Jednou z největších předností binárních souborů oproti souborům textovým jsou rychlé přesuny (tedy operace typu seek) a taktéž možnost namapování obsahu souboru do paměti (mmap). To však není vše, protože si představíme i formát NPZ, který umožňuje uložit větší množství vektorů a matic knihovny NumPy, a to dokonce i s volitelnou komprimací (interně se ovšem nejedná o žádnou raketovou vědu, protože NPZ je vlastně běžný ZIP archiv obsahující soubory NPY).

2. Krátké zopakování z minula – uložení matice do binárního souboru, opětovné načtení této matice

V úvodním článku o problematice binárních souborů obsahujících data pro knihovnu NumPy popř. i datové řady nebo datové rámce pro knihovnu Pandas jsme si mj. ukázali i metodu nazvanou tofile třídy ndarray popř. funkci Numpy.tofile. S využitím těchto dvou volání lze zajistit uložení „čistých“ dat polí do souboru s možností jejich zpětného načtení. Základem je metoda ndarray.tofile:

tofile(...)
    a.tofile(fid, sep="", format="%s")
 
    Write array to a file as text or binary (default).
 
    Data is always written in 'C' order, independent of the order of `a`.
    The data produced by this method can be recovered using the function
    fromfile().

Tuto metodu použijeme pro uložení obsahu poměrně rozsáhlé matice s pěti sloupci a 500 řádky, přičemž jednotlivé prvky budou typu „i“ neboli celé číslo, jehož způsob uložení, rozsah atd. je závislý na použité platformě (viz též tento popis):

"""Uložení obsahu matice do binárního souboru."""
 
import numpy as np
 
# rozměry matice
rows = 500
columns = 5
 
# matice obsahující celočíselné hodnoty typu integer
m = np.linspace(1, rows*columns, rows*columns, dtype="i").reshape(rows, columns)
 
# tisk obsahu zkonstruované matice
print(m)
 
# uložení matice do souboru v čistém binárním formátu
m.tofile("matrix3.bin")
Poznámka: zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_to_file3.py.

Na platformě x86–64 bude výsledkem soubor o velikosti přesně 10 000 bajtů. Proč je tento soubor přesně takto velký, zjistíme snadno – uložilo se celkem 5×500=2500 prvků matice, přičemž každý prvek je uložen ve čtyřech bajtech. Obsah souboru si můžeme zobrazit s využitím příkazu od (octal dump) zmíněného minule:

$ od -t d4 matrix3.bin
 
0000000           1           2           3           4
0000020           5           6           7           8
0000040           9          10          11          12
0000060          13          14          15          16
0000100          17          18          19          20
0000120          21          22          23          24
0000140          25          26          27          28
0000160          29          30          31          32
0000200          33          34          35          36
0000220          37          38          39          40
0000240          41          42          43          44
0000260          45          46          47          48
0000700         113         114         115         116
0000720         117         118         119         120
0000740         121         122         123         124
0000760         125         126         127         128
0001000         129         130         131         132
0001020         133         134         135         136
0001040         137         138         139         140
0001060         141         142         143         144
0001100         145         146         147         148
0001120         149         150
...
...
...
0023120        2453        2454        2455        2456
0023140        2457        2458        2459        2460
0023160        2461        2462        2463        2464
0023200        2465        2466        2467        2468
0023220        2469        2470        2471        2472
0023240        2473        2474        2475        2476
0023260        2477        2478        2479        2480
0023300        2481        2482        2483        2484
0023320        2485        2486        2487        2488
0023340        2489        2490        2491        2492
0023360        2493        2494        2495        2496
0023400        2497        2498        2499        2500
0023420
Poznámka: povšimněte si, že od dokáže nativně pracovat s celými čísly uloženými ve větším množství bajtů.

Zpětné načtení obsahu matice se skládá ze dvou operací – načtení dat ve formě jednorozměrného vektoru (se specifikací formátu prvků) a vytvoření matice z tohoto vektoru metodou reshape. I přes tento název se interně žádné přesuny prvků neprovádí, takže reshape pracuje velmi efektivně:

"""Načtení obsahu matice z binárního souboru se specifikací formátu."""
 
import numpy as np
 
# rozměry výsledné matice
rows = 500
columns = 5
 
# načtení prvků matice z binárního souboru a konstrukce matice
m = np.fromfile("matrix3.bin", dtype="i").reshape(rows, columns)
 
# výpis obsahu právě zkonstruované matice
print(m)

Výsledek po spuštění:

[[   1    2    3    4    5]
 [   6    7    8    9   10]
 [  11   12   13   14   15]
 ...
 [2486 2487 2488 2489 2490]
 [2491 2492 2493 2494 2495]
 [2496 2497 2498 2499 2500]]
Poznámka: zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_from_file5.py.

3. Načtení obsahu matice z binárního souboru se specifikací formátu a offsetu

Velmi často se v praxi můžeme setkat s požadavkem na zpracování dat (typicky rozměrných matic) uložených v binárních souborech o značné velikosti. V případě, že se má zpracovat pouze podmnožina těchto dat, a navíc dokážeme získat počáteční index „podmatice“, lze tuto operaci provést relativně snadno – budeme pouze muset specifikovat offset v rámci binárního souboru. Malý problém spočívá v tom, že offset není specifikován jako index prvku, ale index prvního bajtu, který se má načíst. Na základě velikosti matice (počtu sloupců), požadovaném prvním řádku, který se má načíst a známém typu prvků musíme provést tento výpočet:

# první řádek matice, který chceme načíst z binárního souboru
first_row = 250
 
# platformově nezávislé získání počtu bajtů pro každý prvek typu integer
item_size = np.dtype("i").itemsize
 
# výpočet offsetu při čtení řádků od first_row z binárního souboru
offset = first_row * columns * item_size

Offset se zadává formou nepovinného parametru funkce numpy.fromfile:

# načtení prvků matice z binárního souboru a konstrukce matice
m = np.fromfile("matrix3.bin", dtype="i", offset=offset).reshape(rows, columns)

Ukažme si celý postup na dalším demonstračním příkladu:

"""Načtení obsahu matice z binárního souboru se specifikací formátu a offsetu."""
 
import numpy as np
 
# rozměry výsledné matice
rows = 250
columns = 5
 
# první řádek matice načtený z binárního souboru
first_row = 250
 
# platformově nezávislé získání počtu bajtů pro každý prvek typu integer
item_size = np.dtype("i").itemsize
 
# výpočet offsetu při čtení řádků od first_row z binárního souboru
offset = first_row * columns * item_size
 
print("offset=", offset, "bytes")
print()
 
# načtení prvků matice z binárního souboru a konstrukce matice
m = np.fromfile("matrix3.bin", dtype="i", offset=offset).reshape(rows, columns)
 
# výpis obsahu právě zkonstruované matice
print(m)

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

offset= 5000 bytes
 
[[1251 1252 1253 1254 1255]
 [1256 1257 1258 1259 1260]
 [1261 1262 1263 1264 1265]
 ...
 [2486 2487 2488 2489 2490]
 [2491 2492 2493 2494 2495]
 [2496 2497 2498 2499 2500]]
Poznámka: zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_from_file6.py.

4. Načtení obsahu matice z binárního souboru se specifikací formátu, offsetu a počtu prvků

V předchozí kapitole jsme specifikovali, že načítání prvků má začít od offsetu 5000. Od tohoto offsetu byl načten zbytek souboru, tedy 10000–5000=5000 bajtů, což odpovídá 1250 prvkům. Pro omezení velikosti načítaných dat však můžeme určit jak offset, tak i počet prvků, přičemž počet prvků je specifikován nepovinným parametrem count:

# načtení prvků matice z binárního souboru a konstrukce matice
m = np.fromfile("matrix3.bin", dtype="i", offset=offset, count=count).reshape(last_row-first_row, columns)

Výpočet počtu prvků lze provést na základě prvního a posledního řádku, který se má načíst (a pochopitelně i počtu sloupců v matici):

# první řádek matice načtený z binárního souboru
first_row = 200
 
# poslední řádek matice načtený z binárního souboru
last_row = 350
 
# počet sloupců matice
columns = 5
 
# počet prvků, které se mají načíst
count = (last_row - first_row) * columns

Vše si opět ukážeme na jednoduchém demonstračním příkladu:

"""Načtení obsahu matice z binárního souboru se specifikací formátu, offsetu a počtu prvků."""
 
import numpy as np
 
# první řádek matice načtený z binárního souboru
first_row = 200
 
# poslední řádek matice načtený z binárního souboru
last_row = 350
 
# počet sloupců matice
columns = 5
 
# platformově nezávislé získání počtu bajtů pro každý prvek typu integer
item_size = np.dtype("i").itemsize
 
# výpočet offsetu při čtení řádků od first_row z binárního souboru
offset = first_row * columns * item_size
count = (last_row - first_row) * columns
 
print("offset=", offset, "bytes")
print("count=", count, "items")
print()
 
# načtení prvků matice z binárního souboru a konstrukce matice
m = np.fromfile("matrix3.bin", dtype="i", offset=offset, count=count).reshape(last_row-first_row, columns)
 
# výpis obsahu právě zkonstruované matice
print(m)

Výsledkem bude mnohem menší matice:

offset= 4000 bytes
count= 750 items
 
[[1001 1002 1003 1004 1005]
 [1006 1007 1008 1009 1010]
 [1011 1012 1013 1014 1015]
 [1016 1017 1018 1019 1020]
 [1021 1022 1023 1024 1025]
 [1026 1027 1028 1029 1030]
 [1031 1032 1033 1034 1035]
 [1036 1037 1038 1039 1040]
 [1041 1042 1043 1044 1045]
 [1046 1047 1048 1049 1050]
 [1051 1052 1053 1054 1055]
 ...
 ...
 ...
 [1696 1697 1698 1699 1700]
 [1701 1702 1703 1704 1705]
 [1706 1707 1708 1709 1710]
 [1711 1712 1713 1714 1715]
 [1716 1717 1718 1719 1720]
 [1721 1722 1723 1724 1725]
 [1726 1727 1728 1729 1730]
 [1731 1732 1733 1734 1735]
 [1736 1737 1738 1739 1740]
 [1741 1742 1743 1744 1745]
 [1746 1747 1748 1749 1750]]
Poznámka: zdrojový kód tohoto demonstračního příkladu naleznete na adrese https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_from_file7.py.

5. Uložení obsahu rozsáhlejší matice do standardního binárního souboru

Minule jsme se zmínili i o možnosti uložení obsahu vektorů a matic do standardního binárního souboru. Předchozí pokusy o serializaci dat měly totiž jednu zásadní nevýhodu – bude se jednat skutečně pouze o čisté hodnoty prvků. Žádné další informace se neuloží – tedy ani typ prvků ani tvar pole. To není ani zdaleka ideální situace a proto byl vyvinut dnes již standardní binární formát určený pro ukládání n-rozměrných polí. Tento formát se nazývá NPY a jeho popis lze nalézt na stránce https://numpy.org/devdocs/re­ference/generated/numpy.lib­.format.html. Jedná se o přímou serializaci pole do souboru (což již velmi dobře známe), ovšem před vlastní hodnoty prvků je uložena jednoduchá hlavička se všemi důležitými informacemi – včetně endianity, kterou jsme prozatím vůbec neřešili.

Pro uložení se používá funkce numpy.save:

save(file, arr, allow_pickle=True, fix_imports=True)
    Save an array to a binary file in NumPy ``.npy`` format.
 
    Parameters
    ----------
    file : file, str, or pathlib.Path
        File or filename to which the data is saved.  If file is a file-object,
        then the filename is unchanged.  If file is a string or Path, a ``.npy``
        extension will be appended to the filename if it does not already
        have one.
   ...
   ...
   ...
Poznámka: jedná se skutečně o funkci a nikoli o metodu pole, což je oproti předchozím příkladům odlišné!

Následující skript po svém spuštění uloží rozsáhlou matici s 1000 řádky pěti sloupci do standardního souboru NPY:

"""Uložení obsahu matice do standardního binárního souboru."""
 
import numpy as np
 
# rozměry matice
rows = 1000
columns = 5
 
# matice obsahující celočíselné hodnoty typu integer
m = np.linspace(1, rows*columns, rows*columns, dtype="i").reshape(rows, columns)
 
# tisk obsahu zkonstruované matice
print(m)
 
# uložení matice do souboru ve standardním formátu
np.save("matrix3.npy", m, allow_pickle=False)

Obsah vytvořeného binárního souboru „matrix3.npy“ si opět můžeme zobrazit nástrojem od. Prvních 128 bajtů je určeno pro uložení hlavičky, která obsahuje i metadata v textové podobě. Ve skutečnosti je hlavičkou obsazeno jen 74 bajtů, ovšem v případě rozsáhlejších matic s větším počtem dimenzí je možné, že bude obsazena celá hlavička, protože se zvětší ta část hlavičky, která obsahuje textovou podobu atributu shape:

0000000  1297436307       88400   662372470  1668506980  >.NUMPY..v.{'desc<
0000020   540682098   879311911   656419879  1953656678  >r': '<i4', 'fort<
0000040  1601069426  1701081711   540682098  1936482630  >ran_order': Fals<
0000060   656419941  1885431923   540682085   741356328  >e, 'shape': (30,<
0000100   740898080   539000096   538976288   538976288  > 5), }          <
0000120   538976288   538976288   538976288   538976288  >                <
*
0000160   538976288   538976288   538976288   169877536  >               .<

Od offsetu 0200 (dekadicky tedy od offsetu 128) začínají hodnoty jednotlivých prvků. Každý prvek je uložen ve čtyřech bajtech a vzhledem k tomu, že soubor vznikl na platformě x86–64, používá se pořadí bajtů little endian, což znamená, že nejdříve jsou uloženy bajty s nižší vahou. Nástroj od dokáže s tímto formátem nativně pracovat, takže lze zbytek souboru zobrazit snadno tak, aby byl dobře čitelný:

0000200           1           2           3           4  >................<
0000220           5           6           7           8  >................<
0000240           9          10          11          12  >................<
0000260          13          14          15          16  >................<
0000300          17          18          19          20  >................<
0000320          21          22          23          24  >................<
0000340          25          26          27          28  >................<
0000360          29          30          31          32  >............ ...<
0000400          33          34          35          36  >!..."...#...$...<
0000420          37          38          39          40  >%...&...'...(...<
0000440          41          42          43          44  >)...*...+...,...<
0000460          45          46          47          48  >-......./...0...<
0000500          49          50          51          52  >1...2...3...4...<
0000520          53          54          55          56  >5...6...7...8...<
0000540          57          58          59          60  >9...:...;...<...<
0000560          61          62          63          64  >=...>...?...@...<
0000600          65          66          67          68  >A...B...C...D...<
0000620          69          70          71          72  >E...F...G...H...<
0000640          73          74          75          76  >I...J...K...L...<
0000660          77          78          79          80  >M...N...O...P...<
0000700          81          82          83          84  >Q...R...S...T...<
0000720          85          86          87          88  >U...V...W...X...<
0000740          89          90          91          92  >Y...Z...[...\...<
0000760          93          94          95          96  >]...^..._...`...<
0001000          97          98          99         100  >a...b...c...d...<
0001020         101         102         103         104  >e...f...g...h...<
0001040         105         106         107         108  >i...j...k...l...<
0001060         109         110         111         112  >m...n...o...p...<
0001100         113         114         115         116  >q...r...s...t...<
0001120         117         118         119         120  >u...v...w...x...<
0001140         121         122         123         124  >y...z...{...|...<
0001160         125         126         127         128  >}...~...........<
0001200         129         130         131         132  >................<
0001220         133         134         135         136  >................<
0001240         137         138         139         140  >................<
0001260         141         142         143         144  >................<
0001300         145         146         147         148  >................<
0001320         149         150                          >........<
0001330

6. Přečtení obsahu matice ze standardního binárního souboru

V případě, že budeme chtít načíst obsah celé matice ze standardního binárního souboru, je situace poměrně jednoduchá, protože pro tento účel můžeme použít standardní funkci nazvanou numpy.load, které předáme pouze jméno souboru, ve kterém je matice uložena (jedná se tedy o opak funkce numpy.save):

load(file, mmap_mode=None, allow_pickle=False, fix_imports=True, encoding='ASCII')
    Load arrays or pickled objects from ``.npy``, ``.npz`` or pickled files.
 
    .. warning:: Loading files that contain object arrays uses the ``pickle``
                 module, which is not secure against erroneous or maliciously
                 constructed data. Consider passing ``allow_pickle=False`` to
                 load data that is known not to contain object arrays for the
                 safer handling of untrusted sources.
 

V případě, že budeme chtít načíst celou matici (nejenom její část), předá se funkci numpy.load pouze jméno souboru s uloženou maticí:

"""Přečtení obsahu matice ze standardního binárního souboru."""
 
import numpy as np
 
# načtení matice ze standardního binárního souboru
m = np.load("matrix3.npy")
 
# zobrazení obsahu matice
print(m)
print()
 
# zobrazení dalších informací o matici
print("Dimensions:", m.ndim)
print("Data type:", m.dtype)
print("Item size:", m.itemsize, "bytes")
print("Array size:", m.size, "items")

S touto funkcí jsme se seznámili již minule, takže pro nás nebude příliš překvapující fakt, že počet dimenzí, tvar, datový typ prvků i celková velikost matice byly plně obnoveny:

[[   1    2    3    4    5]
 [   6    7    8    9   10]
 [  11   12   13   14   15]
 ...
 [4986 4987 4988 4989 4990]
 [4991 4992 4993 4994 4995]
 [4996 4997 4998 4999 5000]]
 
Dimensions: 2
Data type: int32
Item size: 4 bytes
Array size: 5000 items

7. Využití systémového volání mmap při práci s rozsáhlejšími maticemi

Při práci se standardními soubory s maticemi lze namísto dvojice open+read využít i systémové volání mmap, které umožňuje k souboru přistupovat jako k regionu ve virtuální paměti (ne ovšem nutně v paměti fyzické). Tento režim se povoluje volbou mmap_mode, přičemž pro režim čtení (bez modifikace) je nutné této nepovinné volbě (parametru) předat řetězec „r“. Přístup k souboru pak bude interně proveden zcela odlišným způsobem:

"""Přečtení obsahu matice ze standardního binárního souboru."""
 
import numpy as np
 
# použití režimu mmap
m = np.load("matrix3.npy", mmap_mode="r")
 
# zobrazení dalších informací o matici
print("Dimensions:", m.ndim)
print("Data type:", m.dtype)
print("Item size:", m.itemsize, "bytes")
print("Array size:", m.size, "items")

Výsledek:

Dimensions: 2
Data type: int32
Item size: 4 bytes
Array size: 5000 items

Pokud budeme přistupovat pouze k části matice, měl by se počet I/O operací snížit:

"""Přečtení obsahu matice ze standardního binárního souboru."""
 
import numpy as np
 
# použití režimu mmap
m = np.load("matrix3.npy", mmap_mode="r")
 
# zobrazení dalších informací o matici
print("Dimensions:", m.ndim)
print("Data type:", m.dtype)
print("Item size:", m.itemsize, "bytes")
print("Array size:", m.size, "items")
 
print(m[500:510])

S výsledkem:

Dimensions: 2
Data type: int32
Item size: 4 bytes
Array size: 5000 items
[[2501 2502 2503 2504 2505]
 [2506 2507 2508 2509 2510]
 [2511 2512 2513 2514 2515]
 [2516 2517 2518 2519 2520]
 [2521 2522 2523 2524 2525]
 [2526 2527 2528 2529 2530]
 [2531 2532 2533 2534 2535]
 [2536 2537 2538 2539 2540]
 [2541 2542 2543 2544 2545]
 [2546 2547 2548 2549 2550]]

8. Porovnání operací použitých pro přečtení matice ze standardního binárního souboru

Podívejme se nyní na to, jak se interně změní systémová volání ve chvíli, kdy načteme soubor s maticí běžným způsobem v porovnání s otevřením v režimu mmap. Nejdříve spustíme skript, který matici otevře a přečte funkcí numpy.load ve standardním režimu. Budeme přitom sledovat pouze operace prováděné nad vstupním souborem s maticí:

$ strace -P matrix3.npy python3 matrix_load_3.py
 
strace: Requested path 'matrix3.npy' resolved into '/home/ptisnovs/src/python/most-popular-python-libs/numpy/matrix3.npy'
openat(AT_FDCWD, "matrix3.npy", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0664, st_size=20128, ...}) = 0
ioctl(3, TCGETS, 0x7ffe69bc6210)        = -1 ENOTTY (Inappropriate ioctl for device)
lseek(3, 0, SEEK_CUR)                   = 0
read(3, "\223NUMPY\1\0v\0{'descr': '<i4', 'fort"..., 4096) = 4096
lseek(3, 0, SEEK_CUR)                   = 4096
fcntl(3, F_DUPFD_CLOEXEC, 0)            = 4
fcntl(4, F_GETFL)                       = 0x8000 (flags O_RDONLY|O_LARGEFILE)
lseek(4, 0, SEEK_CUR)                   = 4096
lseek(3, 0, SEEK_CUR)                   = 4096
fstat(4, {st_mode=S_IFREG|0664, st_size=20128, ...}) = 0
lseek(4, 0, SEEK_SET)                   = 0
read(4, "\223NUMPY\1\0v\0{'descr': '<i4', 'fort"..., 128) = 128
lseek(4, 0, SEEK_SET)                   = 0
read(4, "\223NUMPY\1\0v\0{'descr': '<i4', 'fort"..., 4096) = 4096
read(4, "\341\3\0\0\342\3\0\0\343\3\0\0\344\3\0\0\345\3\0\0\346\3\0\0\347\3\0\0\350\3\0\0"..., 12288) = 12288
read(4, "\341\17\0\0\342\17\0\0\343\17\0\0\344\17\0\0\345\17\0\0\346\17\0\0\347\17\0\0\350\17\0\0"..., 4096) = 3744
close(4)                                = 0
lseek(3, 4096, SEEK_SET)                = 4096
lseek(3, 20128, SEEK_SET)               = 20128
close(3)                                = 0
+++ exited with 0 +++

Z výsledků je patrné, že se soubor otevře dvakrát, ovšem vlastní čtení probíhá pouze se druhým otevřeným souborem. Celá matice je načtena sekvencí systémových volání read (první z těchto volání přečte hlavičku o délce 128 bajtů).

Dále se podíváme na výsledek v případě, že je soubor s maticí otevřen v režimu mmap:

$ strace -P matrix3.npy python3 matrix_load_5.py
 
strace: Requested path 'matrix3.npy' resolved into '/home/ptisnovs/src/python/most-popular-python-libs/numpy/matrix3.npy'
openat(AT_FDCWD, "matrix3.npy", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0664, st_size=20128, ...}) = 0
ioctl(3, TCGETS, 0x7fffd302e2d0)        = -1 ENOTTY (Inappropriate ioctl for device)
lseek(3, 0, SEEK_CUR)                   = 0
read(3, "\223NUMPY\1\0v\0{'descr': '<i4', 'fort"..., 4096) = 4096
lseek(3, 0, SEEK_CUR)                   = 4096
openat(AT_FDCWD, "matrix3.npy", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0664, st_size=20128, ...}) = 0
ioctl(4, TCGETS, 0x7fffd302dff0)        = -1 ENOTTY (Inappropriate ioctl for device)
lseek(4, 0, SEEK_CUR)                   = 0
read(4, "\223NUMPY\1\0v\0{'descr': '<i4', 'fort"..., 4096) = 4096
lseek(4, 0, SEEK_CUR)                   = 4096
close(4)                                = 0
openat(AT_FDCWD, "matrix3.npy", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0664, st_size=20128, ...}) = 0
ioctl(4, TCGETS, 0x7fffd302dae0)        = -1 ENOTTY (Inappropriate ioctl for device)
lseek(4, 0, SEEK_CUR)                   = 0
lseek(4, 0, SEEK_CUR)                   = 0
lseek(4, 0, SEEK_END)                   = 20128
lseek(4, 0, SEEK_CUR)                   = 20128
fstat(4, {st_mode=S_IFREG|0664, st_size=20128, ...}) = 0
fcntl(4, F_DUPFD_CLOEXEC, 0)            = 5
mmap(NULL, 20128, PROT_READ, MAP_SHARED, 4, 0) = 0x7f941fa52000
close(4)                                = 0
close(3)                                = 0
close(5)                                = 0
+++ exited with 0 +++

V tomto případě je opět přečtena hlavička, ovšem poté se zavolá systémové volání mmap a další operace typu read zde již nenalezneme.

9. Standardní souborový formát pro uložení většího množství matic

Nyní již víme, jak vypadá standardní souborový formát NPY, který je určený pro uložení obsahu jediné matice, a to včetně všech důležitých metainformací o této matici (tvar, typ prvků, endianita). Ovšem mnohdy jsme postaveni před úkol přenášet větší množství matic. To lze pochopitelně zajistit použitím většího množství souborů NPY, ovšem nemusí se vždy jednat o to nejvýhodnější řešení. Z tohoto důvodu začal být knihovnou NumPy oficiálně podporován ještě jeden souborový formát nazvaný NPZ, v němž je možné ukládat větší množství matic. Interně se jedná o formát založený na klasickém ZIPu, tedy na formátu, v němž je možné uložit větší množství souborů NPY. V navazujících kapitolách si ukážeme, jakým způsobem je možné tyto soubory vytvářet a pochopitelně i to, jak se načítají jednotlivé matice do tohoto souboru uložené.

10. Uložení většího množství matic do jediného souboru

Pro uložení většího množství matic do jediného souboru typu NPZ se používá funkce pojmenovaná numpy.savez:

savez(file, *args, **kwds)
    Save several arrays into a single file in uncompressed ``.npz`` format.
 
    If arguments are passed in with no keywords, the corresponding variable
    names, in the ``.npz`` file, are 'arr_0', 'arr_1', etc. If keyword
    arguments are given, the corresponding variable names, in the ``.npz``
    file will match the keyword names.

Podívejme se nyní na základní způsob použití této funkce při uložení tří matic do jediného souboru:

"""Uložení více matic do standardního binárního souboru."""
 
import numpy as np
 
# rozměry první matice
rows1 = 10
columns1 = 10
 
# rozměry druhé matice
rows2 = 100
columns2 = 1
 
# rozměry třetí matice
rows3 = 1
columns3 = 100
 
# tři matice obsahující celočíselné hodnoty různých typů
m1 = np.linspace(1, rows1*columns1, rows1*columns1, dtype="b").reshape(rows1, columns1)
m2 = np.linspace(1, rows2*columns2, rows2*columns2, dtype="i").reshape(rows2, columns2)
m3 = np.linspace(1, rows3*columns3, rows3*columns3, dtype="f").reshape(rows3, columns3)
 
# uložení matic do souboru ve standardním formátu
np.savez("matrix.npz", m1, m2, m3)

Výsledkem je soubor typu NPZ pojmenovaný „matrix.npz“. Vzhledem k tomu, že víme, že se jedná o standardní formát ZIP, můžeme si obsah tohoto souboru vypsat nástrojem unzip:

$ unzip -l matrix.npz
Archive:  matrix.npz
  Length      Date    Time    Name
---------  ---------- -----   ----
      228  01-01-1980 00:00   arr_0.npy
      528  01-01-1980 00:00   arr_1.npy
      528  01-01-1980 00:00   arr_2.npy
---------                     -------
     1284                     3 files
Poznámka: časová razítka jsou evidentně nastavena špatně, což by však nemělo ničemu vadit.

Pochopitelně si můžeme tento soubor rozbalit, a to opět standardním nástrojem unzip:

$ unzip matrix.npz

Prozkoumat můžeme například první rozbalený soubor arr0.npy:

$ od -t d1z arr_0.npy

Prvních 128 bajtů představuje nám již známou hlavičku:

0000000 -109   78   85   77   80   89    1    0  118    0  123   39  100  101  115   99  >.NUMPY..v.{'desc<
0000020  114   39   58   32   39  124  105   49   39   44   32   39  102  111  114  116  >r': '|i1', 'fort<
0000040  114   97  110   95  111  114  100  101  114   39   58   32   70   97  108  115  >ran_order': Fals<
0000060  101   44   32   39  115  104   97  112  101   39   58   32   40   49   48   44  >e, 'shape': (10,<
0000100   32   49   48   41   44   32  125   32   32   32   32   32   32   32   32   32  > 10), }         <
0000120   32   32   32   32   32   32   32   32   32   32   32   32   32   32   32   32  >                <
0000160   32   32   32   32   32   32   32   32   32   32   32   32   32   32   32   10  >               .<

Za hlavičkou jsou již uloženy hodnoty jednotlivých prvků matice:

0000200    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16  >................<
0000220   17   18   19   20   21   22   23   24   25   26   27   28   29   30   31   32  >............... <
0000240   33   34   35   36   37   38   39   40   41   42   43   44   45   46   47   48  >!"#$%&'()*+,-./0<
0000260   49   50   51   52   53   54   55   56   57   58   59   60   61   62   63   64  >123456789:;<=>?@<
0000300   65   66   67   68   69   70   71   72   73   74   75   76   77   78   79   80  >ABCDEFGHIJKLMNOP<
0000320   81   82   83   84   85   86   87   88   89   90   91   92   93   94   95   96  >QRSTUVWXYZ[\]^_`<
0000340   97   98   99  100                                                              >abcd<
0000344

11. Načtení většího množství matic z jediného souboru

Matice uložené do souboru typu NPZ je nutné načítat na základě jména souboru v archivu. Tato jména jsou dostupná přes atribut files. Všechny (tři) matice tedy dokážeme načíst a vypsat jejich obsah následujícím skriptem:

"""Načtení většího množství matic ze standardního binárního souboru."""
 
import numpy as np
 
# načtení souboru s větším množstvím matic
npzfile = np.load("matrix.npz")
 
# tisk názvů souborů
print(npzfile.files)
 
# přístup k jednotlivým maticím
for f in npzfile.files:
    m = npzfile[f]
    print(m)

12. Pojmenování matic v souboru NPZ

Matice a tím pádem i korespondující soubory v archivu je vhodné pojmenovat. Pro tento účel je podporován tento způsob volání funkce numpy.savez postavený na tzv. keyword argumentech:

np.savez("matrix.npz", first=matice1, second=matice2, third=matice3, ...)

V případě, že tyto názvy, tedy konkrétně „first“, „second“ a „third“ použijeme v upraveném skriptu, vznikne archiv s odlišně pojmenovanými soubory uvnitř:

"""Uložení více matic do standardního binárního souboru."""
 
import numpy as np
 
# rozměry první matice
rows1 = 10
columns1 = 10
 
# rozměry druhé matice
rows2 = 100
columns2 = 1
 
# rozměry třetí matice
rows3 = 1
columns3 = 100
 
# tři matice obsahující celočíselné hodnoty různých typů
m1 = np.linspace(1, rows1*columns1, rows1*columns1, dtype="b").reshape(rows1, columns1)
m2 = np.linspace(1, rows2*columns2, rows2*columns2, dtype="i").reshape(rows2, columns2)
m3 = np.linspace(1, rows3*columns3, rows3*columns3, dtype="f").reshape(rows3, columns3)
 
# uložení matic do souboru ve standardním formátu
np.savez("matrix.npz", first=m1, second=m2, third=m3)

Pochopitelně si opět můžeme zobrazit obsah vytvořeného archivu:

$ unzip -l matrix.npz 
 
Archive:  matrix.npz
  Length      Date    Time    Name
---------  ---------- -----   ----
      228  01-01-1980 00:00   first.npy
      528  01-01-1980 00:00   second.npy
      528  01-01-1980 00:00   third.npy
---------                     -------
     1284                     3 files

13. Komprimace obsahu matic v souboru NPZ

Díky tomu, že standardní ZIP archivy mohou být komprimovány, je možné se pokusit rozsáhlé matice zkomprimovat. V tomto případě se však namísto nám již známé funkce numpy.savez musí použít funkce pojmenovaná numpy.savez_compressed:

savez_compressed(file, *args, **kwds)
    Save several arrays into a single file in compressed ``.npz`` format.
 
    If keyword arguments are given, then filenames are taken from the keywords.
    If arguments are passed in with no keywords, then stored filenames are
    arr_0, arr_1, etc.
    ...
    ...
    ...

Parametry i způsob použití této funkce se nijak neliší od numpy.savez, takže si můžeme otestovat způsob jejího použití. Vytvoříme nejdříve relativně velkou matici 1000×1000 prvků typu „celé čtyřbajtové číslo“, přičemž všechny prvky budou nulové. Následně tuto matici uložíme do dvou souborů NZP – jednou v nezkomprimované a podruhé ve zkomprimované podobě:

"""Uložení více matic do standardního binárního souboru."""
 
import numpy as np
 
# rozměry matice
rows = 1000
columns = 1000
 
# vytvoření větší matice o zadaném tvaru
m0 = np.zeros((rows, columns), dtype="i")
 
# uložení matice do souboru ve standardním formátu
np.savez("matrix_uncompressed.npz", m0)
 
# uložení matice do souboru ve standardním zkomprimovaném formátu
np.savez_compressed("matrix_compressed.npz", m0)

14. Porovnání souboru NPZ s komprimovanou a nekomprimovanou maticí

Oba vytvořené soubory sice obsahují stejná data, ovšem jednou v nezkomprimovaném a podruhé ve zkomprimovaném tvaru, takže se velikosti obou archivů budou odlišovat:

$ ls -l matrix_*.npz
 
-rw-rw-r--. 1 ptisnovs ptisnovs    4114 Nov  3 17:08 matrix_compressed.npz
-rw-rw-r--. 1 ptisnovs ptisnovs 4000264 Nov  3 17:08 matrix_uncompressed.npz
Poznámka: velikost je rapidně odlišná, protože jsme schválně uložili matici se samými nulami, což jsou pochopitelně velmi snadno zkomprimovatelná data.

Přesvědčit se můžeme i o tom, že délka rozbalených souborů by byla naprosto totožná (první sloupec):

$ unzip -lv matrix_uncompressed.npz
Archive:  matrix_uncompressed.npz
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
 4000128  Stored  4000128   0% 01-01-1980 00:00 569b177d  arr_0.npy
--------          -------  ---                            -------
 4000128          4000128   0%                            1 file
 
$ unzip -lv matrix_compressed.npz
Archive:  matrix_compressed.npz
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
 4000128  Defl:N     3978 100% 01-01-1980 00:00 569b177d  arr_0.npy
--------          -------  ---                            -------
 4000128             3978 100%                            1 file

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

Zdrojové kódy všech minule i dnes popsaných demonstračních příkladů určených pro programovací jazyk Python 3 a nejnovější stabilní verzi knihoven Numpy a 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ích tabulkách.

Demonstrační příklady určené pouze pro knihovnu Numpy:

Linux tip

# Demonstrační příklad Stručný popis příkladu Cesta
1 vector_to_file1.py uložení obsahu vektoru do textového souboru se specifikací oddělovače https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/vec­tor_to_file1.py
2 vector_to_file2.py uložení obsahu vektoru do textového souboru se specifikací oddělovače a formátu jednotlivých prvků https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/vec­tor_to_file2.py
3 vector_to_file3.py uložení obsahu vektoru s prvky typu „byte“ do binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/vec­tor_to_file3.py
4 vector_to_file4.py uložení obsahu vektoru s prvky typu „half integer“ do binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/vec­tor_to_file4.py
5 vector_to_file5.py uložení obsahu vektoru s prvky typu „integer“ do binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/vec­tor_to_file5.py
6 vector_to_file6.py uložení obsahu vektoru s prvky typu „long integer“ do binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/vec­tor_to_file6.py
7 vector_to_file7.py uložení obsahu vektoru s prvky typu „single“ do binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/vec­tor_to_file7.py
8 vector_to_file8.py uložení obsahu vektoru s prvky typu „double“ do binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/vec­tor_to_file8.py
9 vector_to_file9.py uložení obsahu vektoru s prvky typu „half“ do binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/vec­tor_to_file9.py
10 vector_from_file1.py načtení obsahu vektoru z textového souboru se specifikací oddělovače https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/vec­tor_from_file1.py
11 vector_from_file2.py načtení obsahu vektoru z textového souboru se specifikací oddělovače a s konverzí https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/vec­tor_from_file2.py
12 vector_from_file3.py načtení obsahu vektoru z binárního souboru (nekorektní použití) https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/vec­tor_from_file3.py
13 vector_from_file4.py načtení obsahu vektoru z binárního souboru s konverzí https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/vec­tor_from_file4.py
14 vector_save.py uložení obsahu vektoru do standardního binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/vector_save.py
15 vector_load.py načtení obsahu vektoru ze standardního binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/vector_load.py
16 matrix_save1.py uložení matice s prvky typu „byte“ do standardního binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_save1.py
17 matrix_save2.py uložení matice s prvky typu „float“ do standardního binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_save2.py
18 matrix_load1.py načtení matice s prvky typu „byte“ ze standardního binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_load1.py
19 matrix_load2.py načtení matice s prvky typu „float“ ze standardního binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_load2.py
20 matrix_to_file1.py export obsahu matice do textového souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_to_file1.py
21 matrix_to_file2.py export obsahu matice do binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_to_file2.py
22 matrix_from_file1.py načtení matice z textového souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_from_file1.py
23 matrix_from_file2.py načtení matice z textového souboru s konverzí na jiný typ https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_from_file2.py
24 matrix_from_file3.py načtení matice z binárního souboru bez specifikace formátu https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_from_file3.py
25 matrix_from_file4.py načtení matice z binárního souboru se specifikací formátu https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_from_file4.py
       
26 matrix_to_file3.py uložení obsahu rozsáhlejší matice do binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_to_file3.py
27 matrix_from_file5.py načtení obsahu matice z binárního souboru se specifikací formátu https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_from_file5.py
28 matrix_from_file6.py načtení obsahu matice z binárního souboru se specifikací formátu a offsetu https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_from_file6.py
29 matrix_from_file7.py načtení obsahu matice z binárního souboru se specifikací formátu, offsetu a počtu prvků https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_from_file7.py
30 matrix_save3.py uložení obsahu rozsáhlejší matice do standardního binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_save3.py
31 matrix_load3.py přečtení obsahu matice ze standardního binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_load3.py
32 matrix_load4.py otevření souboru s maticí a přístup s využitím mmap https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_load4.py
33 matrix_load5.py přečtení části rozsáhlé matice s využitím mmap https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_load5.py
34 matrix_save_multiple.py uložení více matic do standardního binárního souboru typu npz https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_save_multiple.py
35 matrix_load_multiple.py načtení více matic ze standardního binárního souboru typu npz https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_load_multiple.py
36 matrix_save_multiple2.py uložení více matic do standardního binárního souboru typu npz se specifikací názvů matic https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_save_multiple2.py
37 matrix_save_multiple3.py uložení více matic do standardního komprimovaného binárního souboru typu npz se specifikací názvů matic https://github.com/tisnik/most-popular-python-libs/blob/master/numpy/ma­trix_save_multiple3.py

Demonstrační příklady určené pro knihovnu Pandas:

# Demonstrační příklad Stručný popis příkladu Cesta
1 vector_to_file4.py uložení obsahu vektoru s prvky typu „half integer“ do binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/vec­tor_to_file4.py
2 matrix_to_file2.py export obsahu matice do binárního souboru https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/ma­trix_to_file2.py
3 binary_df1.c vygenerování binárního souboru s prvky různých typů https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/binary_df1.c
4 binary_df2.c vygenerování binárního souboru s prvky různých typů, včetně řetězců https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/binary_df2.c
5 serie_from_file.py načtení obsahu datové řady z binárního souboru s konverzí https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/se­rie_from_file.py
6 dataframe_from_file1.py načtení obsahu datového rámce z binárního souboru se specifikací formátu společného pro všechny sloupce https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/da­taframe_from_file1.py
7 dataframe_from_file2.py načtení obsahu datového rámce z binárního souboru se specifikací formátu https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/da­taframe_from_file2.py
8 dataframe_from_file3.py načtení obsahu datového rámce z binárního souboru se specifikací formátu i endianity https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/da­taframe_from_file3.py
9 dataframe_from_file4.py načtení obsahu datového rámce z binárního souboru se specifikací formátu i endianity, bytové pole https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/da­taframe_from_file4.py
10 dataframe_from_file5.py načtení obsahu datového rámce z binárního souboru se specifikací formátu i endianity, řetězce https://github.com/tisnik/most-popular-python-libs/blob/master/pandas/da­taframe_from_file5.py

16. Odkazy na předchozí části seriálu o knihovně Pandas

Popisem knihovny Pandas (a do jisté míry i Numpy) jsme se již na stránkách Roota zabývali. Pod tímto odstavcem naleznete odkazy na jednotlivé články, které již o knihovně Pandas vyšly:

  1. Knihovna Pandas: základy práce s datovými rámci
    https://www.root.cz/clanky/knihovna-pandas-zaklady-prace-s-datovymi-ramci/
  2. Knihovna Pandas: zobrazení obsahu datových rámců, vykreslení grafů a validace dat
    https://www.root.cz/clanky/knihovna-pandas-zobrazeni-obsahu-datovych-ramcu-vykresleni-grafu-a-validace-dat/
  3. Knihovna Pandas: práce s datovými řadami (series)
    https://www.root.cz/clanky/knihovna-pandas-prace-s-datovymi-radami-series/
  4. Knihovna Pandas: pokročilejší práce s datovými řadami (series)
    https://www.root.cz/clanky/knihovna-pandas-pokrocilejsi-prace-s-datovymi-radami-series/
  5. Knihovna Pandas: spojování datových rámců s využitím append, concat, merge a join
    https://www.root.cz/clanky/knihovna-pandas-spojovani-datovych-ramcu-s-vyuzitim-append-concat-merge-a-join/
  6. Knihovna Pandas: použití metody groupby, naformátování a export tabulek pro tisk
    https://www.root.cz/clanky/knihovna-pandas-pouziti-metody-groupby-naformatovani-a-export-tabulek-pro-tisk/
  7. Knihovna Pandas: práce se seskupenými záznamy, vytvoření multiindexů
    https://www.root.cz/clanky/knihovna-pandas-prace-se-seskupenymi-zaznamy-vytvoreni-multiindexu/
  8. Operace s daty uloženými v binárních souborech v knihovnách NumPy a Pandas
    https://www.root.cz/clanky/operace-s-daty-ulozenymi-v-binarnich-souborech-v-knihovnach-numpy-a-pandas/

17. Odkazy na Internetu

  1. mmap(2) — Linux manual page
    https://www.man7.org/linux/man-pages/man2/mmap.2.html
  2. mmap (Wikipedia)
    https://en.wikipedia.org/wiki/Mmap
  3. ISO/IEC 21320–1:2015 Information technology — Document Container File — Part 1: Core
    https://www.iso.org/standar­d/60101.html
  4. ZIP (file format)
    https://en.wikipedia.org/wi­ki/ZIP_(file_format)
  5. A Simple File Format for NumPy Arrays
    https://docs.scipy.org/doc/numpy-1.14.2/neps/npy-format.html
  6. numpy.lib.format
    https://numpy.org/devdocs/re­ference/generated/numpy.lib­.format.html
  7. The NumPy array: a structure for efficient numerical computation
    https://arxiv.org/pdf/1102.1523.pdf
  8. numpy.ndarray.tofile
    https://numpy.org/doc/sta­ble/reference/generated/num­py.ndarray.tofile.html#num­py.ndarray.tofile
  9. numpy.fromfile
    https://numpy.org/doc/sta­ble/reference/generated/num­py.fromfile.html
  10. How to read part of binary file with numpy?
    https://stackoverflow.com/qu­estions/14245094/how-to-read-part-of-binary-file-with-numpy
  11. How to read binary files in Python using NumPy?
    https://stackoverflow.com/qu­estions/39762019/how-to-read-binary-files-in-python-using-numpy
  12. numpy.save
    https://numpy.org/doc/sta­ble/reference/generated/num­py.save.html#numpy.save
  13. numpy.load
    https://numpy.org/doc/sta­ble/reference/generated/num­py.load.html#numpy.load
  14. Operace typu mmap
    https://en.wikipedia.org/wiki/Mmap
  15. Funkce fseek
    https://en.cppreference.com/w/c/i­o/fseek
  16. Funkce ftell
    https://en.cppreference.com/w/c/i­o/ftell
  17. Loading binary data to NumPy/Pandas
    https://towardsdatascience.com/loading-binary-data-to-numpy-pandas-9caa03eb0672
  18. Combining Data in Pandas With merge(), .join(), and concat()
    https://realpython.com/pandas-merge-join-and-concat/
  19. Repositář python-tabulate na GitHubu
    https://github.com/astanin/python-tabulate
  20. python-tabulate na PyPi
    https://pypi.org/project/tabulate/
  21. Understanding Pandas groupby() function
    https://www.askpython.com/python-modules/pandas/pandas-groupby-function
  22. Python Pandas – GroupBy
    https://www.tutorialspoin­t.com/python_pandas/python_pan­das_groupby.htm
  23. Pandas GroupBy: Group Data in Python
    https://pythonspot.com/pandas-groupby/
  24. JOIN
    https://cs.wikipedia.org/wiki/JOIN
  25. Plotting with matplotlib
    https://pandas.pydata.org/pandas-docs/version/0.13/visualization.html
  26. Plot With Pandas: Python Data Visualization for Beginners
    https://realpython.com/pandas-plot-python/
  27. Pandas Dataframe: Plot Examples with Matplotlib and Pyplot
    https://queirozf.com/entries/pandas-dataframe-plot-examples-with-matplotlib-pyplot
  28. Opulent-Pandas na PyPi
    https://pypi.org/project/opulent-pandas/
  29. pandas_validator na PyPi
    https://pypi.org/project/pan­das_validator/
  30. pandas-validator (dokumentace)
    https://pandas-validator.readthedocs.io/en/latest/
  31. 7 Best Python Libraries for Validating Data
    https://www.yeahhub.com/7-best-python-libraries-validating-data/
  32. Universally unique identifier (Wikipedia)
    https://en.wikipedia.org/wi­ki/Universally_unique_iden­tifier
  33. Nullable integer data type
    https://pandas.pydata.org/pandas-docs/stable/user_guide/integer_na.html
  34. pandas.read_csv
    https://pandas.pydata.org/pandas-docs/stable/reference/api/pan­das.read_csv.html
  35. How to define format when using pandas to_datetime?
    https://stackoverflow.com/qu­estions/36848514/how-to-define-format-when-using-pandas-to-datetime
  36. 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/
  37. Skip rows during csv import pandas
    https://stackoverflow.com/qu­estions/20637439/skip-rows-during-csv-import-pandas
  38. Denni kurz
    https://www.cnb.cz/cs/finan­cni_trhy/devizovy_trh/kur­zy_devizoveho_trhu/denni_kur­z.txt
  39. UUID objects according to RFC 4122 (knihovna pro Python)
    https://docs.python.org/3­.5/library/uuid.html#uuid­.uuid4
  40. Object identifier (Wikipedia)
    https://en.wikipedia.org/wi­ki/Object_identifier
  41. Digital object identifier (Wikipedia)
    https://en.wikipedia.org/wi­ki/Digital_object_identifi­er
  42. voluptuous na (na PyPi)
    https://pypi.python.org/py­pi/voluptuous
  43. Repositář knihovny voluptuous na GitHubu
    https://github.com/alectho­mas/voluptuous
  44. pytest-voluptuous 1.0.2 (na PyPi)
    https://pypi.org/project/pytest-voluptuous/
  45. pytest-voluptuous (na GitHubu)
    https://github.com/F-Secure/pytest-voluptuous
  46. schemagic 0.9.1 (na PyPi)
    https://pypi.python.org/py­pi/schemagic/0.9.1
  47. Schemagic / Schemagic.web (na GitHubu)
    https://github.com/Mechrop­hile/schemagic
  48. schema 0.6.7 (na PyPi)
    https://pypi.python.org/pypi/schema
  49. schema (na GitHubu)
    https://github.com/keleshev/schema
  50. XML Schema validator and data conversion library for Python
    https://github.com/brunato/xmlschema
  51. xmlschema 0.9.7
    https://pypi.python.org/py­pi/xmlschema/0.9.7
  52. jsonschema 2.6.0
    https://pypi.python.org/py­pi/jsonschema
  53. warlock 1.3.0
    https://pypi.python.org/pypi/warlock
  54. Python Virtual Environments – A Primer
    https://realpython.com/python-virtual-environments-a-primer/
  55. pip 1.1 documentation: Requirements files
    https://pip.readthedocs.i­o/en/1.1/requirements.html
  56. unittest.mock — mock object library
    https://docs.python.org/3­.5/library/unittest.mock.html
  57. mock 2.0.0
    https://pypi.python.org/pypi/mock
  58. An Introduction to Mocking in Python
    https://www.toptal.com/python/an-introduction-to-mocking-in-python
  59. Unit testing (Wikipedia)
    https://en.wikipedia.org/wi­ki/Unit_testing
  60. Unit testing
    https://cs.wikipedia.org/wi­ki/Unit_testing
  61. Test-driven development (Wikipedia)
    https://en.wikipedia.org/wiki/Test-driven_development
  62. Pip (dokumentace)
    https://pip.pypa.io/en/stable/
  63. 5 Differences between clojure.spec and Schema
    https://lispcast.com/clojure.spec-vs-schema/
  64. Schema: Clojure(Script) library for declarative data description and validation
    https://github.com/plumatic/schema
  65. clojure.spec – Rationale and Overview
    https://clojure.org/about/spec

Autor článku

Pavel Tišnovský vystudoval VUT FIT a v současné době pracuje ve společnosti Red Hat, kde vyvíjí nástroje pro OpenShift.io.