{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Data Cleaning in Python\n", "Tento Notebook obsahuje cvičenie s jednoduchou ukážkou čistenia dát pre použitie vo vizuálnej analýze za pomoci Pythnu. Získané dáta vizualizujeme pomocou jednoduchých Bar grafov a modulu Plotly. Použité dátové sady obsahujú informácie o kriminalite v ČR podľa jednotlivých regiónov a je ich možné nájsť na stránke *http://www.mapakriminality.cz/data*\n", "\n", "## Python a moduly\n", "Pre úspešné dokončenie tohto cvičenia je potrebné nainštalovať Python 3+ (preferovane 3.5.+ -- pokiaľ ho ešte nemáte nainštalovaný spravte tak stiahnutím inštalačného balíčka zo stránky *https://www.pythong.org*). Alternatívne si môžete stiahnuť distribúciu Pythnu pod názvom Anaconda (*https://www.continuum.io/downloads*), ktorá obsahuje množstvo užitočných modulov, ktoré sa hodia na prácu s dátami.\n", "\n", "Po úspešnom nainštalovaní Pythnu si stiahnite modul Plotly. Otvorte príkazovú riadku (terminál alebo konzolu, podľa OS) a zadajte príkaz:\n", "\n", "`pip install plotly`\n", "\n", "Tento príkaz môže byť spustený v ľubovoľnom adresáry.\n", "\n", "## Prehľad zložky\n", "V zložke *kriminalita* môžete nájsť súbor *clean_data_initial.ipynb*, ktoré obsahuje zákaldnú šablónu ktorú budeme dopĺňať. Nájdete tu tiež súbor *clean_data_final.ipynb*, ktoré obsahuje finálnu verziu cvičenia. Notebook *data_cleaning_pandas.ipynb* obsahuje, len pre zaujímavosť, spôsob práce s dátami za použitia modulu Pandas. V zložke */data* nájdete datasety, s ktorými budeme pracovať.\n", "\n", "## Dáta\n", "Naše dáta sú uložené v zákaldom CSV súbore, ktorý používa znak čiark (,) ako separátor medzi údajmi. Každý súbor odpovedá jednej územnej jednotke. Každý riadok obsahuje informácie o určitom časovom období (jeden mesiac) v rozmedzí od 1-2013 po 12-2016. Niektoré z údajov sú nekompletné (obsahujú stĺpce s hodnotou 0, ktorá je v kontexte nevalídna). Našou úlohou bude vytiahnuť z tohto súboru len tie dáta, ktoré nás budú zaujímať (špecifický stĺpec pre všetky CSV v zložke)\n", "\n", "## Jupyter Notebook\n", "Jupyter Notebook je jednoduchý nástroj, ktorý umožňuje rýchle prototypovanie pomocou Pythnu. Na spustenie jednotlivých buniek použite možnosť *Cells->Run Cells*, tlačidlo *run cell, select below* alebo klávesovú skraktu *ctrl + enter*" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# IMPORTS\n", "import csv\n", "import glob\n", "import plotly as py\n", "import plotly.graph_objs as go" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Variables\n", "csv_file = 'data//crimes-0100-101-903-120-167.csv'\n", "ROW_NAMES = [\"Index Kriminality\",\"Zjištěno\",\"Objasněno- Počet\",\"Objasněno- Dodatečně\", \\\n", " \"Stíháno, Vyšetřováno Osob - Mladiství 15-17 Let\",\"Stíháno, Vyšetřováno Osob - Recidivisté\", \\\n", " \"Stíháno, Vyšetřováno Osob - Celkem\",\"Stíháno, Vyšetřováno Osob - Nezletilí 1-14 Let\", \\\n", " \"Stíháno, Vyšetřováno Osob - Ženy\",\"Spácháno Skutků - Mladiství 15-17 Let\", \\\n", " \"Spácháno Skutků - Z Toho Alkohol\",\"Spácháno Skutků - Pod Vlivem\",\\\n", " \"Spácháno Skutků - Recidivisté\",\"Spácháno Skutků - Nezletilí 1-14 Let\",\\\n", " \"Škody V Tis. Kč - Zajištěno\",\"Škody V Tis. Kč - Celkem\",\"Časová Jednotka\",\\\n", " \"Kód úz.jednotky\",\"Název úz.jednotky\",\"Počet Obyv. úz. Jednotky\"]\n", "\n", "USED_ROW_NAME = 'Zjištěno'\n", "TIMESTAMP_NAME = \"Časová Jednotka\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Najprv potrebujeme načítať dáta z CSV súboru. Python ponúka metódu `open()` pre otvorenie súboru a modul `csv` pre čítanie CSV súborov. Použijeme tento kód na načítanie dát:\n", "\n", "```\n", "# Open CSV file for reading, uses ',' for delimiter\n", " with open(file_path, 'r', encoding='utf-8') as csvfile:\n", " reader = csv.reader(csvfile)\n", "\n", " # Prints CSV data to console\n", " for row in reader:\n", " print(','.join(row))\n", "```\n", "\n", "Alternatívne môžte použiť metódu `csv.DictReader()` ktorej výstupom je slovník.\n", "\n", "**TASK:** Vašou úlohou je uložiť jednotlivé riadky CSV do dátovej štruktúry a vrátiť ich ako výstup metódy\n", "\n", "**TASK 2:** Metódy v Pythne dokážu vraciať niekoľko hodnôt. Prepíšte metódu tak, aby vracala 2 hodnoty -- hlavičku CSV a dáta. Na zísaknie hlavičky môžte použiť napríklad built-in metódu `next()`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def load_csv_file(file_path):\n", " \"\"\"\n", " Loads CSV file and returns two variables, header and values\n", " \"\"\"\n", " # Open CSV file for reading, uses ',' for delimiter\n", " pass\n", " \n", " # TASK: RETURN VALUE OF LOADED FILE AS \n", " # TWO VARIABLES HEADER AND DATA (take a look at next() method)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "data = load_csv_file(csv_file)\n", "data\n", "#header, data = load_csv_file(csv_file)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Teraz keď vieme načítať hodnoty z jedného CSV súboru, budeme potrebovať metódu, ktorá nám získa všetky súbory v adresáry. \n", "\n", "**TASK : ** Implementujte funkcionalitu metódy `get_all_files_in_dir()`, vyhľadajte si modul `glob` ktorý by vám mal pomôcť." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def get_all_files_in_dir(path):\n", " \"\"\"\n", " Get all CSV files in the directory \n", " and returns them as a list of urls\n", " \"\"\"\n", " \n", " # TASK: IMPLEMENT FUNCTIONALITY, LOOK INTO glob MODULE\n", " pass\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "get_all_files_in_dir('data')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Naším ďalším krokom je získať iba tie stĺpce, ktoré nás zaujímajú.\n", "\n", "```\n", " row_index = row_names.index(name)\n", " final_data = []\n", " for row in data:\n", " final_data.append(row[row_index])\n", " \n", " return final_data\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def get_row_value(data, name, row_names):\n", " \"\"\"\n", " Takes loaded CSV file, name of the row we want to display and\n", " list of row names. Returns list containing filtered values\n", " \"\"\"\n", " pass\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# We will be ordering data based on timestamps, so first get timestamps\n", "timestamps = get_row_value(data, TIMESTAMP_NAME, header)\n", "row = get_row_value(data, USED_ROW_NAME, header)\n", "timestamps" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Uistíme sa, že naše dáta obsahujú len dáta, ktoré pre nás majú význam. V našom datasete sa nachádzajú hodnoty, o ktorých z kontextu vieme povedať, že nie sú správné. Tieto bunky obsahujú hodnotu 0. Avšak existujú aj bunky, v ktorých je hodnota 0 správna. Preto si musíme dať pozor na to, ktoré stĺpce filtrujeme a volať túto metódu len na stĺpcoch o ktorých máme dostatok informácií.\n", "\n", "```\n", " cleared_data = dict()\n", " \n", " for i in range(len(data_row)):\n", " # Values in file are strings\n", " if data_row[i] != '0':\n", " cleared_data[timestamps[i]] = data_row[i]\n", " \n", " return cleared_data\n", "```\n", "\n", "**TASK: ** Existuje lepší spôsob, ako tieto dáta nazahrnúť do výpočtu? \n", "\n", "*Poznámka:* Konštrukt `for i in range(len(data_row))` sa nepovažuje v Pythne za dobrý kód, pokiaľ by vás zaujímalo, ako na to ísť lepšie pozrite sa na metódu `zip()`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def clean_data(data_row, timestamps):\n", " \"\"\"\n", " Clears data getting rid of lines which are\n", " equal to 0. Make sure the data which are lost \n", " were noise and were not supposed to be 0.\n", " Returns dictionary using timestamp as key and value as value.\n", " \"\"\"\n", " pass\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "cleaned_row = clean_data(row, timestamps)\n", "cleaned_row" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "sorted(cleaned_row.keys())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Môžete si všímnúť, že použitím built-in metódy `sorted()`, ktorá nám zoradí kľúče dostávame zoradený list, avšak nie spôsobom, akým by sme chceli. Naše dáta by mali byť zoradené podľa roku, až potom podľa mesiacov. Potrebujeme teda zmeniť formát dátumu.\n", "\n", "```\n", " result = []\n", "\n", " for time in times:\n", " split_res = time.split('-')\n", " \n", " # To get the sorting right\n", " if int(split_res[0]) < 10:\n", " split_res[0] = '0' + split_res[0]\n", " \n", " result.append(split_res[1] + '-' + split_res[0])\n", "\n", " return result \n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def change_time_format(times):\n", " \"\"\"\n", " Changes time format from M-YYYY\n", " to YYYY-MM more suited for sorting.\n", " Returns result as a new list containing new formats\n", " \"\"\"\n", " pass\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A pre vytvorenie nového slovníka s časom v správnom formáte.\n", "\n", "```\n", " k = list(data.keys())\n", " changed_times = change_time_format(k)\n", " final_dict = dict()\n", " \n", " for i in range(len(k)):\n", " final_dict[changed_times[i]] = data[k[i]]\n", " \n", " return final_dict\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def change_dataset_time(data):\n", " \"\"\"\n", " Change time format from M-YYYY \n", " into YYYY-MM, more suitable for sorting\n", " and returns new dictionary containing dates with new keys\n", " \"\"\"\n", " pass" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "cleaned_data_time_changed = change_dataset_time(cleaned_row)\n", "cleaned_data_time_changed" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Po prečístení výsledkov budeme potrebovať dáta znova uložiť (napr. ako CSV). Metóda bude brať naše dáta, názov riadku, cestu kam budeme chcieť dáta uložiť a dobrovoľný parameter, podľa toho, či budeme chcieť, aby sa naše dáta pred uložením zoradili, alebo nie.\n", "\n", "```\n", " keys = data.keys()\n", " \n", " with open(file_name, 'w', encoding='utf-8') as csvfile:\n", " writer = csv.writer(csvfile)\n", " \n", " writer.writerow(['' , row_name])\n", " \n", " for row_key in keys:\n", " writer.writerow([row_key, data[row_key]])\n", "```\n", "\n", "**TASK:** Implementujte funkcionalitu metódy tak, aby zoradila výsledky predtým, ako ich exportuje, pokiaľ je parameter `sort` nastavený na True.\n", "\n", "**TASK 2 (optional):** Implementujte funkcionalitu tak, aby metóda brala list hodnôt a uložila ich do CSV súboru, s tým, že názov stĺpca bude názov odpovedajúcej územnej jednotky. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# TASK: CHANGE FUNCTION TO TAKE DATA FROM ALL CSV FILES\n", "def export_as_csv_file(data, row_name, file_name, sort = True):\n", " \"\"\"\n", " Takes data in a single row and the name of the row \n", " and exports it as csv file. Note that 'data' variable\n", " has to be passed as dictionary\n", " \"\"\" \n", " # TASK: MAKE CSV ORDER BASED ON DATE (FIRST YEAR THEN MONTH)\n", " pass\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Be sure to pass dictionary with cleaned data, not raw data list\n", "#export_as_csv_file(cleaned_row, USED_ROW_NAME, 'cleaned_data.csv', False)\n", "\n", "# TO EXPORT ORDERED DATA USE VARIABLE 'cleaned_data_time_changed'\n", "export_as_csv_file(cleaned_data_time_changed, USED_ROW_NAME, 'cleaned_data.csv', True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Použijeme modul Plotly na to, aby sme vytvorili jednoduchý Bar graph, ktorý bude zobrazovať naše hodnoty v jednotlivých časových obdobiach. Najjednoduchšia implementácia potrebuje dáta, ktoré ma zobraziť na X a Y osách. Preto je potrebné tieto informácie získať ako 2 listy.\n", "\n", "```\n", " k = sorted(data.keys())\n", " names = []\n", " values = []\n", " \n", " for key in k:\n", " names.append(key)\n", " values.append(data[key])\n", " \n", " return names, values\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def prepare_graph_data(data):\n", " \"\"\"\n", " Splits data passed as dictionary into names\n", " and values, makes sure that values are sorted\n", " \"\"\"\n", " pass" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Získané dáta potom použijeme na vykreslenie grafu.\n", "\n", "```\n", " graph_data = [go.Bar(\n", " x= names,\n", " y= values\n", " )]\n", "\n", " py.offline.plot(graph_data)\n", "```\n", "\n", "**TASK:** Pozrite sa na dokumentáciu Plotly a vyskúšajte si vylepšiť vzhľad grafu: *https://plot.ly/python/bar-charts/*" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def draw_graph(names, values):\n", " \"\"\"\n", " Draws a simple bar graph which will display\n", " data passed into the method\n", " \"\"\"\n", " \n", " # TASK: Take a look at: https://plot.ly/python/bar-charts/\n", " # and try out more options\n", " pass" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "graph_names, graph_values = prepare_graph_data(cleaned_data_time_changed)\n", "draw_graph(graph_names, graph_values)" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python [conda root]", "language": "python", "name": "conda-root-py" }, "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.5.2" } }, "nbformat": 4, "nbformat_minor": 0 }