<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Table of Contents
<p><div class="lev1 toc-item"><a href="#Exercise-notebook-2
Step1:  Exercise 1
Step2:  Dataframe attributes
A dataframe attribute is like a variable that can only be accessed in the context of a dataframe. One such attribute is <code>columns</code> which holds a dataframe's column names.
Step3:  Dataframe rows
A dataframe has a default integer index for its rows, which starts at zero <code>0</code>. The irow() method returns the row at the given index.
Step4:  The <code>head()</code> method
The head() method returns a dataframe with the first rows, as many as given in the argument. By default, if the argument is missing, it returns the first five rows.
Step5:  The <code>tail()</code> method
The <code>tail()</code> method is similar to the <code>head()</code> method. If no argument is used, the last five rows of the dataframe are returned, otherwise the number of rows returned is dependent on the argument.
Step6:  Selecting and displaying columns in a dataframe
You found in Week 1 that you can select and display the values for a single dataframe column by puting the name of the column (in quotes) within square brackets immediately after the dataframe's name. However you can also select and display the values for multiple columns too.
To get multiple columns you need to use a list. A list in Python is a number of items separated by commas within square brackets, for example ['Country', 'Population (1000s)']. This list is then put within square brackets immediately after the dataframe's name. The resulting expression represents a new dataframe, just with those columns, and therefore any dataframe method can be applied to it, like for example head()
Step7:  Applying methods to a dataframe column
The irow(), <code>head()</code> and <code>tail()</code> methods discussed above can be used with single columns.
Step8:  Tasks
In the code cell below, write the code to get and display the 55th row in the dataframe <code>df</code>.
Step9:  In the code cell below write the code to display the first 10 rows of the dataframe <code>df</code>.
Step10:  In the code cell below, select and display the first eight rows from the <code>'Country'</code> and <code>'TB deaths'</code> columns.
Step11:  Now go back to the 'Dataframes and CSV files' step in FutureLearn to discuss and mark it complete.
Exercise 2
Step12:  Task
In the code cell below write code to find all the rows in <code>df</code> where TB deaths exceed 10000.
Step13:  Now go back to the 'Comparison operators' step in FutureLearn to discuss and mark it complete.
Exercise 3
Step14:  If the same columns will be used repeatedly in the program, the code becomes more readable if written as follows
Step15:  Task
In the code cell below find  all the countries where the Population (1000s) is less than or equal to 50000 or TB deaths are greater than or equal to 20000.
Step16:  Now go back to the 'Bitwise operators' step in FutureLearn to discuss and mark it complete.
Exercise 4
Step17:  Removing initial spaces
There are too many columns for the dataframe to fit horizontally in this notebook, but they can be displayed separately.
Step18:  This shows that <code>' Max Wind SpeedKm/h'</code> is prefixed by a space, as are other columm names such as <code>' Mean Humidity'</code> and <code>' Max Sea Level PressurehPa'</code>.
The  <code>read_csv()</code> function has interpreted spaces after commas as being part of the next value. This can be rectified  easily by adding another argument to the <code>read_csv()</code> function to skip the initial spaces after a comma.
Step19:  Removing extra characters
Another problem shown above is that the final column is called <code>'WindDirDegrees&lt; br /&gt;'</code>.
When the dataset was exported from the Weather Underground web site html line breaks were automatically added to each line in the file which <code>read_csv()</code> has interpreted as part of the column name and its values. This can be seen more clearly by looking at more values in the final column
Step20:  <code>'WindDirDegrees&lt; br /&gt;'</code> can be changed to <code>'WindDirDegrees'</code> with the <code>rename()</code> method as follows
Step21:  To remove the <code>'&lt; br /&gt;'</code> html line breaks from the values in the <code>'WindDirDegrees'</code> column you need to use the string method <code>rstrip()</code> which is used to remove characters from the end or 'rear' of a string
Step22:  Display the first few rows of the <code>'WindDirDegrees'</code> to confirm the change
Step23:  Missing values
Missing (also called null or not available) values are marked as NaN (not a number) in dataframes.
Step24:  The isnull() method returns True for each row in a column that has a null value. The method can be used to select and display those rows. Scroll the table below to the right to check that the events column is only showing missing values.
Step25:  One way to deal with missing values is to replace them by some value. The column method fillna() fills all not available value cells with the value given as argument. In the example below, each missing event is replaced by the empty string.
Step26:  All NaN values of Events column are replaced by the empty string.
Step27:  The empty dataframe (no rows) confirms there are no more missing event values.
Another way to deal with missing values is to ignore rows with them. The dropna() dataframe method returns a new dataframe where all rows with at least one non-available value have been removed.
Step28:  Note that the table above has fewer than 251 of the original 365 rows, so there must be further null values besides the 114 missing events.
Changing the value type of a column
The type of every column in a dataframe can be determined by looking at the dataframe's dtypes attribute, like this
Step29:  The type of all the values in a column can be changed using the <code>astype()</code> method. The following code will change the values in the <code>'WindDirDegrees'</code> column from strings (object) to integers (<code>int64</code>).
Step30:  The function to_datetime() is needed to change the values in the 'GMT' column from strings (object) to dates (datetime64)
Step31:  Values of type datetime64 can be created using the datetime() function where the first integer argument is the year, the second the month and the third the day. 
The code below will get and display the row in the dataframe whose 'GMT' value is 4th June 2014.
Step32:  Queries such as 'Return all the rows where the date is between 8 December and 12 December' can be made
Step33:  Tasks
Now that the wind direction is given by a number, write code to select all days that had a northerly wind. Hint
Step34:  In the code cell below, write code to get and display all the rows in the dataframe that are beween 1 April 2014 and 
11 April 2014.
Step35:  In the cell below, write two lines of code to display the first five rows that have a missing value in the 'Max Gust SpeedKm/h' column. Hint
Step36:  Now go back to the 'Changing the value types of columns' step in FutureLearn to discuss and mark it complete.
Exercise 5
Step37:  The plot() method can make a graph of the values in a column. Gridlines are turned on by the grid argument.
Step38:  The graph can be made bigger by giving the method a figsize=(x,y) argument where x and y are integers that determine the length of the x-axis and y-axis.
Step39:  Multiple lines can be plotted by selecting multiple columns.
Step40:  Task
In the cell below, write code to plot the minimum, mean, and maximum temperature during 2014 in London.
Step41:  Now go back to the 'Every picture tells a story' step in FutureLearn to discuss and mark it complete.
Exercise 6
Step42:  The irow() method can still be used to get and display rows, but now you can now also use the datetime64 index to get a row using the dataframe's ix (index) property, like this
Step43:  A query such as 'Return all the rows where the date is between December 8th and December 12th' can now be done  succinctly like this
Step44:  Now we have a datetime64 index, let's plot 'Max Wind SpeedKm/h' again
Step45:  Now it is much clearer that the worst winds were in mid February.
Task
Use the code cell below to plot the values of 'Mean Humidity' during spring (full months of March, April and May).
<ASSISTANT_TASK:>
Python Code:
import sys
sys.version
import warnings
warnings.simplefilter('ignore', FutureWarning)
from pandas import *
show_versions()
Explanation: Table of Contents
<p><div class="lev1 toc-item"><a href="#Exercise-notebook-2:-Cleaning-up-our-act" data-toc-modified-id="Exercise-notebook-2:-Cleaning-up-our-act-1"><span class="toc-item-num">1&nbsp;&nbsp;</span>Exercise notebook 2: Cleaning up our act</a></div><div class="lev2 toc-item"><a href="#Env" data-toc-modified-id="Env-11"><span class="toc-item-num">1.1&nbsp;&nbsp;</span>Env</a></div><div class="lev2 toc-item"><a href="#Exercise-1:-Dataframes-and-CSV-files" data-toc-modified-id="Exercise-1:-Dataframes-and-CSV-files-12"><span class="toc-item-num">1.2&nbsp;&nbsp;</span>Exercise 1: Dataframes and CSV files</a></div><div class="lev3 toc-item"><a href="#Dataframe-attributes" data-toc-modified-id="Dataframe-attributes-121"><span class="toc-item-num">1.2.1&nbsp;&nbsp;</span>Dataframe attributes</a></div><div class="lev3 toc-item"><a href="#Dataframe-rows" data-toc-modified-id="Dataframe-rows-122"><span class="toc-item-num">1.2.2&nbsp;&nbsp;</span>Dataframe rows</a></div><div class="lev3 toc-item"><a href="#The-head()-method" data-toc-modified-id="The-head()-method-123"><span class="toc-item-num">1.2.3&nbsp;&nbsp;</span>The <code>head()</code> method</a></div><div class="lev3 toc-item"><a href="#The-tail()-method" data-toc-modified-id="The-tail()-method-124"><span class="toc-item-num">1.2.4&nbsp;&nbsp;</span>The <code>tail()</code> method</a></div><div class="lev3 toc-item"><a href="#Selecting-and-displaying-columns-in-a-dataframe" data-toc-modified-id="Selecting-and-displaying-columns-in-a-dataframe-125"><span class="toc-item-num">1.2.5&nbsp;&nbsp;</span>Selecting and displaying columns in a dataframe</a></div><div class="lev3 toc-item"><a href="#Applying-methods-to-a-dataframe-column" data-toc-modified-id="Applying-methods-to-a-dataframe-column-126"><span class="toc-item-num">1.2.6&nbsp;&nbsp;</span>Applying methods to a dataframe column</a></div><div class="lev3 toc-item"><a href="#Tasks" data-toc-modified-id="Tasks-127"><span class="toc-item-num">1.2.7&nbsp;&nbsp;</span>Tasks</a></div><div class="lev2 toc-item"><a href="#Exercise-2:-Comparison-operators" data-toc-modified-id="Exercise-2:-Comparison-operators-13"><span class="toc-item-num">1.3&nbsp;&nbsp;</span>Exercise 2: Comparison operators</a></div><div class="lev3 toc-item"><a href="#Task" data-toc-modified-id="Task-131"><span class="toc-item-num">1.3.1&nbsp;&nbsp;</span>Task</a></div><div class="lev2 toc-item"><a href="#Exercise-3:-Bitwise-operators" data-toc-modified-id="Exercise-3:-Bitwise-operators-14"><span class="toc-item-num">1.4&nbsp;&nbsp;</span>Exercise 3: Bitwise operators</a></div><div class="lev3 toc-item"><a href="#Task" data-toc-modified-id="Task-141"><span class="toc-item-num">1.4.1&nbsp;&nbsp;</span>Task</a></div><div class="lev2 toc-item"><a href="#Exercise-4:-Display-rows-from-dataframe" data-toc-modified-id="Exercise-4:-Display-rows-from-dataframe-15"><span class="toc-item-num">1.5&nbsp;&nbsp;</span>Exercise 4: Display rows from dataframe</a></div><div class="lev3 toc-item"><a href="#Removing-initial-spaces" data-toc-modified-id="Removing-initial-spaces-151"><span class="toc-item-num">1.5.1&nbsp;&nbsp;</span>Removing initial spaces</a></div><div class="lev3 toc-item"><a href="#Removing-extra-characters" data-toc-modified-id="Removing-extra-characters-152"><span class="toc-item-num">1.5.2&nbsp;&nbsp;</span>Removing extra characters</a></div><div class="lev3 toc-item"><a href="#Missing-values" data-toc-modified-id="Missing-values-153"><span class="toc-item-num">1.5.3&nbsp;&nbsp;</span>Missing values</a></div><div class="lev3 toc-item"><a href="#Changing-the-value-type-of-a-column" data-toc-modified-id="Changing-the-value-type-of-a-column-154"><span class="toc-item-num">1.5.4&nbsp;&nbsp;</span>Changing the value type of a column</a></div><div class="lev3 toc-item"><a href="#Tasks" data-toc-modified-id="Tasks-155"><span class="toc-item-num">1.5.5&nbsp;&nbsp;</span>Tasks</a></div><div class="lev2 toc-item"><a href="#Exercise-5:-Every-picture-tells-a-story" data-toc-modified-id="Exercise-5:-Every-picture-tells-a-story-16"><span class="toc-item-num">1.6&nbsp;&nbsp;</span>Exercise 5: Every picture tells a story</a></div><div class="lev3 toc-item"><a href="#Task" data-toc-modified-id="Task-161"><span class="toc-item-num">1.6.1&nbsp;&nbsp;</span>Task</a></div><div class="lev2 toc-item"><a href="#Exercise-6:-Changing-a-dataframe's-index" data-toc-modified-id="Exercise-6:-Changing-a-dataframe's-index-17"><span class="toc-item-num">1.7&nbsp;&nbsp;</span>Exercise 6: Changing a dataframe's index</a></div><div class="lev3 toc-item"><a href="#Task" data-toc-modified-id="Task-171"><span class="toc-item-num">1.7.1&nbsp;&nbsp;</span>Task</a></div>
# Exercise notebook 2: Cleaning up our act
This Jupyter notebook, for Week 2 of The Open University's [Learn to code for Data Analysis](https://www.futurelearn.com/courses/learn-to-code/) course, has code examples and coding activities for you. Remember to run the code in this notebook before you start.
You'll come across steps in the FutureLearn course directing you to this notebook. Once you've done the exercise, go back to FutureLearn to discuss it with your fellow learners and course facilitators and mark it as complete. 
## Env
End of explanation
df = read_csv('WHO POP TB all.csv')
df.head()
df.head(10)
df.tail(5)
Explanation: Exercise 1: Dataframes and CSV files
To read a CSV file into a dataframe you need to call the pandas function called <code>read_csv()</code>. The simplest usage of this function is with a single argument, a string that holds the name of the CSV file, for example.
End of explanation
df.columns
Explanation: Dataframe attributes
A dataframe attribute is like a variable that can only be accessed in the context of a dataframe. One such attribute is <code>columns</code> which holds a dataframe's column names.
End of explanation
df.iloc[0] # first row, index 0
df.iloc[2] # third row, index 2
Explanation: Dataframe rows
A dataframe has a default integer index for its rows, which starts at zero <code>0</code>. The irow() method returns the row at the given index.
End of explanation
df.head() # first five rows
df.head(7) # first seven rows
Explanation: The <code>head()</code> method
The head() method returns a dataframe with the first rows, as many as given in the argument. By default, if the argument is missing, it returns the first five rows.
End of explanation
df.tail() # last five rows
Explanation: The <code>tail()</code> method
The <code>tail()</code> method is similar to the <code>head()</code> method. If no argument is used, the last five rows of the dataframe are returned, otherwise the number of rows returned is dependent on the argument.
End of explanation
df[['Country', 'Population (1000s)']].head()
Explanation: Selecting and displaying columns in a dataframe
You found in Week 1 that you can select and display the values for a single dataframe column by puting the name of the column (in quotes) within square brackets immediately after the dataframe's name. However you can also select and display the values for multiple columns too.
To get multiple columns you need to use a list. A list in Python is a number of items separated by commas within square brackets, for example ['Country', 'Population (1000s)']. This list is then put within square brackets immediately after the dataframe's name. The resulting expression represents a new dataframe, just with those columns, and therefore any dataframe method can be applied to it, like for example head():
End of explanation
df['TB deaths'].iloc[2] # third value of deaths column
df['Population (1000s)'].tail() # last five values of population column      
Explanation: Applying methods to a dataframe column
The irow(), <code>head()</code> and <code>tail()</code> methods discussed above can be used with single columns.
End of explanation
df.iloc[54] # 55th row of dataframe
Explanation: Tasks
In the code cell below, write the code to get and display the 55th row in the dataframe <code>df</code>.
End of explanation
df.head(10)
Explanation: In the code cell below write the code to display the first 10 rows of the dataframe <code>df</code>.
End of explanation
df[["Country", "TB deaths"]].head(8)
Explanation: In the code cell below, select and display the first eight rows from the <code>'Country'</code> and <code>'TB deaths'</code> columns.
End of explanation
df[df['Population (1000s)'] > 80000].head()
Explanation: Now go back to the 'Dataframes and CSV files' step in FutureLearn to discuss and mark it complete.
Exercise 2: Comparison operators
Python has the following comparison operators:
== (equals)
!= (not equal)
&lt; (less than)
&gt; (greater than)
&lt;= (less than or equal to)
&gt;= (greater than or equal to)
The following code will get and display all the rows in df where it is True that the value in the 'Population (1000s)' column is greater than 80000.
End of explanation
df[df['TB deaths'] > 10000].head()
Explanation: Task
In the code cell below write code to find all the rows in <code>df</code> where TB deaths exceed 10000.
End of explanation
df[(df['Population (1000s)'] > 80000) & (df['TB deaths'] > 10000)].head()
Explanation: Now go back to the 'Comparison operators' step in FutureLearn to discuss and mark it complete.
Exercise 3: Bitwise operators
Pandas has two operators to make more complicated queries. Use the operator &amp; (means 'and') to select rows where two conditions are both true. Use the operator | (means 'or') to select rows where at least one condition is true. Don't forget to put parentheses around each comparison. For example, the following expression selects only countries with a population over 80 million inhabitants and with more that 10 thousand deaths.
End of explanation
population = df['Population (1000s)']
deaths = df['TB deaths']
df[(population > 80000) & (deaths > 10000)].head()
Explanation: If the same columns will be used repeatedly in the program, the code becomes more readable if written as follows:
End of explanation
population = df['Population (1000s)']
deaths = df['TB deaths']
df[(population <= 500000) | (deaths >= 20000)].head()
Explanation: Task
In the code cell below find  all the countries where the Population (1000s) is less than or equal to 50000 or TB deaths are greater than or equal to 20000.
End of explanation
london = read_csv('London_2014.csv')
london.head()
Explanation: Now go back to the 'Bitwise operators' step in FutureLearn to discuss and mark it complete.
Exercise 4: Display rows from dataframe
You have downloaded the file London_2014.csv from our website, it can now be read into a dataframe.
End of explanation
london.columns
Explanation: Removing initial spaces
There are too many columns for the dataframe to fit horizontally in this notebook, but they can be displayed separately.
End of explanation
london = read_csv('London_2014.csv', skipinitialspace=True)
Explanation: This shows that <code>' Max Wind SpeedKm/h'</code> is prefixed by a space, as are other columm names such as <code>' Mean Humidity'</code> and <code>' Max Sea Level PressurehPa'</code>.
The  <code>read_csv()</code> function has interpreted spaces after commas as being part of the next value. This can be rectified  easily by adding another argument to the <code>read_csv()</code> function to skip the initial spaces after a comma.
End of explanation
london['WindDirDegrees<br />'].head()
Explanation: Removing extra characters
Another problem shown above is that the final column is called <code>'WindDirDegrees&lt; br /&gt;'</code>.
When the dataset was exported from the Weather Underground web site html line breaks were automatically added to each line in the file which <code>read_csv()</code> has interpreted as part of the column name and its values. This can be seen more clearly by looking at more values in the final column:
End of explanation
london = london.rename(columns={'WindDirDegrees<br />' : 'WindDirDegrees'})
Explanation: <code>'WindDirDegrees&lt; br /&gt;'</code> can be changed to <code>'WindDirDegrees'</code> with the <code>rename()</code> method as follows:
End of explanation
london['WindDirDegrees'] = london['WindDirDegrees'].str.rstrip('<br />')
Explanation: To remove the <code>'&lt; br /&gt;'</code> html line breaks from the values in the <code>'WindDirDegrees'</code> column you need to use the string method <code>rstrip()</code> which is used to remove characters from the end or 'rear' of a string:
End of explanation
london['WindDirDegrees'].head()
Explanation: Display the first few rows of the <code>'WindDirDegrees'</code> to confirm the change:
End of explanation
london['Events'].tail()
Explanation: Missing values
Missing (also called null or not available) values are marked as NaN (not a number) in dataframes.
End of explanation
london[london['Events'].isnull()].head()
Explanation: The isnull() method returns True for each row in a column that has a null value. The method can be used to select and display those rows. Scroll the table below to the right to check that the events column is only showing missing values.
End of explanation
london['Events'] = london['Events'].fillna('')
london[london['Events'].isnull()]
Explanation: One way to deal with missing values is to replace them by some value. The column method fillna() fills all not available value cells with the value given as argument. In the example below, each missing event is replaced by the empty string.
End of explanation
london.head()
Explanation: All NaN values of Events column are replaced by the empty string.
End of explanation
london.dropna().head()
Explanation: The empty dataframe (no rows) confirms there are no more missing event values.
Another way to deal with missing values is to ignore rows with them. The dropna() dataframe method returns a new dataframe where all rows with at least one non-available value have been removed.
End of explanation
london.dtypes
Explanation: Note that the table above has fewer than 251 of the original 365 rows, so there must be further null values besides the 114 missing events.
Changing the value type of a column
The type of every column in a dataframe can be determined by looking at the dataframe's dtypes attribute, like this:
End of explanation
london['WindDirDegrees'] = london['WindDirDegrees'].astype('int64')
Explanation: The type of all the values in a column can be changed using the <code>astype()</code> method. The following code will change the values in the <code>'WindDirDegrees'</code> column from strings (object) to integers (<code>int64</code>).
End of explanation
london['GMT'] = to_datetime(london['GMT'])
london.dtypes
Explanation: The function to_datetime() is needed to change the values in the 'GMT' column from strings (object) to dates (datetime64):
End of explanation
london[london['GMT'] == datetime(2014, 6, 4)]
Explanation: Values of type datetime64 can be created using the datetime() function where the first integer argument is the year, the second the month and the third the day. 
The code below will get and display the row in the dataframe whose 'GMT' value is 4th June 2014.
End of explanation
dates = london['GMT']
start = datetime(2014, 12, 8)
end = datetime(2014, 12, 12)
london[(dates >= start) & (dates <= end)]
Explanation: Queries such as 'Return all the rows where the date is between 8 December and 12 December' can be made:
End of explanation
windir = london['WindDirDegrees']
london[(windir >= 350) | (windir <= 10)]
Explanation: Tasks
Now that the wind direction is given by a number, write code to select all days that had a northerly wind. Hint: select the rows where the direction is greater than or equal to 350 or smaller than or equal to 10, as the compass rose shows.
End of explanation
dates = london['GMT']
start = datetime(2014, 4, 1)
end = datetime(2014, 4, 11)
london[(dates >= start) & (dates <= end)]
Explanation: In the code cell below, write code to get and display all the rows in the dataframe that are beween 1 April 2014 and 
11 April 2014.
End of explanation
london[london['Max Gust SpeedKm/h'].isnull()].head(5)
Explanation: In the cell below, write two lines of code to display the first five rows that have a missing value in the 'Max Gust SpeedKm/h' column. Hint: first select the missing value rows and store them in a new dataframe, then display the first five rows of the new dataframe.
End of explanation
%matplotlib inline
Explanation: Now go back to the 'Changing the value types of columns' step in FutureLearn to discuss and mark it complete.
Exercise 5: Every picture tells a story
The following line of code tells Jupyter to display inside this notebook any graph that is created.
End of explanation
london[['Max Wind SpeedKm/h']].plot(grid=True);
# Add a semicolon at the end of the matplotlib statement to remove noise of execution of the statements.
Explanation: The plot() method can make a graph of the values in a column. Gridlines are turned on by the grid argument.
End of explanation
london[['Max Wind SpeedKm/h']].plot(grid=True, figsize=(10,5));
Explanation: The graph can be made bigger by giving the method a figsize=(x,y) argument where x and y are integers that determine the length of the x-axis and y-axis.
End of explanation
london[['Max Wind SpeedKm/h', 'Mean Wind SpeedKm/h']].plot(grid=False, figsize=(20,8));
Explanation: Multiple lines can be plotted by selecting multiple columns.
End of explanation
london[['Max TemperatureC', 'Mean TemperatureC', 'Min TemperatureC']].plot(grid=False, figsize=(20,8));
Explanation: Task
In the cell below, write code to plot the minimum, mean, and maximum temperature during 2014 in London.
End of explanation
london.index = london['GMT']
london.head(2)
Explanation: Now go back to the 'Every picture tells a story' step in FutureLearn to discuss and mark it complete.
Exercise 6: Changing a dataframe's index
Changing the dataframe's index from the default to datetime64 values is done by assigning to the dataframe's index attribute the contents of the 'GMT' column, like this:
End of explanation
london.loc[datetime(2014, 1, 1)]
Explanation: The irow() method can still be used to get and display rows, but now you can now also use the datetime64 index to get a row using the dataframe's ix (index) property, like this:
End of explanation
london.loc[datetime(2014,12,8) : datetime(2014,12,12)]
#The meaning of the above code is get the rows beween and including 
#the indices datetime(2014,12,8) and datetime(2014,12,12)
Explanation: A query such as 'Return all the rows where the date is between December 8th and December 12th' can now be done  succinctly like this:
End of explanation
london[['Max Wind SpeedKm/h']].plot(grid=True, figsize=(20,8));
Explanation: Now we have a datetime64 index, let's plot 'Max Wind SpeedKm/h' again:
End of explanation
mean_humidity = london[['Mean Humidity']]
start_date = datetime(2014, 3, 1)
end_date = datetime(2014, 5, 31)
spring_df = mean_humidity.loc[start_date : end_date]
mean_humidity.plot(grid=True, figsize=(20,8));
Explanation: Now it is much clearer that the worst winds were in mid February.
Task
Use the code cell below to plot the values of 'Mean Humidity' during spring (full months of March, April and May).
End of explanation
<END_TASK>