diff --git a/README.md b/README.md index 5a7d2c1..a8f1660 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,56 @@ -# learning-by-doing - -a set of tasks for people to learn basic software and data science skills by completing the tasks - - -## License - -Except as otherwise noted, the tutorial content of this `astropgh/learning-by-doing` is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/) [](http://creativecommons.org/licenses/by-sa/4.0/), and the code samples are licensed under the [MIT License](https://opensource.org/licenses/MIT). +# Task 4: [database] Preparing for data scraping: design a data model for top baby names +## Background +Before we start to scrape the top baby names from the webpage, we need to design +a data model that we will use to store the data. +The term "data model" has different meanings in different contexts. +We can ask what kind of object the data will be stored in. +A python list? A python dictionary? A pandas data frame? +For a given type, we can further ask how the data is stored. +For example, if we store the data in a pandas data frame, we can ask what +are the columns and rows. +Let's look at some examples. +The original webpage store the names as a table, with columns being +`year`, `female_rank1`, `female_rank2`, `male_rank1`, `male_rank2`..., and +each row corresponds to one single year. +A more extreme example would be storing the names as a sequence (say a python list), +the content of the sequence will be the names, while the indices of the sequence encode +year, ranking, and gender altogether. A possible way to encode the information is +```python +year = 2017 - index // 10 +rank = index % 5 + 1 +gender = 'female' if index % 10 < 5 else 'male' +``` +While this data model preserves all the information, it is unlikely that this +model will be very convenient when it comes to data exploration. +Yet another totally different data model is to group the data by names. +Let's say we'll store the data in a python dictionary. A possible way is: +```python +{ + 'Emma':{ + 'gender': 'female', + 'years_ranked_1': [2017, 2016, 2015, 2014, ...], + 'years_ranked_2': [2013, 2012, 2009, ...], + 'years_ranked_3': [...], + }, + 'Noah':{ + ..., + }, + ..., +} +``` +Note that the form (object) that the data is stored and how the data is structured +are two different things. (*Food for thoughts: why? can you give an example?*) +Clearly, the choice of data model heavily depends on the questions that we would +like to answer with the data. +If the amount of data is very large, we will also need to consider the avabilable +computing resources like memory usage and I/O speed when designing the data model. +For now, we don't yet need to worry about the limitation due to computing resources. +## Task +Try to come up with a data model that is good for answering each of the following questions. +Think about the code you'll need to write to interact with the data model to answer +these questions. +1. Which years Emma is the most chosen names? +2. Which name had been the most chosen name for the longest consecutive years? +3. How many unique male names have be on top 5 between years 1980 and 2000? +4. Are there more unique male names or more unique female names that are on top 5? +5. What is the distribution of the numbers of consecutive years that a male name remains the most chosen name? diff --git a/data_structure.ipynb b/data_structure.ipynb new file mode 100755 index 0000000..32792f2 --- /dev/null +++ b/data_structure.ipynb @@ -0,0 +1,1237 @@ +{ + "metadata": { + "name": "", + "signature": "sha256:b99c50f5345e8fd1ce020369618bbc3cabda5bdfdff85e2a1cce6f7592d1a2cb" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "cells": [ + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import pandas as pd" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "#\"\"\"\n", + "#get_top_names.py\n", + "#For astrophg/learning-by-doing: Task 3\n", + "#https://github.com/astropgh/learning-by-doing/tree/master/task-03\n", + "#\"\"\"\n", + "\n", + "def extract_data_lines(filename, start_text, end_text, include_start = False, include_end = False):\n", + " \"\"\"\n", + " open `filename`, and yield the lines between\n", + " the line that contains `start_text` and the line that contains `end_text`\n", + " \"\"\"\n", + "\n", + " # Needed to record the text in between\n", + " parsing = False\n", + " \n", + " # use `yield line` to return desired lines but keep the function going\n", + " with open(filename) as fh:\n", + " \n", + " for line in fh:\n", + " \n", + " ######################################################################\n", + " \n", + " if start_text in line:\n", + " \n", + " parsing = True\n", + " \n", + " if not include_start:\n", + " \n", + " continue\n", + " \n", + " ###################################################################### \n", + " \n", + " elif end_text in line:\n", + " \n", + " if include_end:\n", + " \n", + " #parsing = True\n", + " yield line\n", + " break\n", + " \n", + " else:\n", + " \n", + " parsing = False\n", + " \n", + " ######################################################################\n", + " \n", + " \n", + " if parsing: # Do stuff with the data\n", + " \n", + " yield line" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 2 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "Years = []\n", + "Names = []\n", + "\n", + "if __name__ == '__main__':\n", + " filename = 'top5names.html'\n", + " start_text = '
| \n", + " | 1918 | \n", + "1919 | \n", + "1920 | \n", + "1921 | \n", + "1922 | \n", + "1923 | \n", + "1924 | \n", + "1925 | \n", + "1926 | \n", + "1927 | \n", + "... | \n", + "2008 | \n", + "2009 | \n", + "2010 | \n", + "2011 | \n", + "2012 | \n", + "2013 | \n", + "2014 | \n", + "2015 | \n", + "2016 | \n", + "2017 | \n", + "
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| F1 | \n", + "Mary | \n", + "Mary | \n", + "Mary | \n", + "Mary | \n", + "Mary | \n", + "Mary | \n", + "Mary | \n", + "Mary | \n", + "Mary | \n", + "Mary | \n", + "... | \n", + "Emma | \n", + "Isabella | \n", + "Isabella | \n", + "Sophia | \n", + "Sophia | \n", + "Sophia | \n", + "Emma | \n", + "Emma | \n", + "Emma | \n", + "Emma | \n", + "
| F2 | \n", + "Helen | \n", + "Helen | \n", + "Dorothy | \n", + "Dorothy | \n", + "Dorothy | \n", + "Dorothy | \n", + "Dorothy | \n", + "Dorothy | \n", + "Dorothy | \n", + "Dorothy | \n", + "... | \n", + "Isabella | \n", + "Emma | \n", + "Sophia | \n", + "Isabella | \n", + "Emma | \n", + "Emma | \n", + "Olivia | \n", + "Olivia | \n", + "Olivia | \n", + "Olivia | \n", + "
| F3 | \n", + "Dorothy | \n", + "Dorothy | \n", + "Helen | \n", + "Helen | \n", + "Helen | \n", + "Helen | \n", + "Helen | \n", + "Betty | \n", + "Betty | \n", + "Betty | \n", + "... | \n", + "Emily | \n", + "Olivia | \n", + "Emma | \n", + "Emma | \n", + "Isabella | \n", + "Olivia | \n", + "Sophia | \n", + "Sophia | \n", + "Ava | \n", + "Ava | \n", + "
| F4 | \n", + "Margaret | \n", + "Margaret | \n", + "Margaret | \n", + "Margaret | \n", + "Margaret | \n", + "Margaret | \n", + "Betty | \n", + "Helen | \n", + "Helen | \n", + "Helen | \n", + "... | \n", + "Olivia | \n", + "Sophia | \n", + "Olivia | \n", + "Olivia | \n", + "Olivia | \n", + "Isabella | \n", + "Isabella | \n", + "Ava | \n", + "Sophia | \n", + "Isabella | \n", + "
| F5 | \n", + "Ruth | \n", + "Ruth | \n", + "Ruth | \n", + "Ruth | \n", + "Ruth | \n", + "Betty | \n", + "Margaret | \n", + "Margaret | \n", + "Margaret | \n", + "Margaret | \n", + "... | \n", + "Ava | \n", + "Ava | \n", + "Ava | \n", + "Ava | \n", + "Ava | \n", + "Ava | \n", + "Ava | \n", + "Isabella | \n", + "Isabella | \n", + "Sophia | \n", + "
| M1 | \n", + "John | \n", + "John | \n", + "John | \n", + "John | \n", + "John | \n", + "John | \n", + "Robert | \n", + "Robert | \n", + "Robert | \n", + "Robert | \n", + "... | \n", + "Jacob | \n", + "Jacob | \n", + "Jacob | \n", + "Jacob | \n", + "Jacob | \n", + "Noah | \n", + "Noah | \n", + "Noah | \n", + "Noah | \n", + "Liam | \n", + "
| M2 | \n", + "William | \n", + "William | \n", + "William | \n", + "Robert | \n", + "Robert | \n", + "Robert | \n", + "John | \n", + "John | \n", + "John | \n", + "John | \n", + "... | \n", + "Michael | \n", + "Ethan | \n", + "Ethan | \n", + "Mason | \n", + "Mason | \n", + "Jacob | \n", + "Liam | \n", + "Liam | \n", + "Liam | \n", + "Noah | \n", + "
| M3 | \n", + "James | \n", + "James | \n", + "Robert | \n", + "William | \n", + "William | \n", + "William | \n", + "William | \n", + "William | \n", + "James | \n", + "James | \n", + "... | \n", + "Ethan | \n", + "Michael | \n", + "Michael | \n", + "William | \n", + "Ethan | \n", + "Liam | \n", + "Mason | \n", + "Mason | \n", + "William | \n", + "William | \n", + "
| M4 | \n", + "Robert | \n", + "Robert | \n", + "James | \n", + "James | \n", + "James | \n", + "James | \n", + "James | \n", + "James | \n", + "William | \n", + "William | \n", + "... | \n", + "Joshua | \n", + "Alexander | \n", + "Jayden | \n", + "Jayden | \n", + "Noah | \n", + "Mason | \n", + "Jacob | \n", + "Jacob | \n", + "Mason | \n", + "James | \n", + "
| M5 | \n", + "Charles | \n", + "Charles | \n", + "Charles | \n", + "Charles | \n", + "Charles | \n", + "Charles | \n", + "Charles | \n", + "Charles | \n", + "Charles | \n", + "Charles | \n", + "... | \n", + "Daniel | \n", + "William | \n", + "William | \n", + "Noah | \n", + "William | \n", + "William | \n", + "William | \n", + "William | \n", + "James | \n", + "Logan | \n", + "
10 rows \u00d7 100 columns
\n", + "" + ], + "metadata": {}, + "output_type": "pyout", + "prompt_number": 9, + "text": [ + " 1918 1919 1920 1921 1922 1923 1924 \\\n", + "F1 Mary Mary Mary Mary Mary Mary Mary \n", + "F2 Helen Helen Dorothy Dorothy Dorothy Dorothy Dorothy \n", + "F3 Dorothy Dorothy Helen Helen Helen Helen Helen \n", + "F4 Margaret Margaret Margaret Margaret Margaret Margaret Betty \n", + "F5 Ruth Ruth Ruth Ruth Ruth Betty Margaret \n", + "M1 John John John John John John Robert \n", + "M2 William William William Robert Robert Robert John \n", + "M3 James James Robert William William William William \n", + "M4 Robert Robert James James James James James \n", + "M5 Charles Charles Charles Charles Charles Charles Charles \n", + "\n", + " 1925 1926 1927 ... 2008 2009 2010 \\\n", + "F1 Mary Mary Mary ... Emma Isabella Isabella \n", + "F2 Dorothy Dorothy Dorothy ... Isabella Emma Sophia \n", + "F3 Betty Betty Betty ... Emily Olivia Emma \n", + "F4 Helen Helen Helen ... Olivia Sophia Olivia \n", + "F5 Margaret Margaret Margaret ... Ava Ava Ava \n", + "M1 Robert Robert Robert ... Jacob Jacob Jacob \n", + "M2 John John John ... Michael Ethan Ethan \n", + "M3 William James James ... Ethan Michael Michael \n", + "M4 James William William ... Joshua Alexander Jayden \n", + "M5 Charles Charles Charles ... Daniel William William \n", + "\n", + " 2011 2012 2013 2014 2015 2016 2017 \n", + "F1 Sophia Sophia Sophia Emma Emma Emma Emma \n", + "F2 Isabella Emma Emma Olivia Olivia Olivia Olivia \n", + "F3 Emma Isabella Olivia Sophia Sophia Ava Ava \n", + "F4 Olivia Olivia Isabella Isabella Ava Sophia Isabella \n", + "F5 Ava Ava Ava Ava Isabella Isabella Sophia \n", + "M1 Jacob Jacob Noah Noah Noah Noah Liam \n", + "M2 Mason Mason Jacob Liam Liam Liam Noah \n", + "M3 William Ethan Liam Mason Mason William William \n", + "M4 Jayden Noah Mason Jacob Jacob Mason James \n", + "M5 Noah William William William William James Logan \n", + "\n", + "[10 rows x 100 columns]" + ] + } + ], + "prompt_number": 9 + }, + { + "cell_type": "heading", + "level": 1, + "metadata": {}, + "source": [ + "QUESTION 1: Which years Emma is the most chosen names?" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "dic_names['1918']" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 10, + "text": [ + "array(['Mary', 'Helen', 'Dorothy', 'Margaret', 'Ruth', 'John', 'William',\n", + " 'James', 'Robert', 'Charles'], \n", + " dtype='|S11')" + ] + } + ], + "prompt_number": 10 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "df_names.get_value('F1','1918')" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 11, + "text": [ + "'Mary'" + ] + } + ], + "prompt_number": 11 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "df_names.apply(lambda row: row.astype(str).str.contains('Emma').any(), axis=0)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "pyout", + "prompt_number": 12, + "text": [ + "1918 False\n", + "1919 False\n", + "1920 False\n", + "1921 False\n", + "1922 False\n", + "1923 False\n", + "1924 False\n", + "1925 False\n", + "1926 False\n", + "1927 False\n", + "1928 False\n", + "1929 False\n", + "1930 False\n", + "1931 False\n", + "1932 False\n", + "1933 False\n", + "1934 False\n", + "1935 False\n", + "1936 False\n", + "1937 False\n", + "1938 False\n", + "1939 False\n", + "1940 False\n", + "1941 False\n", + "1942 False\n", + "1943 False\n", + "1944 False\n", + "1945 False\n", + "1946 False\n", + "1947 False\n", + " ... \n", + "1988 False\n", + "1989 False\n", + "1990 False\n", + "1991 False\n", + "1992 False\n", + "1993 False\n", + "1994 False\n", + "1995 False\n", + "1996 False\n", + "1997 False\n", + "1998 False\n", + "1999 False\n", + "2000 False\n", + "2001 False\n", + "2002 True\n", + "2003 True\n", + "2004 True\n", + "2005 True\n", + "2006 True\n", + "2007 True\n", + "2008 True\n", + "2009 True\n", + "2010 True\n", + "2011 True\n", + "2012 True\n", + "2013 True\n", + "2014 True\n", + "2015 True\n", + "2016 True\n", + "2017 True\n", + "dtype: bool" + ] + } + ], + "prompt_number": 12 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print df_names[df_names=='Emma'].index" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "Index([u'F1', u'F2', u'F3', u'F4', u'F5', u'M1', u'M2', u'M3', u'M4', u'M5'], dtype='object')\n" + ] + } + ], + "prompt_number": 13 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "ranking_Emma = []\n", + "year_Emma = []\n", + "\n", + "\n", + "#for row in range(df_names.shape[0]):\n", + "for row in list(df_names.index): # The column labels are strings, not integers\n", + " \n", + " #for col in range(df_names.shape[1]):\n", + " for col in list(df_names.columns.values): # The column labels are strings, not integers\n", + " \n", + " if df_names.get_value(row,col) == 'Emma':\n", + " \n", + " print(row, col)\n", + " #break\n", + " \n", + " ranking_Emma.append(int(row[-1]))\n", + " year_Emma.append(int(col))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "('F1', '2008')\n", + "('F1', '2014')\n", + "('F1', '2015')\n", + "('F1', '2016')\n", + "('F1', '2017')\n", + "('F2', '2003')\n", + "('F2', '2004')\n", + "('F2', '2005')\n", + "('F2', '2006')\n", + "('F2', '2009')\n", + "('F2', '2012')\n", + "('F2', '2013')\n", + "('F3', '2007')\n", + "('F3', '2010')\n", + "('F3', '2011')\n", + "('F4', '2002')\n" + ] + } + ], + "prompt_number": 14 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "fig, ax = plt.subplots()\n", + "\n", + "ax.hist2d(year_Emma, ranking_Emma);\n", + "ax.set_yticks([1, 2, 3, 4]);\n", + "ax.tick_params(axis='both', which='major', pad=10, labelsize=12)\n", + "\n", + "\n", + "ax.set_title(r'$\\rm{Years \\, Emma \\, most \\, popular \\, female \\, name}$' + '\\n', fontsize=18);\n", + "\n", + "ax.set_xlabel(r'$\\rm{Year}$', fontsize=18, labelpad=5);\n", + "ax.set_ylabel(r'$\\rm{Ranking}$', fontsize=18, labelpad=10);" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "metadata": {}, + "output_type": "display_data", + "png": "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\n", + "text": [ + "