diff --git a/pandasdmx.ipynb b/pandasdmx.ipynb index d6a7381..730e77a 100644 --- a/pandasdmx.ipynb +++ b/pandasdmx.ipynb @@ -41,16 +41,16 @@ "Requirement already satisfied: pandasdmx in ./venv/lib/python3.9/site-packages (1.4.1)\r\n", "Requirement already satisfied: pydantic==1.7 in ./venv/lib/python3.9/site-packages (1.7)\r\n", "Requirement already satisfied: requests>=2.7 in ./venv/lib/python3.9/site-packages (from pandasdmx) (2.25.1)\r\n", - "Requirement already satisfied: lxml>=3.6 in ./venv/lib/python3.9/site-packages (from pandasdmx) (4.6.2)\r\n", "Requirement already satisfied: pandas>=1.0 in ./venv/lib/python3.9/site-packages (from pandasdmx) (1.2.3)\r\n", + "Requirement already satisfied: lxml>=3.6 in ./venv/lib/python3.9/site-packages (from pandasdmx) (4.6.2)\r\n", + "Requirement already satisfied: pytz>=2017.3 in ./venv/lib/python3.9/site-packages (from pandas>=1.0->pandasdmx) (2021.1)\r\n", "Requirement already satisfied: numpy>=1.16.5 in ./venv/lib/python3.9/site-packages (from pandas>=1.0->pandasdmx) (1.20.1)\r\n", "Requirement already satisfied: python-dateutil>=2.7.3 in ./venv/lib/python3.9/site-packages (from pandas>=1.0->pandasdmx) (2.8.1)\r\n", - "Requirement already satisfied: pytz>=2017.3 in ./venv/lib/python3.9/site-packages (from pandas>=1.0->pandasdmx) (2021.1)\r\n", "Requirement already satisfied: six>=1.5 in ./venv/lib/python3.9/site-packages (from python-dateutil>=2.7.3->pandas>=1.0->pandasdmx) (1.15.0)\r\n", "Requirement already satisfied: chardet<5,>=3.0.2 in ./venv/lib/python3.9/site-packages (from requests>=2.7->pandasdmx) (4.0.0)\r\n", - "Requirement already satisfied: urllib3<1.27,>=1.21.1 in ./venv/lib/python3.9/site-packages (from requests>=2.7->pandasdmx) (1.26.3)\r\n", "Requirement already satisfied: idna<3,>=2.5 in ./venv/lib/python3.9/site-packages (from requests>=2.7->pandasdmx) (2.10)\r\n", - "Requirement already satisfied: certifi>=2017.4.17 in ./venv/lib/python3.9/site-packages (from requests>=2.7->pandasdmx) (2020.12.5)\r\n" + "Requirement already satisfied: certifi>=2017.4.17 in ./venv/lib/python3.9/site-packages (from requests>=2.7->pandasdmx) (2020.12.5)\r\n", + "Requirement already satisfied: urllib3<1.27,>=1.21.1 in ./venv/lib/python3.9/site-packages (from requests>=2.7->pandasdmx) (1.26.3)\r\n" ] } ], @@ -109,7 +109,21 @@ { "cell_type": "markdown", "source": [ - "È possibile selezionare tra più fonti di dati, tra i quali Eurostat:" + "È possibile selezionare tra più fonti di dati, tra i quali Eurostat (`ESTAT`)." + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "> __Request__: client di comunicazione tra `pandasdmx` e un server di dati come Eurostat\n", + "\n", + "Come prima cosa, è necessario creare un'istanza di `pandasdmx.Request`:" ], "metadata": { "collapsed": false, @@ -124,7 +138,7 @@ "outputs": [ { "data": { - "text/plain": "" + "text/plain": "" }, "execution_count": 3, "metadata": {}, @@ -132,7 +146,6 @@ } ], "source": [ - "# Crea un \"client\" di comunicazione SDMX-ML con Eurostat\n", "eurostat: pandasdmx.Request = pandasdmx.Request(\"ESTAT\")\n", "eurostat" ], @@ -146,7 +159,11 @@ { "cell_type": "markdown", "source": [ - "Sembra che PandaSDMX implementi la funzionalità che cercavamo di ricerca metadati:" + "> __Dataflow__: set di metadati relativi a una misura effettuata (ad esempio, `educ_enrl1ad - Students by ISCED level, study intensity and sex`)\n", + "\n", + "> __Message__: risposta HTTPS ricevuta in seguito a una richiesta effettuata ad un server di dati\n", + "\n", + "Poi, scarichiamo _tutti_ i dataflow disponibili usando `.dataflow()` sul client creato in precedenza per effettuare una richiesta al server Eurostat, creando un `pandasdmx.message.Message`:" ], "metadata": { "collapsed": false, @@ -161,7 +178,7 @@ "outputs": [ { "data": { - "text/plain": "\n
\n id: 'IDREF372221'\n prepared: '2021-03-13T13:41:50.771000+00:00'\n receiver: \n sender: \n source: \n test: False\n response: \n DataflowDefinition (6573): DS-018995 DS-022469 DS-032655 DS-043227 DS...\n DataStructureDefinition (6573): DSD_DS-018995 DSD_DS-022469 DSD_DS-03..." + "text/plain": "\n
\n id: 'IDREF382067'\n prepared: '2021-03-15T01:45:49.005000+00:00'\n receiver: \n sender: \n source: \n test: False\n response: \n DataflowDefinition (6573): DS-018995 DS-022469 DS-032655 DS-043227 DS...\n DataStructureDefinition (6573): DSD_DS-018995 DSD_DS-022469 DSD_DS-03..." }, "execution_count": 4, "metadata": {}, @@ -169,8 +186,6 @@ } ], "source": [ - "# Scarica i metadati di TUTTI dataflow disponibili su Eurostat\n", - "# Ci mette qualche minuto: i dataflow sono 6573!\n", "all_flows_msg: pandasdmx.message.Message = eurostat.dataflow()\n", "all_flows_msg" ], @@ -181,10 +196,23 @@ } } }, + { + "cell_type": "markdown", + "source": [ + "> __Series__: una specie di `dict` più veloce e avanzato implementato da `pandas`\n", + "\n", + "PandaSDMX ha la funzionalità che cercavamo di cercare dataset per keyword!\n", + "\n", + "Per effettuare la ricerca, usiamo il metodo `.to_pandas()` per convertire il `Message` in oggetti Python e/o `pandas`, poi usiamo i metodi \"nativi\" per trovare quello che ci serve:" + ], + "metadata": { + "collapsed": false + } + }, { "cell_type": "code", "source": [ - "# Convertiamo i risultati in due Series di pandas, una con i dataflow e una con la loro relativa struttura\n", + "# Converte i risultati in due Series di pandas, una con i dataflow e una con la loro relativa struttura\n", "_dict: dict[str, pandas.Series] = all_flows_msg.to_pandas()\n", "all_flows: pandas.Series = _dict[\"dataflow\"]\n", "all_structs: pandas.Series = _dict[\"structure\"]\n", @@ -234,31 +262,34 @@ } } }, + { + "cell_type": "markdown", + "source": [ + "Per continuare gli esperimenti, prendiamo il primo dataflow tra quelli contenenti `\"student\"` nel label:" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 7, "outputs": [ { "data": { - "text/plain": "(,\n )" + "text/plain": "'educ_enrl1ad'" }, - "execution_count": 12, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "# Prendiamo il primo e andiamo a scaricare i dati corrispondenti\n", "my_flow_label = student_flows.index[0]\n", - "# Scarichiamo lo specifico dataflow che ci interessa\n", - "my_flow_msg: pandasdmx.message.Message = eurostat.dataflow(my_flow_label)\n", - "my_flow: pandasdmx.model.DataflowDefinition = my_flow_msg.dataflow[my_flow_label]\n", - "# Scopriamo il label della struttura dati\n", - "my_struct_label: pandasdmx.source.DataStructureDefinition = my_flow.structure.id\n", - "# Scarichiamo la struttura del dataflow\n", - "my_struct_msg: pandasdmx.message.Message = eurostat.datastructure(my_struct_label)\n", - "my_struct: pandasdmx.source.DataStructureDefinition = my_struct_msg.structure[my_struct_label]\n", - "my_flow, my_struct" + "my_flow_label" ], "metadata": { "collapsed": false, @@ -267,25 +298,119 @@ } } }, + { + "cell_type": "markdown", + "source": [ + "Usiamo il label per chiamare di nuovo `.dataflow()`, specificando però stavolta il dataflow di cui ci interessano i dettagli:" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 8, "outputs": [ { "data": { - "text/plain": "([],\n >,\n ; >,\n ; ; ; ; ; ; >)" + "text/plain": "" }, - "execution_count": 14, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "my_flow_msg: pandasdmx.message.Message = eurostat.dataflow(my_flow_label)\n", + "my_flow: pandasdmx.model.DataflowDefinition = my_flow_msg.dataflow[my_flow_label]\n", + "my_flow" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "> __Structure__: metadati su come sono strutturate le misure di un dataflow (cosa è stato misurato, quali filtri è possibile applicare, note, etc)\n", + "\n", + "_Particolarità di Eurostat: la structure va richiesta separatamente dal dataflow, in quanto tutti i campi a parte `id` di `dataflow.structure` sono sempre vuoti._\n", + "\n", + "Scopriamo prima il label della structure, poi scarichiamo da Eurostat la structure del dataflow che ci interessa con il metodo `.datastructure()`:" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 9, + "outputs": [ + { + "data": { + "text/plain": "" + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "my_struct_label: pandasdmx.source.DataStructureDefinition = my_flow.structure.id\n", + "my_struct_msg: pandasdmx.message.Message = eurostat.datastructure(my_struct_label)\n", + "my_struct: pandasdmx.source.DataStructureDefinition = my_struct_msg.structure[my_struct_label]\n", + "my_struct" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Ispezioniamo la structure che abbiamo scaricato, visualizzandola contemporaneamente [sul Data Explorer di Eurostat](https://ec.europa.eu/eurostat/databrowser/view/educ_enrl1ad/default/table?lang=en)\n", + "\n", + "> __Measures__: valori aggregati relativi alle misure effettuate, simili a `COUNT(*)` dell'SQL\n", + "\n", + "> __Dimensions__: filtri applicabili ai dati raccolti in modo simile all'`HAVING` dell'SQL\n", + "\n", + "> __Attributes__: ???\n", + "\n", + "> __Annotations__: commenti che possono essere aggiunti al dataflow" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 10, + "outputs": [ + { + "data": { + "text/plain": "([],\n >,\n ; >,\n ; ; ; ; ; ; >)" + }, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "# Ispezioniamo la struttura, che contiene:\n", - "# - annotazioni\n", - "# - misure\n", - "# - attributi\n", - "# - dimensioni\n", "my_struct.annotations, my_struct.measures, my_struct.attributes, my_struct.dimensions" ], "metadata": { @@ -294,6 +419,79 @@ "name": "#%%\n" } } + }, + { + "cell_type": "markdown", + "source": [ + "Infine, richiediamo i dati da Eurostat, limitandoli a quelli dell'`IT`alia dal 2010 in poi e selezionando solo il `WORKTIME` `TOTAL`, e convertiamoli in una Series multi-chiave:" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 28, + "outputs": [ + { + "data": { + "text/plain": "FREQ UNIT ISCED97 SEX WORKTIME GEO TIME_PERIOD\nA NR ED0 F TOTAL IT 2010 808706.0\n 2011 811615.0\n 2012 815656.0\n M TOTAL IT 2010 872281.0\n 2011 876225.0\n ... \n UNK M TOTAL IT 2011 NaN\n 2012 NaN\n T TOTAL IT 2010 NaN\n 2011 NaN\n 2012 NaN\nName: value, Length: 279, dtype: float64" + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "my_data_msg: pandasdmx.message.Message = eurostat.data(my_flow_label, key={\"GEO\": \"IT\", \"WORKTIME\": \"TOTAL\"}, params={\"startPeriod\": \"2010\"})\n", + "my_data: pandas.Series = my_data_msg.to_pandas()\n", + "my_data" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Abbiamo ricevuto i dati, e possiamo manipolarli come una qualsiasi series di `pandas` (le quali sono molto simili a tabelle SQL in-memory):" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 30, + "outputs": [ + { + "data": { + "text/plain": "SEX TIME_PERIOD\nF 2010 808706.0\n 2011 811615.0\n 2012 815656.0\nM 2010 872281.0\n 2011 876225.0\n 2012 879256.0\nT 2010 1680987.0\n 2011 1687840.0\n 2012 1694912.0\nName: value, dtype: float64" + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Il numero di studenti [M]aschi, [F]emmine e [T]otali in Italia nel [2010], [2011] e [2012]\n", + "my_data.groupby([\"SEX\", \"TIME_PERIOD\"]).first()" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } } ], "metadata": {