diff --git a/README.md b/README.md
index 226070b48a8f04ecf0c7273a8cb624d177ce2aa2..6f3a33cd1afda566a09b9606259ae128a22c7c76 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,9 @@
 # Python for Data Science
-This is an introductionary course for Using Python for Data Science applications. In the recent years Python has became extremely popular within the data science communities mainly due to its ease of use, open-source nature and the fact that it is completely free. This couse aims to introduce newcomers to the most popular packages used today - numpy, pandas and matplotlib. Note that it assumes basic knowledge of python (i.e. lists, dicts, indexing).
+This is an introductory course for using Python for Data Science applications. In the recent years Python has become popular within the data science community mainly due to its ease of use, open-source nature and the fact that it is completely free. This couse aims to introduce newcomers to the most popular packages used today - numpy, pandas and matplotlib. Note that it assumes basic knowledge of python (i.e. lists, dicts, indexing).
 
-This is entirely self-contained and self-paced. You can do it in your own time and it shouldn't take more than 6 hours to go throught all of the material. However, this course is by no means a complete guide to using Python for data science applications. It serves the purpose of an introduction into the world of data analysis and make you comfortable with looking at seemingly random numbers and trying to extract meeting from them.
+The course is run by Digital Skills at the University of Edinburgh and takes place many times throughout the year. You can find the schedule [here](https://www.ed.ac.uk/information-services/help-consultancy/is-skills/programmes-courses-and-resources/classroom-based-courses).
+
+However, the course content is entirely self-contained and can be studied without the taught course. You can do it in your own time and it shouldn't take more than 6 hours to go throught all of the material. However, this course is by no means a complete guide to using Python for data science applications. It serves the purpose of an introduction into the world of data analysis and make you comfortable with looking at seemingly random numbers and trying to extract meeting from them.
 
 The course is based on the wonderful Jupyter Notebooks which you can install from [here](http://jupyter.org/install). Alternatively, if you are from the University of Edinburgh you can access the programming environment using [Noteable](https://noteable.edina.ac.uk/) which can be accessed through the accompanying learn course (search for *Python for Data Science* course on [Learn](https://learn.ed.ac.uk)).
 
@@ -13,27 +15,30 @@ If you are using Noteable, then the easiest way to get the necessary files in th
 For an overview of how Jupyter notebooks work, you can check out the short notebook `python-data-jupyter-readme.ipynb`.
 
 ## Structure
-The course is split into 6 different notebooks:
+The course is split into 4 core notebooks followed by a couple of *extra* notebooks which allow you to apply everything you have learned to practical tasks in various fields.
 
 ### Notebook 0
-A recap of the assumed Python knowledge for the course.
+A recap of the assumed Python knowledge for the course. Skip this if you're a pro in Python already.
 
 ### Notebook 1
 Python warm-up with some text analysis exercises.
 
 ### Notebook 2
-Introduction to vectorised computing and dealing with large data with numpy.
+Introduction to vectorised computing and dealing with large data with **numpy**.
 
 ### Notebook 3
-Introduction to plotting in Python with matplotlib.
+Introduction to plotting in Python with **matplotlib**.
 
 ### Notebook 4
 Introduction to pandas and dealing with tabular data.
 
 ### Extra notebooks
-At the end of the course, there are notebooks starting with `extra` which over a wide
-range of applied data science topics. Usually students are expected to do one
-of their choice but feel free to go through all of them.
+At the end of the course, there are notebooks starting with `extra` which over a wide range of data science topics.
+- `python-data-extra-machine-learning`, introducing machine learning with scikit-learn.
+- `python-data-extra-networks`, introducing network analysis with NetworkX.
+- `python-data-extra-regex`, which introdices regular expressions, a powerful tool for working with text data.
+- `python-data-extra-text-analysis`, introducing tools for analysing text and performing sentiment analysis (see also `python-data-extra-regex`)
+- `python-data-extra-scipy`, introducing SciPy and exploring its signal processing module.
 
 ## Authors
 This course was developed by Ignat Georgiev and Patrick Kinnear from the Digital Skills team at Information Services at the University of Edinburgh.
diff --git a/attlist.txt b/attlist.txt
deleted file mode 100644
index cc3d7f7a67578867535fa551738feed970b4581e..0000000000000000000000000000000000000000
--- a/attlist.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Attributes
-Digeridoo - CC BY (freesound)
-chord-11 - CC-BY (freesound, mtcband)
-no - CC0 (freesound, allietron)
-no_male - CC0 (freesound, dragunnitum)
-yes_male - CC0 (freesound, draguunitem)
\ No newline at end of file
diff --git a/data/no.wav b/data/no.wav
deleted file mode 100644
index 80df8462f0f555de0b0dba5c90949a5553125d4b..0000000000000000000000000000000000000000
Binary files a/data/no.wav and /dev/null differ
diff --git a/data/no/no_jo_2.wav b/data/no/no_9.wav
similarity index 100%
rename from data/no/no_jo_2.wav
rename to data/no/no_9.wav
diff --git a/data/scipy_audio_licensing.txt b/data/scipy_audio_licensing.txt
new file mode 100644
index 0000000000000000000000000000000000000000..50a4f6581a4f88dd7d7159f94ce0e8face997095
--- /dev/null
+++ b/data/scipy_audio_licensing.txt
@@ -0,0 +1,33 @@
+The following audio files were obtained from Freesound.
+
+File                                                            Author                  License
+
+data-chord-11.wav                                               mtcband                 CC-BY
+
+data/no_male.wav                                                Dragunnitum             CC0
+data/yes_male.wav                                               Dragunnitum             CC0
+
+data/yes/104758__tim-kahn__yes-yes_0.wav                        tim.kahn                CC-BY
+data/yes/157506__matteusnova__the-word-yes.wav                  MatteusNova             CC-BY
+data/yes/242638__reitanna__yes-short.wav                        Reitanna                CC0
+data/yes/242640__reitanna__yesss.wav                            Reitanna                CC0
+data/yes/246307__vikuserro__yes-decisive.wav                    vikuserro               CC-BY
+data/yes/340367__daehedon__male-yes-aggressive.wav              daehedon                CC0
+data/yes/343877__reitanna__triumphant-yes-x2_0.wav              Reitanna                CC0
+data/yes/343877__reitanna__triumphant-yes-x2_1.wav              Reitanna                CC0
+data/yes/345422__artmasterrich__male-yes-01.wav                 Artmasterrich           CC0
+data/yes/71466__noisecollector__yes.wav                         NoiseCollector          CC-BY
+data/yes/ulqb8-0qyby_dragunnitum.wav                            Dragunnitum             CC0
+
+data/no/269542__allietron__no.wav                               alietron                CC0
+data/no/343891__reitanna__another-loud-no.wav                   Reitanna                CC0
+data/no/344047__reitanna__low-no.wav                            Reitanna                CC0
+data/no/345466__artmasterrich__male-nooo-02.wav                 Artmasterrich           CC0
+data/no/377738__bluesiren__disgusted-angry-ugh-no-female.wav    BlueSiren               CC0
+data/no/379496__katt16__no.wav                                  KATT16                  CC0
+data/no/431608__prucanada__no-questioning.wav                   prucanada               CC-BY
+data/no/74482__dobroide__20090617-no.wav                        dobroide                CC-BY
+data/no/hytw4-edq6s_dragunnitum.wav                             Dragunnitum             CC0
+data/no/katt16_1.wav                                            KATT16                  CC0
+
+All other audio files were recorded by the author, and are released under the MIT license.
\ No newline at end of file
diff --git a/data/scipy_test_files.csv b/data/scipy_test_files.csv
index c0d19da875974a6a98bdd899be5d7d29bd99dc8e..ca1a1844a715a4a3024b09e3352cc62304be5e97 100644
--- a/data/scipy_test_files.csv
+++ b/data/scipy_test_files.csv
@@ -1,2 +1,2 @@
-data/test_yes/yes_andy.wav,data/test_yes/yes_andrew.wav,data/test_yes/yes_laura.wav,data/test_yes/yes_satu.wav,data/test_yes/yes_tracy.wav,data/test_yes/yes_jo.wav,data/test_yes/yes_kaseya.wav,data/test_yes/yes_patrick.wav
-data/test_no/no_andy.wav,data/test_no/no_andrew.wav,data/test_no/no_laura.wav,data/test_no/no_satu.wav,data/test_no/no_tracy.wav,data/test_no/no_jo.wav,data/test_no/no_kaseya.wav,data/test_no/no_patrick.wav
\ No newline at end of file
+data/test_yes/yes_1.wav,data/test_yes/yes_2.wav,data/test_yes/yes_3.wav,data/test_yes/yes_4.wav,data/test_yes/yes_5.wav,data/test_yes/yes_6.wav,data/test_yes/yes_7.wav,data/test_yes/yes_8.wav
+data/test_no/no_1.wav,data/test_no/no_2.wav,data/test_no/no_3.wav,data/test_no/no_4.wav,data/test_no/no_5.wav,data/test_no/no_6.wav,data/test_no/no_7.wav,data/test_no/no_8.wav
diff --git a/data/scipy_training_files.csv b/data/scipy_training_files.csv
index 0c4cabcff95df8f4b84e30557891874dc71c135b..3b563b30ba5102fcdbe148272a3f41be410c679e 100644
--- a/data/scipy_training_files.csv
+++ b/data/scipy_training_files.csv
@@ -1,2 +1,2 @@
 data/yes/104758__tim-kahn__yes-yes_0.wav,data/yes/157506__matteusnova__the-word-yes.wav,data/yes/242638__reitanna__yes-short.wav,data/yes/242640__reitanna__yesss.wav,data/yes/246307__vikuserro__yes-decisive.wav,data/yes/340367__daehedon__male-yes-aggressive.wav,data/yes/343877__reitanna__triumphant-yes-x2_0.wav,data/yes/343877__reitanna__triumphant-yes-x2_1.wav,data/yes/345422__artmasterrich__male-yes-01.wav,data/yes/71466__noisecollector__yes.wav,data/yes/ulqb8-0qyby_dragunnitum.wav
-data/no/269542__allietron__no.wav,data/no/343891__reitanna__another-loud-no.wav,data/no/344047__reitanna__low-no.wav,data/no/345466__artmasterrich__male-nooo-02.wav,data/no/377738__bluesiren__disgusted-angry-ugh-no-female.wav,data/no/379496__katt16__no.wav,data/no/431608__prucanada__no-questioning.wav,data/no/74482__dobroide__20090617-no.wav,data/no/hytw4-edq6s_dragunnitum.wav,data/no/katt16_1.wav,data/no/no_jo_2.wav
\ No newline at end of file
+data/no/269542__allietron__no.wav,data/no/343891__reitanna__another-loud-no.wav,data/no/344047__reitanna__low-no.wav,data/no/345466__artmasterrich__male-nooo-02.wav,data/no/377738__bluesiren__disgusted-angry-ugh-no-female.wav,data/no/379496__katt16__no.wav,data/no/431608__prucanada__no-questioning.wav,data/no/74482__dobroide__20090617-no.wav,data/no/hytw4-edq6s_dragunnitum.wav,data/no/katt16_1.wav,data/no/no_9.wav
diff --git a/data/scipy_training_licensing.txt b/data/scipy_training_licensing.txt
deleted file mode 100644
index e42a35a7091e71adc7a0b6425b449ee4cd1e5360..0000000000000000000000000000000000000000
--- a/data/scipy_training_licensing.txt
+++ /dev/null
@@ -1 +0,0 @@
-TODO: Fill in details here.
\ No newline at end of file
diff --git a/data/test_no/no_andrew.wav b/data/test_no/no_1.wav
similarity index 100%
rename from data/test_no/no_andrew.wav
rename to data/test_no/no_1.wav
diff --git a/data/test_no/no_andy.wav b/data/test_no/no_2.wav
similarity index 100%
rename from data/test_no/no_andy.wav
rename to data/test_no/no_2.wav
diff --git a/data/test_no/no_jo.wav b/data/test_no/no_3.wav
similarity index 100%
rename from data/test_no/no_jo.wav
rename to data/test_no/no_3.wav
diff --git a/data/test_no/no_kaseya.wav b/data/test_no/no_4.wav
similarity index 100%
rename from data/test_no/no_kaseya.wav
rename to data/test_no/no_4.wav
diff --git a/data/test_no/no_laura.wav b/data/test_no/no_5.wav
similarity index 100%
rename from data/test_no/no_laura.wav
rename to data/test_no/no_5.wav
diff --git a/data/test_no/no_patrick.wav b/data/test_no/no_6.wav
similarity index 100%
rename from data/test_no/no_patrick.wav
rename to data/test_no/no_6.wav
diff --git a/data/test_no/no_satu.wav b/data/test_no/no_7.wav
similarity index 100%
rename from data/test_no/no_satu.wav
rename to data/test_no/no_7.wav
diff --git a/data/test_no/no_tracy.wav b/data/test_no/no_8.wav
similarity index 100%
rename from data/test_no/no_tracy.wav
rename to data/test_no/no_8.wav
diff --git a/data/test_yes/yes_andrew.wav b/data/test_yes/yes_1.wav
similarity index 100%
rename from data/test_yes/yes_andrew.wav
rename to data/test_yes/yes_1.wav
diff --git a/data/test_yes/yes_andy.wav b/data/test_yes/yes_2.wav
similarity index 100%
rename from data/test_yes/yes_andy.wav
rename to data/test_yes/yes_2.wav
diff --git a/data/test_yes/yes_jo.wav b/data/test_yes/yes_3.wav
similarity index 100%
rename from data/test_yes/yes_jo.wav
rename to data/test_yes/yes_3.wav
diff --git a/data/test_yes/yes_kaseya.wav b/data/test_yes/yes_4.wav
similarity index 100%
rename from data/test_yes/yes_kaseya.wav
rename to data/test_yes/yes_4.wav
diff --git a/data/test_yes/yes_laura.wav b/data/test_yes/yes_5.wav
similarity index 100%
rename from data/test_yes/yes_laura.wav
rename to data/test_yes/yes_5.wav
diff --git a/data/test_yes/yes_patrick.wav b/data/test_yes/yes_6.wav
similarity index 100%
rename from data/test_yes/yes_patrick.wav
rename to data/test_yes/yes_6.wav
diff --git a/data/test_yes/yes_satu.wav b/data/test_yes/yes_7.wav
similarity index 100%
rename from data/test_yes/yes_satu.wav
rename to data/test_yes/yes_7.wav
diff --git a/data/test_yes/yes_tracy.wav b/data/test_yes/yes_8.wav
similarity index 100%
rename from data/test_yes/yes_tracy.wav
rename to data/test_yes/yes_8.wav
diff --git a/python-data-1-warmup.ipynb b/python-data-1-warmup.ipynb
index c0827f4257fd09340eeaf38222c36788f197b830..b2e0b1573439a7310d1b79e6f79e495ae96d87bb 100644
--- a/python-data-1-warmup.ipynb
+++ b/python-data-1-warmup.ipynb
@@ -47,7 +47,7 @@
    "source": [
     "Well, that was a lot of text. Can we turn it into something useful?\n",
     "\n",
-    "For example, we can split up each line into the words making it and then count the occurances of the word \"and\". Here's a function that does that. Try it out!"
+    "For example, we can split up each line into the words making it and then count the occurances of the word \"and\". Here's code that does that. Try it out!"
    ]
   },
   {
@@ -56,27 +56,16 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# define functino\n",
-    "def countAnd(file_path):\n",
-    "    counter = 0\n",
-    "    file = open(file_path)\n",
-    "    \n",
-    "    for line in file:\n",
-    "        for word in line.split():\n",
-    "            if word == \"and\":\n",
-    "                counter += 1\n",
-    "                \n",
-    "    return counter"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# try function\n",
-    "countAnd(\"./data/humanistic_nursing.txt\")"
+    "counter = 0\n",
+    "file = open(\"data/humanistic_nursing.txt\")\n",
+    "\n",
+    "for line in file:\n",
+    "    for word in line.split():\n",
+    "        if word == \"and\":\n",
+    "            counter += 1\n",
+    "\n",
+    "# display results\n",
+    "print(\"The text contains {} 'and' words\".format(counter))"
    ]
   },
   {
@@ -84,22 +73,11 @@
    "metadata": {},
    "source": [
     "## Exercise 1: Count any word\n",
-    "Based on the function above, now write your own function which counts the occurances of any word. For example:\n",
-    "```python\n",
-    "countAny(filename, \"medicine\")\n",
-    "```\n",
-    "will return the occurences of the word \"medicine\" in the file filename."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "def countAny(file_path, des_word):\n",
-    "    # [ WRITE YOUR CODE HERE ]\n",
-    "    "
+    "Based on the code above, now write your own code which counts the occurances of any word. Do this by using a variable `target` to represent the word we're counting.\n",
+    "\n",
+    "You should find the word `patient` 125 times.\n",
+    "\n",
+    "Try looking for some other words as well."
    ]
   },
   {
@@ -108,50 +86,37 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "# Verify your function\n",
-    "countAny(\"./data/humanistic_nursing.txt\", \"patient\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Exercise 2: Count multiple words\n",
-    "Before this exercise you should be familiar with Python dictionaries. If you're not, please see [here](https://docs.python.org/3/tutorial/datastructures.html#dictionaries).\n",
-    "\n",
-    "Write a function which takes a file path and a list of words, and returns a dictionary mapping each word to its frequency in the given file.\n",
-    "\n",
-    "Intuitively, we can first fill in the dictionary keys with the words in our list. Afterwards we can count the occurrences of each word and and fill in the appropriate dictionary value.\n",
+    "target = \"patient\"\n",
     "\n",
-    "*Hint: Can we use `countAny()` for this?*"
+    "# fill in your code here"
    ]
   },
   {
-   "cell_type": "code",
-   "execution_count": null,
+   "cell_type": "markdown",
    "metadata": {},
-   "outputs": [],
    "source": [
-    "def countAll(file_path, words):\n",
-    "    # [ WRITE YOUR CODE HERE ]\n",
-    "    "
+    "## Exercise 2: Find the longest word\n",
+    "Find the word with the most characters in the whole text. Print it out and its length."
    ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
+   "metadata": {
+    "scrolled": true
+   },
    "outputs": [],
    "source": [
-    "# Verify your function\n",
-    "countAll(\"./data/humanistic_nursing.txt\", [\"patient\", \"and\", \"the\"])"
+    "# fill in your code here"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "You should expect `{'patient': 125, 'and': 1922, 'the': 2604}`"
+    "Does that seem like a correct word?\n",
+    "\n",
+    "If not, you can try storing a dictionary of the largest words you find to identify which is truly the biggest word."
    ]
   }
  ],
