{"cells": [{"cell_type": "markdown", "metadata": {}, "source": ["# 2A.i - Huge datasets, datasets hi\u00e9rarchiques\n", "\n", "L'exemple [Building a huge numpy array using pytables](http://stackoverflow.com/questions/8642626/building-a-huge-numpy-array-using-pytables) montre cr\u00e9er une grande matrice qui ne tient pourtant pas en m\u00e9moire. Il existe des modules qui permet de faire des calcul \u00e0 partir de donn\u00e9es stock\u00e9es sur disque comme si elles \u00e9taient en m\u00e9moire."]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [{"data": {"text/html": ["
run previous cell, wait for 2 seconds
\n", ""], "text/plain": [""]}, "execution_count": 2, "metadata": {}, "output_type": "execute_result"}], "source": ["from jyquickhelper import add_notebook_menu\n", "add_notebook_menu()"]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": ["%matplotlib inline"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## h5py"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Le module [h5py](http://www.h5py.org/) est un module qui permet d'agr\u00e9ger un grand nombre de donn\u00e9es dans un seul fichier et de les nommer comme des fichiers sur un disque. L'exemple suivant cr\u00e9e un seul fichier contenant deux tableaux :"]}, {"cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["\n", "random f0_100 (1000,)\n", "random f0_1000 (10000,)\n"]}], "source": ["import h5py\n", "import random\n", "hf = h5py.File('example.hdf5','w')\n", "arr = [ random.randint(0,100) for h in range(0,1000) ]\n", "hf[\"random/f0_100\"] = arr\n", "arr = [ random.randint(0,1000) for h in range(0,10000) ]\n", "hf[\"random/f0_1000\"] = arr\n", "hf.close()\n", "\n", "hf = h5py.File('example.hdf5','r')\n", "print(hf)\n", "for k in hf :\n", " for k2 in hf[k] :\n", " obj =hf[\"{0}/{1}\".format(k,k2)]\n", " print(k, k2, obj, obj.value.shape)\n", "hf.close()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["L'avantage est de pouvoir acc\u00e9der \u00e0 une partie d'un ensemble sans que celui-ci ne soit charg\u00e9 en m\u00e9moire :"]}, {"cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["[361 155 961 162 560]\n"]}], "source": ["hf = h5py.File('example.hdf5','r')\n", "print(hf[\"random/f0_1000\"][20:25])\n", "hf.close()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## pytables"]}, {"cell_type": "markdown", "metadata": {}, "source": ["[pytables](http://pytables.github.io/) peut se comprendre comme une sorte de base de donn\u00e9es [sqlite](https://www.sqlite.org/) et [sqlite3](https://docs.python.org/3/library/sqlite3.html) qui s'utilise comme un dataframe."]}, {"cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": ["try:\n", " from tables import IsDescription, StringCol, Int64Col, Float32Col, Float64Col\n", "except ImportError as e:\n", " # Parfois cela \u00e9choue sur Windows: DLL load failed: La proc\u00e9dure sp\u00e9cifi\u00e9e est introuvable.\n", " import sys\n", " raise ImportError(\"Cannot import tables.\\n\" + \"\\n\".join(sys.path)) from e\n", "\n", "class Particle(IsDescription):\n", " name = StringCol(16) # 16-character String\n", " idnumber = Int64Col() # Signed 64-bit integer\n", " pressure = Float32Col() # float (single-precision)\n", " energy = Float64Col() # double (double-precision)"]}, {"cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": ["from tables import open_file\n", "\n", "h5file = open_file(\"particule2.h5\", mode = \"w\", title = \"Test file\")"]}, {"cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [{"data": {"text/plain": ["File(filename=particule2.h5, title='Test file', mode='w', root_uep='/', filters=Filters(complevel=0, shuffle=False, bitshuffle=False, fletcher32=False, least_significant_digit=None))\n", "/ (RootGroup) 'Test file'\n", "/detector (Group) 'Detector information'\n", "/detector/readout (Table(0,)) 'Readout example'\n", " description := {\n", " \"energy\": Float64Col(shape=(), dflt=0.0, pos=0),\n", " \"idnumber\": Int64Col(shape=(), dflt=0, pos=1),\n", " \"name\": StringCol(itemsize=16, shape=(), dflt=b'', pos=2),\n", " \"pressure\": Float32Col(shape=(), dflt=0.0, pos=3)}\n", " byteorder := 'little'\n", " chunkshape := (1820,)"]}, "execution_count": 8, "metadata": {}, "output_type": "execute_result"}], "source": ["group = h5file.create_group(\"/\", 'detector', 'Detector information')\n", "table = h5file.create_table(group, 'readout', Particle, \"Readout example\")\n", "h5file"]}, {"cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": ["particle = table.row"]}, {"cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": ["for i in range(10):\n", " particle['name'] = 'Particle: %6d' % (i)\n", " particle['pressure'] = float(i*i)\n", " particle['energy'] = float(particle['pressure'] ** 4)\n", " particle['idnumber'] = i * (2 ** 34)\n", " # Insert a new particle record\n", " particle.append()"]}, {"cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": ["table.flush()"]}, {"cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [{"data": {"text/plain": ["[25.0, 36.0, 49.0]"]}, "execution_count": 12, "metadata": {}, "output_type": "execute_result"}], "source": ["table_read = h5file.root.detector.readout\n", "pressure = [x['pressure'] for x in table_read.iterrows() if 20 <= x['pressure'] < 50]\n", "pressure"]}, {"cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [{"data": {"text/plain": ["[b'Particle: 5', b'Particle: 6', b'Particle: 7']"]}, "execution_count": 13, "metadata": {}, "output_type": "execute_result"}], "source": ["names = [ x['name'] for x in table.where(\"\"\"(20 <= pressure) & (pressure < 50)\"\"\") ]\n", "names"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Ces lignes sont extraites du [tutoriel](http://www.pytables.org/usersguide/tutorials.html). Le module autorise la cr\u00e9ation de tableaux, toujours sur disque."]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": ["h5file.close()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## blosc\n", "\n", "[blosc](http://www.blosc.org/) compresse des tableaux num\u00e9rique. Cela permet de lib\u00e9rer de la m\u00e9moire pendant le temps qu'il ne sont pas utilis\u00e9s. Il est optimis\u00e9 pour perdre le moins de temps possible en compression / d\u00e9compression."]}, {"cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [{"data": {"text/plain": ["(10000000,)"]}, "execution_count": 15, "metadata": {}, "output_type": "execute_result"}], "source": ["import blosc\n", "import numpy as np\n", "\n", "a = np.linspace(0, 100, 10000000)\n", "a.shape"]}, {"cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [{"data": {"text/plain": ["(bytes, 6969171)"]}, "execution_count": 16, "metadata": {}, "output_type": "execute_result"}], "source": ["packed = blosc.pack_array(a)\n", "type(packed), len(packed)"]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [{"data": {"text/plain": ["numpy.ndarray"]}, "execution_count": 17, "metadata": {}, "output_type": "execute_result"}], "source": ["array = blosc.unpack_array(packed)\n", "type(array)"]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["166 ms \u00b1 4.96 ms per loop (mean \u00b1 std. dev. of 7 runs, 10 loops each)\n"]}], "source": ["%timeit blosc.pack_array(a)"]}, {"cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["103 ms \u00b1 6.08 ms per loop (mean \u00b1 std. dev. of 7 runs, 10 loops each)\n"]}], "source": ["%timeit blosc.unpack_array(packed)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Performance en fonction de la dimension."]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["1 0.019986204999895563 6.755499998689629e-05\n", "2 0.00012523500004135713 3.7926000004517846e-05\n", "3 0.0001631599998290767 4.819800005861907e-05\n", "4 0.0005262239999410667 0.00014814799988016603\n", "5 0.002960992999987866 0.001279211000110081\n", "6 0.018268078000119203 0.011275079999904847\n", "7 0.1547826650000843 0.09316439400004128\n", "8 1.544297945999915 0.9456180869999571\n"]}], "source": ["import time\n", "x = []\n", "t_comp = []\n", "t_dec = []\n", "size = 10\n", "for i in range(1,9): \n", " a = np.linspace(0, 100, size)\n", " t1 = time.perf_counter()\n", " packed = blosc.pack_array(a)\n", " t2 = time.perf_counter()\n", " blosc.unpack_array(packed)\n", " t3 = time.perf_counter()\n", " x.append(len(a))\n", " t_comp.append(t2-t1)\n", " t_dec.append(t3-t2)\n", " print(i, t2-t1, t3-t2)\n", " size *= 10"]}, {"cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [{"data": {"image/png": "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\n", "text/plain": ["
"]}, "metadata": {}, "output_type": "display_data"}], "source": ["import matplotlib.pyplot as plt\n", "fig, ax = plt.subplots(1, 1)\n", "ax.plot(x, t_comp, label=\"compression\")\n", "ax.plot(x, t_dec, label=\"d\u00e9compression\")\n", "ax.set_xlabel(\"taille\")\n", "ax.set_ylabel(\"time(ms)\")\n", "ax.set_xscale(\"log\", nonposx='clip')\n", "ax.set_yscale(\"log\", nonposy='clip')\n", "ax.legend();"]}, {"cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": []}], "metadata": {"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}, "language_info": {"codemirror_mode": {"name": "ipython", "version": 3}, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.0"}}, "nbformat": 4, "nbformat_minor": 2}