diff --git a/python-data-2-numpy.ipynb b/python-data-2-numpy.ipynb
index db5db2243e9a38f1240d46780c7b8dd76a4ced58..5f2bbf650010394f991a163eaac2580332dd8472 100644
--- a/python-data-2-numpy.ipynb
+++ b/python-data-2-numpy.ipynb
@@ -527,7 +527,7 @@
     "### Exercise 3\n",
     "Change the value of `c` so that the following code runs properly.\n",
     "\n",
-    "_Hint: What happens when you obtain `a*c`? What are the dimensions of this object? Use .dim, and comment out some lines, to play with this code and figure this out._"
+    "_Hint: What happens when you obtain `a*b`? What are the dimensions of this object? Use .dim, and comment out some lines, to play with this code and figure this out._"
    ]
   },
   {
@@ -955,7 +955,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Here `mean(axis=1)` means compute the mean across the columns (axis 1)"
+    "Here `mean(axis=1)` means compute the mean across the columns (axis 1). This will compute the mean in the direction where the column index grows, i.e. the mean **of each row**. Similarly, choosing `axis=0` would compute the mean in the row direction, so we would obtain the mean of each column."
    ]
   },
   {
@@ -1079,7 +1079,20 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "We can also extend this with the `numpy.linalg` package, which provides linear algebra functionality:"
+    "There are a few functions available in standard NumPy for working with matrices:\n",
+    "\n",
+    "| Function | Description |\n",
+    "| --- | --- |\n",
+    "| diag | Return the diagonal (or off-diagonal) elements of a square matrix as a 1D array,<br>or convert a 1D array into a square matrix with zeros on the off-diagonal |\n",
+    "| dot | Matrix multiplication |\n",
+    "| trace | Compute the sum of the diagonal elements |"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "We can also extend this with the `numpy.linalg` module, which provides linear algebra functionality:"
    ]
   },
   {
@@ -1102,6 +1115,22 @@
     "inv(A)  # get the inverse of a matrix"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "We needed the above import statement to get access to the `inv()` function, since it lives in the `linalg` submodule of NumPy and so wasn't imported when we imported NumPy. We could also call it directly by giving the submodule as follows:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "np.linalg.inv(A)"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -1110,9 +1139,6 @@
     "\n",
     "| Function | Description |\n",
     "| --- | --- |\n",
-    "| diag | Return the diagonal (or off-diagonal) elements of a square matrix as a 1D array,<br>or convert a 1D array into a square matrix with zeros on the off-diagonal |\n",
-    "| dot | Matrix multiplication |\n",
-    "| trace | Compute the sum of the diagonal elements |\n",
     "| det | Compute the matrix determinant |\n",
     "| eig | Compute the eigenvalues and eigenvectors of a square matrix |\n",
     "| inv | Compute the inverse of a square matrix |\n",
@@ -1213,7 +1239,7 @@
     "### Exercise 8\n",
     "Read in the file `daily_gas_price.csv`, which lists the daily price of natural gas since 1997. Each row contains a date and a price, separated by a comma. Find the minimum, maximum, and mean gas price over the dataset.\n",
     "\n",
-    "(Hint: you will need to use the delimiter option in `np.genfromtxt` to specify that data is separated by commas. Also, NumPy will interpret the data in float format by default - we may need to set the dtype to a string format at first, then discard the dates, before turning the gas prices back into floats to process them! Otherwise, NumPy may find it confusing to try and interpret dates formatted as YYYY-MM-DD as floats and will probably complain.)"
+    "_Hint: you will need to use the delimiter option in `np.genfromtxt` to specify that data is separated by commas. We will be discarding the date column..._"
    ]
   },
   {
@@ -1240,7 +1266,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.7.2"
+   "version": "3.6.8"
   }
  },
  "nbformat": 4,
diff --git a/python-data-4-pandas.ipynb b/python-data-4-pandas.ipynb
index ac2af6277f0b1cf388bae9b8b47a74165ddba350..777b6f3fdc454dd77336b81f3acd9ab0a55c1d13 100644
--- a/python-data-4-pandas.ipynb
+++ b/python-data-4-pandas.ipynb
@@ -427,25 +427,6 @@
     "frame2.loc[\"a\", \"size\"]"
    ]
   },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "### Exercise 1\n",
-    "A dataset of random numbers is created below. Obtain all rows starting from row 85 to 97.\n",
-    "\n",
-    "*Note: Remember that Python uses 0-based indexing*"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "df = pd.DataFrame(np.reshape(np.arange(10000), (100,100)))\n"
-   ]
-  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -520,21 +501,6 @@
     "| ** | pow | Exponentiation |\n"
    ]
   },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "### Exercise 2\n",
-    "Create a (3,3) DataFrame and square all elements in it."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -632,6 +598,40 @@
     "| value_counts() | Counts the number of occurrences of each unique element in a column |"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Exercise 1\n",
+    "A dataset of random numbers is created below. Obtain all rows starting from row 85 to 97.\n",
+    "\n",
+    "*Note: Remember that Python uses 0-based indexing*"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "df = pd.DataFrame(np.reshape(np.arange(10000), (100,100)))\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Exercise 2\n",
+    "Create a (3,3) DataFrame and square all elements in it."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -1034,6 +1034,23 @@
    "metadata": {},
    "outputs": [],
    "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Further Resources\n",
+    "We have now reached the end of the core notebooks for this course, covering the essential tools for any data science project using Python. There are now a range of extension notebooks introducing more specific topics which we encourage you to explore. these are:\n",
+    "- `python-data-extra-machine-learning`, introducing machine learning with scikit-learn.\n",
+    "- `python-data-extra-networks`, introducing network analysis with NetworkX.\n",
+    "- `python-data-extra-regex`, which introdices regular expressions, a powerful tool for working with text data.\n",
+    "- `python-data-extra-text-analysis`, introducing tools for analysing text and performing sentiment analysis (see also `python-data-extra-regex`)\n",
+    "- `python-data-extra-scipy`, introducing SciPy and exploring its signal processing module.\n",
+    "\n",
+    "Additonally, there is a notebook `python-data-extra-life` which is on John Conway's [Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life). This is not directly related to data science, but is a fun exercise in programming if you want to sharpen your skills in this area. This notebook was created by Alisdair Tullo, and is reproduced here with his kind permission.\n",
+    "\n",
+    "The book [Python for Data Analysis](https://discovered.ed.ac.uk/primo-explore/fulldisplay?docid=44UOE_ALMA51179646230002466&context=L&vid=44UOE_VU2&lang=en_US&search_scope=default_scope&adaptor=Local%20Search%20Engine&isFrbr=true&tab=default_tab&query=any,contains,python%20data%20analysis&sortby=date&facet=frbrgroupid,include,1619270935&offset=0) by Wes McKinney is avaliable from the library. It provides a more comprehensive overview of data science in Python, and in particular the later chapters extend and build on what has been developed so far in this course. Further, there are a host of Lynda.com courses available to extend your skills. [Python for Data Science Essential Training](https://www.lynda.com/Python-tutorials/Python-Data-Science-Essential-Training/520233-2.html) begins by crossing over with the core notebooks of this course, and goes on to introduce intereting topics including maths and stats, dimensionality reduction, outlier analysis, Bayesian analysis, and web scraping. [Python for Data Science Tips, Tricks & Techniques]() introduces methods for reading in data in arange of formats, further techniques for exploring data using pandas, and an alternative library called `ggplot` for plotting data."
+   ]
   }
  ],
  "metadata": {
diff --git a/python-data-extra-exercises.ipynb b/python-data-extra-exercises.ipynb
deleted file mode 100644
index f93a2c4b2feae2dcca0feb797c485d2886436f64..0000000000000000000000000000000000000000
--- a/python-data-extra-exercises.ipynb
+++ /dev/null
@@ -1,124 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "# Extra Notebook\n",
-    "Containing exercises to test your new data science skills\n",
-    "\n",
-    "## Exercise 1\n",
-    "Create a 8x8 matrix with a checkboard pattern of 1s and 0s"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Exercise 2\n",
-    "Obtain the determinant of a [Cauchy matrix](https://en.wikipedia.org/wiki/Cauchy_matrix) from two arrays.\n",
-    "\n",
-    "Remember the cauchy formula:\n",
-    "$$ C_{{ij}}={\\frac {1}{x_{i}-y_{j}}} $$"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Exercise 3\n",
-    "Remember the canvas exercises? Can you use slicing with a skip of 5 to get the image below?\n",
-    "\n",
-    "Remember how you can add a step to slicing in the Python built-in data types? Well, you can do that in NumyPy as well!\n",
-    "\n",
-    "\n",
-    "![white rectangle with dots](http://softdev.ppls.ed.ac.uk/static/images/dots.png)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "##  Exercise 4\n",
-    "Consider a random vector with shape (100, 2) representing coordinates, find the maximum euclidian distance between 2 points.\n",
-    "\n",
-    "Recall the Euclidean distance formula: the distance from $(x_1, y_1)$ to $(x_2, y_2)$ is\n",
-    "\n",
-    "$$ \\sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2}$$."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Execise 5\n",
-    "Generate a generic 2D Gaussian-like array, centered around 0,0\n",
-    "\n",
-    "You might want to recall the gaussian formula:\n",
-    "\n",
-    "$$ P(x) = \\frac{1}{\\sigma \\sqrt{2\\pi}} e^{\\frac{-(x - \\mu)^2}{2\\sigma^2}} $$\n",
-    "\n",
-    "You can use $$ \\mu = 0  \\quad  \\sigma = 1 $$\n",
-    "\n",
-    "*Hint: You can find the [np.meshgrid](https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.meshgrid.html) function helpful here.*"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "## Exercise 6\n",
-    "The file `data/soft_survey.csv` conta"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "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.6.7"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/python-data-extra-machine-learning.ipynb b/python-data-extra-machine-learning.ipynb
index 9b4a4e1b355b61c66a60e37be3ba097321f67eb2..2e29058d58332ebc30a34a45b745ca65b95b954e 100644
--- a/python-data-extra-machine-learning.ipynb
+++ b/python-data-extra-machine-learning.ipynb
@@ -468,6 +468,19 @@
    "source": [
     "# [ENTER CODE IN THIS BLOCK]\n"
    ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Further Resources\n",
+    "In this notebook, we briefly touched upon the area of Machine Learning, which has bloomed in the past decade. There is huge interest in the field, it is very widely applicable and there are new breakthroughs all the time.\n",
+    "\n",
+    "If you want to get more grounding in Machine Learning here's a collection of resources, all using Python of course:\n",
+    "- [Lynda courses](https://www.lynda.com/search?q=machine+learning+python) - a variety of courses on different topics of machine learning. Pick one that describes your needs the best. Lynda is free for students and staff of Edinburgh University.\n",
+    "- [deeplearning.ai](https://www.deeplearning.ai/) - a lengthy \"degree\" that takes you all the way from the basics of the field to the cutting edge. Recommended if you are interested in a career in the field, however it is paid.\n",
+    "- [Datacamp course](https://www.datacamp.com/tracks/machine-learning-with-python) - less dense than the above, gives good introduction into the field, focusing on the fundementals."
+   ]
   }
  ],
  "metadata": {
diff --git a/python-data-extra-networks.ipynb b/python-data-extra-networks.ipynb
index 7e20c00b5016e92c01b0d7bc5b935d072e5e0140..28f0ee78ca18c8b2b9062e11e05e44d95059869b 100644
--- a/python-data-extra-networks.ipynb
+++ b/python-data-extra-networks.ipynb
@@ -442,6 +442,18 @@
    "outputs": [],
    "source": []
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Further Resources\n",
+    "To find out more about network science, an accessible introdution to some foundational concepts is given in [this paper by Denny](http://www.mjdenny.com/workshops/SN_Theory_I.pdf).\n",
+    "\n",
+    "The following courses from [MIT](https://ocw.mit.edu/courses/media-arts-and-sciences/mas-961-networks-complexity-and-its-applications-spring-2011/index.htm) and [Cornell](https://www.cs.cornell.edu/courses/cs6850/2008fa/) are more technical, and give a good overview of a diverse range of topics. The mathematics behind networks is known as graph theory, and those interested in this fascinating topic are directed to the following [notes of Griffin](http://www.personal.psu.edu/cxg286/Math485.pdf), giving a good overview of the area. In this notebook, we have considered social networks. The go-to book on this subject is [Wasserman and Faust](https://discovered.ed.ac.uk/primo-explore/fulldisplay?docid=44UOE_ALMA2185037360002466&context=L&vid=44UOE_VU2&search_scope=default_scope&tab=default_tab&lang=en_US), available from the library. Additionally, the [following lecture by Tsvetovat](https://www.youtube.com/watch?v=qgGqaBAEy3Q) discusses social network analysis using NetworkX.\n",
+    "\n",
+    "A useful visualisation library for NetworkX is [nxviz](https://github.com/ericmjl/nxviz/). If conducting analysis in very large-scale networks, you may find that NetworkX will fail to store or process netowrk data efficiently at scale. In this case, it might be worth exploring other network analysis packages. Popular choices include [graph-tool](https://graph-tool.skewed.de/), [igraph](https://igraph.org/python/) and [SNAP](http://snap.stanford.edu/snappy/index.html), but please note that we can't guarantee that the installation of these packages will be easy! if you are working with large but very sparse networks, then you may find some useful functionality available in the SciPy module `scipy.sparse.csgraph` (see also our SciPy extension notebook `python-data-extra-scipy`)."
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
diff --git a/python-data-extra-regex.ipynb b/python-data-extra-regex.ipynb
index a1f1aceb3eaab44fb125dc5dfbe1e3f41377dd0f..0e648bc6e0e3089abeab254e93275d6272978116 100644
--- a/python-data-extra-regex.ipynb
+++ b/python-data-extra-regex.ipynb
@@ -298,6 +298,19 @@
    "metadata": {},
    "outputs": [],
    "source": []
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Further Resources\n",
+    "In this extra notebook, we briefly touched upon *regular expressions* and how they are used in Python. However, regular expressions are actually a standard format for text matching across all of computing and IT i.e. they are not particular to a programming language or a tool. If you are interested in textual analysis or working with databases, then I would recommend taking the time to learn regular expressions.\n",
+    "\n",
+    "Here is a collection of resources for that:\n",
+    "- [Lynda course](https://www.lynda.com/Regular-Expressions-tutorials/Using-Regular-Expressions/85870-2.html?srchtrk=index%3a1%0alinktypeid%3a2%0aq%3aregular+expressions%0apage%3a1%0as%3arelevance%0asa%3atrue%0aproducttypeid%3a2) - very good one-stop-shop for learning regular expressions. You'll be a pro at the end of the course. Lynda is free for students and staff of Edinburgh University.\n",
+    "- https://regexone.com/ - free website course on regular expressions. Also very good, comprehensive and interactive.\n",
+    "- [Python-specific tutorial](https://www.w3schools.com/python/python_regex.asp) - if you ever need to see more examples of how regular expressions are used in Python."
+   ]
   }
  ],
  "metadata": {
diff --git a/python-data-extra-scipy.ipynb b/python-data-extra-scipy.ipynb
index 85fbb446afeb05c453a05a62086935893eca98ab..44a08233fe1b75decfe19f8f7746b4dc2e2d75f7 100644
--- a/python-data-extra-scipy.ipynb
+++ b/python-data-extra-scipy.ipynb
@@ -481,6 +481,30 @@
     "In reality, we'd likely train and test on much more data. We would also train the classifier using some form of predictive model, rather than by eyeballing the data. Packages such as [scikit-learn](https://scikit-learn.org/stable/index.html) have easy-to-use inbuilt functions for building and testing classifiers (in fact, sklearn has its own project notebook as part of this course)."
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Further Resources\n",
+    "In this notebook, we've just explored a single module of scipy, the signal processing module `scipy.signal`. But there are a host of other specialized modules for specififc scientific applications, including:\n",
+    "- Special functions in physics (`scipy.special`)\n",
+    "- Integration (`scipy.integrate`)\n",
+    "- Optimization (`scipy.optimize`)\n",
+    "- Interpolcation (`scipy.interpolate`)\n",
+    "- Fourier Transforms (`scipy.fftpack`)\n",
+    "- Linear Algebra (`scipy.linalg`), and sparse Eigenvalue problems (`scipy.sparse.linalg.eigs`)\n",
+    "- Graph theory on sparse graphs (`scipy.sparse.csgraph`)\n",
+    "- Spatial algorithms (`scipy.spatial`)\n",
+    "- Statistics (`scipy.stats`)\n",
+    "- Multidimentsional image processing (`scipy.ndimage`)\n",
+    "\n",
+    "There are examples showing how to use each of these submodules, as well as the helper module `scipy.io`, in the [SciPy Tutorial](https://docs.scipy.org/doc/scipy/reference/tutorial/index.html).\n",
+    "\n",
+    "Another great resource is the [SciPy Lecture Notes](http://scipy-lectures.org/index.html), which cover a range of relevant topics from beginner to advanced. Of particular interest for those starting out may be the notes on [getting help and finding documentation](http://scipy-lectures.org/intro/help/help.html).\n",
+    "\n",
+    "SciPy is a core part of the Python scientific computing ecosystem, so it interfaces well with many common Python packages. We've seen that it rests on NumPy, and that we can use it alongside Matplotlib. To perform statistical analyses, we can also use the `scipy.stats` module along with Pandas, and for machine learning applications we can use it with scikit-learn (the subject of the notebook `python-data-extra-machine-learning`). While scipy tends to implement numerical methods, users who wish to extend its functionality to symbolic computation could explore the [SymPy package](https://docs.sympy.org/latest/tutorial/)."
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -488,10 +512,15 @@
     "## References\n",
     "This notebook was based on a project from \"Enhance your DSP Course with these Interesting Projects\" by D. Hoffbeck, in proceedings AC 2012-3836, the American Society for Engineering Education, 2012. \n",
     "\n",
-    "Training files were obtained from freesound. Licensing info and accreditation is given in scipy_training_licensing.txt.\n",
-    "\n",
-    "Testing files were recorded by the author."
+    "Some of this notebook's audio files were obtained from freesound. Licensing info and accreditation is given in scipy_audio_licensing.txt."
    ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
   }
  ],
  "metadata": {
@@ -510,7 +539,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.6.6"
+   "version": "3.6.8"
   }
  },
  "nbformat": 4,
diff --git a/python-data-extra-text-analysis.ipynb b/python-data-extra-text-analysis.ipynb
index 9a93aa841ec82293ef15b97a0dba9c273d7a6356..841993f721e2c5c8033c8662a430b1f04c8b9033 100644
--- a/python-data-extra-text-analysis.ipynb
+++ b/python-data-extra-text-analysis.ipynb
@@ -402,11 +402,13 @@
    "source": []
   },
   {
-   "cell_type": "code",
-   "execution_count": null,
+   "cell_type": "markdown",
    "metadata": {},
-   "outputs": [],
-   "source": []
+   "source": [
+    "## Further Resources\n",
+    "- [Python for Data Analysis book](https://www.amazon.co.uk/Python-Data-Analysis-Wrangling-IPython/dp/1449319793) - Chapters 5 to 10 are useful for text analysis and also can compliment the rest of the course. The book is available at the Main Lirbrary at Edinburgh University.\n",
+    "- [Text analysis blog post](https://www.analyticsvidhya.com/blog/2018/02/the-different-methods-deal-text-data-predictive-python/) - long practical blog post on using Python for text analysis. Similar to what you did in this notebook."
+   ]
   }
  ],
  "metadata": {