{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
" \n",
" \n",
" \n",
" \n",
" \n",
" \n",
"[Home Page](../../START_HERE.ipynb)\n",
"\n",
"[Previous Notebook](Challenge.ipynb)\n",
" \n",
" \n",
" \n",
" \n",
"[1](Challenge.ipynb)\n",
"[2]\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Bike Rental Prediction Challenge - Solution\n",
"\n",
"## 1. Introduction\n",
"\n",
"This notebook walks through an end-to-end GPU machine learning workflow where cuDF is used for processing the data and cuML is used to train machine learning models on it. \n",
"\n",
"After completing this excercise, you will be able to use cuDF to load data from disk, combine tables, scale features, use one-hote encoding and even write your own GPU kernels to efficiently transform feature columns. Additionaly you will learn how to pass this data to cuML, and how to train ML models on it. The trained model is saved and it will be used for prediction.\n",
"\n",
"It is not required that the user is familiar with cuDF or cuML. Since our aim is to go from ETL to ML training, a detailed introduction is out of scope for this notebook. We recommend [Introduction to cuDF](../../CuDF/01-Intro_to_cuDF.ipynb) for additional information.\n",
"\n",
"### 1.2. Problem statement\n",
"\n",
"We are trying to predict daily demand for short-term bike rentals made in 2011 and 2012. We will combine three data sources: bike rental information, historical weather data, and dates of public holidays. In Section 2 of this notebook we will use cuDF to combine these data into a single dataset that can be used as an input for machine learning algorithms. In Section 3 we train models using cuML to predict bike rentals.\n",
"\n",
"### 1.3 Why RAPIDS?\n",
"\n",
"Using the GPU accelerated libraries from RAPIDS greatly reduces the execution time of a data science workflow. This leads to faster iteration with data preparation and model selection, and overall a more efficient workflow.\n",
"\n",
"### 1.2.1 References\n",
"\n",
"This notebook is inspired by the [blog article](https://medium.com/rapids-ai/essential-machine-learning-with-linear-models-in-rapids-part-1-of-a-series-992fab0240da) from Paul Mahler and its accompanying [notebook](https://github.com/rapidsai-community/notebooks-contrib/blob/master/blog_notebooks/regression/regression_blog_notebook.ipynb). The dataset is prepared along the steps given by *Hadi Fanaee-T and Joao Gama* in their [paper](https://doi.org/10.1007/s13748-013-0040-3) *Event labeling combining ensemble detectors and background knowledge*. The exploratory data analysis notebooks by [Vivek Srinivasan](https://www.kaggle.com/viveksrinivasan/eda-ensemble-model-top-10-percentile) and [Mitesh Yadav](https://www.kaggle.com/miteshyadav/comprehensive-eda-with-xgboost-top-10-percentile) provided useful input for this excercise. \n",
"\n",
"First part of this notebook contains sections from [Introduction to cuDF](https://github.com/rapidsai-community/notebooks-contrib/blob/master/getting_started_notebooks/intro_tutorials/02_Introduction_to_cuDF.ipynb) by Paul Hendricks, which gives a concise introduction to cuDF, also discussing a few points not mentioned in this notebook. \n",
"\n",
"Dataset sources:\n",
"- The bike sharing dataset is provided by [Capital Bike Share](https://www.capitalbikeshare.com/system-data).\n",
"- The weather data is retrieved from the [Bike Sharing Dataset](https://archive.ics.uci.edu/ml/datasets/bike+sharing+dataset) hosted by the UCI Machine Learning repository.\n",
"- The original source of the weather data is https://www.freemeteo.com.\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. Prepare dataset with cuDF\n",
"Let's start by loading the necessary libraries"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import cudf\n",
"import pandas as pd\n",
"import numpy as np\n",
"\n",
"from datetime import datetime, timedelta\n",
"import os\n",
"import sys\n",
"sys.path.insert(1, os.path.realpath(os.path.pardir))\n",
"import importlib\n",
"import utils\n",
"importlib.reload(utils)\n",
"from utils import fetch_bike_dataset, fetch_weather_dataset, read_bike_data_pandas\n",
"import matplotlib.pyplot as plt\n",
"import seaborn as sns"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2.1 Prepare weather data\n",
"First, we will download the weather data."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Downloading https://archive.ics.uci.edu/ml/machine-learning-databases/00275/Bike-Sharing-Dataset.zip to data/Bike-Sharing-Dataset.zip\n",
"Weather file saved at data/weather2011-2012.csv\n"
]
}
],
"source": [
"filename = fetch_weather_dataset()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"cuDF DataFrames are a tabular structure of data that reside on the GPU. We interface with these cuDF DataFrames in the same way we interface with Pandas DataFrames that reside on the CPU - with a few deviations. Load data from CSV file into a cuDF DataFrame."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"weather = cudf.read_csv(filename)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 2.1.1 Inspecting a cuDF DataFrame\n",
"\n",
"There are several ways to inspect a cuDF DataFrame. The first method is to enter the cuDF DataFrame directly into the REPL. This shows us an overview about the DatFrame including its type and metadata such as the number of rows or columns."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Hour
\n",
"
Temperature
\n",
"
Relative Temperature
\n",
"
Rel. humidity
\n",
"
Wind
\n",
"
Weather
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2011-01-01T00:00:00Z
\n",
"
3.28
\n",
"
3.0014
\n",
"
81
\n",
"
0.0000
\n",
"
Clear or Partly cloudy
\n",
"
\n",
"
\n",
"
1
\n",
"
2011-01-01T01:00:00Z
\n",
"
2.34
\n",
"
1.9982
\n",
"
80
\n",
"
0.0000
\n",
"
Clear or Partly cloudy
\n",
"
\n",
"
\n",
"
2
\n",
"
2011-01-01T02:00:00Z
\n",
"
2.34
\n",
"
1.9982
\n",
"
80
\n",
"
0.0000
\n",
"
Clear or Partly cloudy
\n",
"
\n",
"
\n",
"
3
\n",
"
2011-01-01T03:00:00Z
\n",
"
3.28
\n",
"
3.0014
\n",
"
75
\n",
"
0.0000
\n",
"
Clear or Partly cloudy
\n",
"
\n",
"
\n",
"
4
\n",
"
2011-01-01T04:00:00Z
\n",
"
3.28
\n",
"
3.0014
\n",
"
75
\n",
"
0.0000
\n",
"
Clear or Partly cloudy
\n",
"
\n",
"
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
\n",
"
\n",
"
17374
\n",
"
2012-12-31T19:00:00Z
\n",
"
4.22
\n",
"
1.0016
\n",
"
60
\n",
"
11.0014
\n",
"
Mist or Cloudy
\n",
"
\n",
"
\n",
"
17375
\n",
"
2012-12-31T20:00:00Z
\n",
"
4.22
\n",
"
1.0016
\n",
"
60
\n",
"
11.0014
\n",
"
Mist or Cloudy
\n",
"
\n",
"
\n",
"
17376
\n",
"
2012-12-31T21:00:00Z
\n",
"
4.22
\n",
"
1.0016
\n",
"
60
\n",
"
11.0014
\n",
"
Clear or Partly cloudy
\n",
"
\n",
"
\n",
"
17377
\n",
"
2012-12-31T22:00:00Z
\n",
"
4.22
\n",
"
1.9982
\n",
"
56
\n",
"
8.9981
\n",
"
Clear or Partly cloudy
\n",
"
\n",
"
\n",
"
17378
\n",
"
2012-12-31T23:00:00Z
\n",
"
4.22
\n",
"
1.9982
\n",
"
65
\n",
"
8.9981
\n",
"
Clear or Partly cloudy
\n",
"
\n",
" \n",
"
\n",
"
17379 rows × 6 columns
\n",
"
"
],
"text/plain": [
" Hour Temperature Relative Temperature Rel. humidity \\\n",
"0 2011-01-01T00:00:00Z 3.28 3.0014 81 \n",
"1 2011-01-01T01:00:00Z 2.34 1.9982 80 \n",
"2 2011-01-01T02:00:00Z 2.34 1.9982 80 \n",
"3 2011-01-01T03:00:00Z 3.28 3.0014 75 \n",
"4 2011-01-01T04:00:00Z 3.28 3.0014 75 \n",
"... ... ... ... ... \n",
"17374 2012-12-31T19:00:00Z 4.22 1.0016 60 \n",
"17375 2012-12-31T20:00:00Z 4.22 1.0016 60 \n",
"17376 2012-12-31T21:00:00Z 4.22 1.0016 60 \n",
"17377 2012-12-31T22:00:00Z 4.22 1.9982 56 \n",
"17378 2012-12-31T23:00:00Z 4.22 1.9982 65 \n",
"\n",
" Wind Weather \n",
"0 0.0000 Clear or Partly cloudy \n",
"1 0.0000 Clear or Partly cloudy \n",
"2 0.0000 Clear or Partly cloudy \n",
"3 0.0000 Clear or Partly cloudy \n",
"4 0.0000 Clear or Partly cloudy \n",
"... ... ... \n",
"17374 11.0014 Mist or Cloudy \n",
"17375 11.0014 Mist or Cloudy \n",
"17376 11.0014 Clear or Partly cloudy \n",
"17377 8.9981 Clear or Partly cloudy \n",
"17378 8.9981 Clear or Partly cloudy \n",
"\n",
"[17379 rows x 6 columns]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"weather"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A second way to inspect a cuDF DataFrame is to wrap the object in a Python print function `print(weather)` function. This results in showing the rows and columns of the dataframe with simple formating.\n",
"\n",
"For very large dataframes, we often want to see the first couple rows. We can use the `head` method of a cuDF DataFrame to view the first N rows."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Hour
\n",
"
Temperature
\n",
"
Relative Temperature
\n",
"
Rel. humidity
\n",
"
Wind
\n",
"
Weather
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2011-01-01T00:00:00Z
\n",
"
3.28
\n",
"
3.0014
\n",
"
81
\n",
"
0.0
\n",
"
Clear or Partly cloudy
\n",
"
\n",
"
\n",
"
1
\n",
"
2011-01-01T01:00:00Z
\n",
"
2.34
\n",
"
1.9982
\n",
"
80
\n",
"
0.0
\n",
"
Clear or Partly cloudy
\n",
"
\n",
"
\n",
"
2
\n",
"
2011-01-01T02:00:00Z
\n",
"
2.34
\n",
"
1.9982
\n",
"
80
\n",
"
0.0
\n",
"
Clear or Partly cloudy
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Hour Temperature Relative Temperature Rel. humidity \\\n",
"0 2011-01-01T00:00:00Z 3.28 3.0014 81 \n",
"1 2011-01-01T01:00:00Z 2.34 1.9982 80 \n",
"2 2011-01-01T02:00:00Z 2.34 1.9982 80 \n",
"\n",
" Wind Weather \n",
"0 0.0 Clear or Partly cloudy \n",
"1 0.0 Clear or Partly cloudy \n",
"2 0.0 Clear or Partly cloudy "
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"weather.head(3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 2.1.2 Columns\n",
"\n",
"cuDF DataFrames store metadata such as information about columns or data types. We can access the columns of a cuDF DataFrame using the `.columns` attribute."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Index(['Hour', 'Temperature', 'Relative Temperature', 'Rel. humidity', 'Wind',\n",
" 'Weather'],\n",
" dtype='object')\n"
]
}
],
"source": [
"print(weather.columns)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can modify the columns of a cuDF DataFrame by modifying the `columns` attribute. We can do this by setting that attribute equal to a list of strings representing the new columns. Let's shorten the two longest column names!"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Hour
\n",
"
Temperature
\n",
"
RTemp
\n",
"
Humidity
\n",
"
Wind
\n",
"
Weather
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2011-01-01T00:00:00Z
\n",
"
3.28
\n",
"
3.0014
\n",
"
81
\n",
"
0.0
\n",
"
Clear or Partly cloudy
\n",
"
\n",
"
\n",
"
1
\n",
"
2011-01-01T01:00:00Z
\n",
"
2.34
\n",
"
1.9982
\n",
"
80
\n",
"
0.0
\n",
"
Clear or Partly cloudy
\n",
"
\n",
"
\n",
"
2
\n",
"
2011-01-01T02:00:00Z
\n",
"
2.34
\n",
"
1.9982
\n",
"
80
\n",
"
0.0
\n",
"
Clear or Partly cloudy
\n",
"
\n",
"
\n",
"
3
\n",
"
2011-01-01T03:00:00Z
\n",
"
3.28
\n",
"
3.0014
\n",
"
75
\n",
"
0.0
\n",
"
Clear or Partly cloudy
\n",
"
\n",
"
\n",
"
4
\n",
"
2011-01-01T04:00:00Z
\n",
"
3.28
\n",
"
3.0014
\n",
"
75
\n",
"
0.0
\n",
"
Clear or Partly cloudy
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Hour Temperature RTemp Humidity Wind \\\n",
"0 2011-01-01T00:00:00Z 3.28 3.0014 81 0.0 \n",
"1 2011-01-01T01:00:00Z 2.34 1.9982 80 0.0 \n",
"2 2011-01-01T02:00:00Z 2.34 1.9982 80 0.0 \n",
"3 2011-01-01T03:00:00Z 3.28 3.0014 75 0.0 \n",
"4 2011-01-01T04:00:00Z 3.28 3.0014 75 0.0 \n",
"\n",
" Weather \n",
"0 Clear or Partly cloudy \n",
"1 Clear or Partly cloudy \n",
"2 Clear or Partly cloudy \n",
"3 Clear or Partly cloudy \n",
"4 Clear or Partly cloudy "
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"### TODO rename the relative temperature column to RTemp, and the relative humidity to Humidity\n",
"#weather.columns = ['Hour', 'Temperature', 'Relative Temperature', 'Rel. Humidity', 'Wind', 'Weather']\n",
"weather.columns = ['Hour', 'Temperature', 'RTemp', 'Humidity', 'Wind', 'Weather']\n",
"weather.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 2.1.3 Series\n",
"\n",
"cuDF DataFrames are composed of rows and columns. Each column is represented using an object of type `Series`. For example, if we subset a cuDF DataFrame using just one column we will be returned an object of type `cudf.dataframe.series.Series`."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"0 81\n",
"1 80\n",
"2 80\n",
"3 75\n",
"4 75\n",
" ..\n",
"17374 60\n",
"17375 60\n",
"17376 60\n",
"17377 56\n",
"17378 65\n",
"Name: Humidity, Length: 17379, dtype: int64\n"
]
}
],
"source": [
"humidity = weather['Humidity']\n",
"print(type(humidity))\n",
"print(humidity)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We also see a column of values on the left hand side with values 0, 1, 2, 3. These values represent the index of the Series.\n",
"The DataFrame and Series objects have both an index attribute that will be useful for joining tables and also for selecting data."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 2.1.4 Data Types\n",
"\n",
"We can also inspect the data types of the columns of a cuDF DataFrame using the `dtypes` attribute."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Hour object\n",
"Temperature float64\n",
"RTemp float64\n",
"Humidity int64\n",
"Wind float64\n",
"Weather object\n",
"dtype: object\n"
]
}
],
"source": [
"print(weather.dtypes)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can modify the data types of the columns of a cuDF DataFrame by passing in a cuDF Series with a modified data type."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Hour object\n",
"Temperature float64\n",
"RTemp float64\n",
"Humidity float64\n",
"Wind float64\n",
"Weather object\n",
"dtype: object\n"
]
}
],
"source": [
"weather['Humidity'] = weather['Humidity'].astype(np.float64)\n",
"print(weather.dtypes)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The 'Weather' column provides a description of the weather condidions. We should mark it as a categorical column."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0 Clear or Partly cloudy\n",
"1 Clear or Partly cloudy\n",
"2 Clear or Partly cloudy\n",
"3 Clear or Partly cloudy\n",
"4 Clear or Partly cloudy\n",
" ... \n",
"17374 Mist or Cloudy\n",
"17375 Mist or Cloudy\n",
"17376 Clear or Partly cloudy\n",
"17377 Clear or Partly cloudy\n",
"17378 Clear or Partly cloudy\n",
"Name: Weather, Length: 17379, dtype: category\n",
"Categories (4, object): ['Clear or Partly cloudy', 'Heavy Rain, Snow + Fog, Ice', 'Light Rain or Snow, Thunderstorm', 'Mist or Cloudy']"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"weather['Weather'] = weather['Weather'].astype('category')\n",
"weather['Weather']"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"After this step the numerical category codes can be accessed using the `.cat.codes` attribute of the column. We actually will not need the category labels, we just replace the 'Weather' column with the category codes."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"weather['Weather'] = weather['Weather'].cat.codes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The data type of the 'Hour' column is `object` which means a string. Let's convert this to a numeric value! This cannot be done with the `astype` method, you should use the [cudf.to_datetime](https://docs.rapids.ai/api/cudf/nightly/api.html#cudf.to_datetime) function!"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Hour datetime64[ns]\n",
"Temperature float64\n",
"RTemp float64\n",
"Humidity float64\n",
"Wind float64\n",
"Weather uint8\n",
"dtype: object"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"### TODO convert the 'Hour' column from string to datetime\n",
"weather['Hour'] = cudf.to_datetime(weather['Hour'])\n",
"weather.dtypes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 2.1.2 Prepare features\n",
"##### Operations with cudf Series\n",
"We can perform mathematical operations on the Series data type. We will scale the Humidity and and Temperature variables, so that they lay in the [0, 1] range (some ML algorithms work better if the input data is scaled this way)."
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"weather['Humidity'] = weather['Humidity'] / 100.0"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We will scale the temperature using the following formula T = (T - Tmin) / (Tmax - Tmin). First we select the min and max values."
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"-7.06 39.0\n"
]
}
],
"source": [
"T = weather['Temperature']\n",
"\n",
"# Select the minimum temperature\n",
"Tmin = T.min()\n",
"\n",
"### TODO select the maximum temperature (1 line of code)\n",
"Tmax = T.max()\n",
"\n",
"print(Tmin, Tmax)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We could simply use the Tmin and Tmax values and apply the above formula on the series. \n",
"\n",
"##### User defined functions (UDF)\n",
"We can write custom functions to operate on the data. When cuDF executes a UDF, it gets just-in-time (JIT) compiled into a CUDA kernel (either explicitly or implicitly) and is run on the GPU. Let's write a function that scales the temperature!"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"def scale_temp(T):\n",
" # Note that the Tmin and Tmax variables are stored during compilation time and remain constant afterwards\n",
" T = (T - Tmin) / (Tmax - Tmin)\n",
" return T "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The applymap function will call scale_temp on all element of the series"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"weather['Temperature'] = weather['Temperature'].applymap(scale_temp)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lets do the same min-max scaling for the wind data"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0.0 56.996900000000004\n"
]
}
],
"source": [
"### TODO calculate the minimum and maximum values of the 'Wind' column (2 lines of code)\n",
"Wmin = weather['Wind'].min()\n",
"Wmax = weather['Wind'].max()\n",
"\n",
"print(Wmin, Wmax)\n",
"\n",
"### TODO define a scale_wind function and apply it on the Wind column (~ 2-3 lines of code)\n",
"def scale_wind(w):\n",
" return (w - Wmin) / ( Wmax - Wmin)\n",
"\n",
"### TODO apply the scale_wind function on the 'Wind' column\n",
"weather['Wind'] = weather['Wind'].applymap(scale_wind)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's inspect the table, the Temperature, Wind and Humidity columns should have values in the [0, 1] range."
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Temperature
\n",
"
RTemp
\n",
"
Humidity
\n",
"
Wind
\n",
"
Weather
\n",
"
\n",
" \n",
" \n",
"
\n",
"
count
\n",
"
17379.000000
\n",
"
17379.000000
\n",
"
17379.000000
\n",
"
17379.000000
\n",
"
17379.000000
\n",
"
\n",
"
\n",
"
mean
\n",
"
0.486722
\n",
"
15.401157
\n",
"
0.626947
\n",
"
0.223460
\n",
"
0.947868
\n",
"
\n",
"
\n",
"
std
\n",
"
0.196486
\n",
"
11.342114
\n",
"
0.193013
\n",
"
0.143811
\n",
"
1.334769
\n",
"
\n",
"
\n",
"
min
\n",
"
0.000000
\n",
"
-16.000000
\n",
"
0.000000
\n",
"
0.000000
\n",
"
0.000000
\n",
"
\n",
"
\n",
"
25%
\n",
"
0.326531
\n",
"
5.997800
\n",
"
0.480000
\n",
"
0.122840
\n",
"
0.000000
\n",
"
\n",
"
\n",
"
50%
\n",
"
0.489796
\n",
"
15.996800
\n",
"
0.630000
\n",
"
0.228047
\n",
"
0.000000
\n",
"
\n",
"
\n",
"
75%
\n",
"
0.653061
\n",
"
24.999200
\n",
"
0.780000
\n",
"
0.298225
\n",
"
3.000000
\n",
"
\n",
"
\n",
"
max
\n",
"
1.000000
\n",
"
50.000000
\n",
"
1.000000
\n",
"
1.000000
\n",
"
3.000000
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Temperature RTemp Humidity Wind Weather\n",
"count 17379.000000 17379.000000 17379.000000 17379.000000 17379.000000\n",
"mean 0.486722 15.401157 0.626947 0.223460 0.947868\n",
"std 0.196486 11.342114 0.193013 0.143811 1.334769\n",
"min 0.000000 -16.000000 0.000000 0.000000 0.000000\n",
"25% 0.326531 5.997800 0.480000 0.122840 0.000000\n",
"50% 0.489796 15.996800 0.630000 0.228047 0.000000\n",
"75% 0.653061 24.999200 0.780000 0.298225 3.000000\n",
"max 1.000000 50.000000 1.000000 1.000000 3.000000"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"weather.describe()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### Dropping Columns\n",
"\n",
"The relative temperature column is correlated with the temperature, it will not give much extra information for the ML model. We want to remove this column from our `DataFrame`. We can do so using the `drop_column` method. Note that this method removes a column in-place - meaning that the `DataFrame` we act on will be modified."
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Hour
\n",
"
Temperature
\n",
"
Humidity
\n",
"
Wind
\n",
"
Weather
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2011-01-01 00:00:00
\n",
"
0.224490
\n",
"
0.81
\n",
"
0.000000
\n",
"
0
\n",
"
\n",
"
\n",
"
1
\n",
"
2011-01-01 01:00:00
\n",
"
0.204082
\n",
"
0.80
\n",
"
0.000000
\n",
"
0
\n",
"
\n",
"
\n",
"
2
\n",
"
2011-01-01 02:00:00
\n",
"
0.204082
\n",
"
0.80
\n",
"
0.000000
\n",
"
0
\n",
"
\n",
"
\n",
"
3
\n",
"
2011-01-01 03:00:00
\n",
"
0.224490
\n",
"
0.75
\n",
"
0.000000
\n",
"
0
\n",
"
\n",
"
\n",
"
4
\n",
"
2011-01-01 04:00:00
\n",
"
0.224490
\n",
"
0.75
\n",
"
0.000000
\n",
"
0
\n",
"
\n",
"
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
\n",
"
\n",
"
17374
\n",
"
2012-12-31 19:00:00
\n",
"
0.244898
\n",
"
0.60
\n",
"
0.193018
\n",
"
3
\n",
"
\n",
"
\n",
"
17375
\n",
"
2012-12-31 20:00:00
\n",
"
0.244898
\n",
"
0.60
\n",
"
0.193018
\n",
"
3
\n",
"
\n",
"
\n",
"
17376
\n",
"
2012-12-31 21:00:00
\n",
"
0.244898
\n",
"
0.60
\n",
"
0.193018
\n",
"
0
\n",
"
\n",
"
\n",
"
17377
\n",
"
2012-12-31 22:00:00
\n",
"
0.244898
\n",
"
0.56
\n",
"
0.157870
\n",
"
0
\n",
"
\n",
"
\n",
"
17378
\n",
"
2012-12-31 23:00:00
\n",
"
0.244898
\n",
"
0.65
\n",
"
0.157870
\n",
"
0
\n",
"
\n",
" \n",
"
\n",
"
17379 rows × 5 columns
\n",
"
"
],
"text/plain": [
" Hour Temperature Humidity Wind Weather\n",
"0 2011-01-01 00:00:00 0.224490 0.81 0.000000 0\n",
"1 2011-01-01 01:00:00 0.204082 0.80 0.000000 0\n",
"2 2011-01-01 02:00:00 0.204082 0.80 0.000000 0\n",
"3 2011-01-01 03:00:00 0.224490 0.75 0.000000 0\n",
"4 2011-01-01 04:00:00 0.224490 0.75 0.000000 0\n",
"... ... ... ... ... ...\n",
"17374 2012-12-31 19:00:00 0.244898 0.60 0.193018 3\n",
"17375 2012-12-31 20:00:00 0.244898 0.60 0.193018 3\n",
"17376 2012-12-31 21:00:00 0.244898 0.60 0.193018 0\n",
"17377 2012-12-31 22:00:00 0.244898 0.56 0.157870 0\n",
"17378 2012-12-31 23:00:00 0.244898 0.65 0.157870 0\n",
"\n",
"[17379 rows x 5 columns]"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"weather.drop(['RTemp'],axis=1,inplace=True)\n",
"weather"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we want to remove a column without modifying the original DataFrame, we can use the `drop` method. This method will return a new DataFrame without that column (or columns)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### Index\n",
"\n",
"Like `Series` objects, each `DataFrame` has an index attribute."
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"RangeIndex(start=0, stop=17379)"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"weather.index"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can use the index values to subset the `DataFrame`. Lets use this to plot the first 48 values. Before plotting we have to transfer from the GPU memory to the system memory. We use the `to_array` method to return a copy of the data as a numpy array."
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Text(0, 0.5, 'Temperature [C]')"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"
"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"selection = weather[weather.index<48]\n",
"plt.plot(selection['Hour'].to_array(), selection['Temperature'].to_array())\n",
"plt.xlabel('Hour')\n",
"plt.ylabel('Temperature [C]')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can also change the index. Our dataset has one entry for each hour, so one could set the 'Hour' coulmn as index by calling\n",
"```\n",
"weather = weather.set_index('Hour')\n",
"```\n",
"\n",
"We do not perform this change right now, but we will use it later."
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"#weather = weather.set_index('Hour')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2.2 Prepare bike sharing data\n",
"We start by downloading the data"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"24744.0kB [00:01, 13625.36kB/s] \n",
"42448.0kB [00:17, 2456.30kB/s] \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Files extracted: ['data/2011-capitalbikeshare-tripdata.csv', 'data/2012Q1-capitalbikeshare-tripdata.csv', 'data/2012Q2-capitalbikeshare-tripdata.csv', 'data/2012Q3-capitalbikeshare-tripdata.csv', 'data/2012Q4-capitalbikeshare-tripdata.csv']\n"
]
}
],
"source": [
"files = fetch_bike_dataset([2011,2012])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's read the first file to have an idea of the dataset"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Duration
\n",
"
Start date
\n",
"
End date
\n",
"
Start station number
\n",
"
Start station
\n",
"
End station number
\n",
"
End station
\n",
"
Bike number
\n",
"
Member type
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
3548
\n",
"
2011-01-01 00:01:29
\n",
"
2011-01-01 01:00:37
\n",
"
31620
\n",
"
5th & F St NW
\n",
"
31620
\n",
"
5th & F St NW
\n",
"
W00247
\n",
"
Member
\n",
"
\n",
"
\n",
"
1
\n",
"
346
\n",
"
2011-01-01 00:02:46
\n",
"
2011-01-01 00:08:32
\n",
"
31105
\n",
"
14th & Harvard St NW
\n",
"
31101
\n",
"
14th & V St NW
\n",
"
W00675
\n",
"
Casual
\n",
"
\n",
"
\n",
"
2
\n",
"
562
\n",
"
2011-01-01 00:06:13
\n",
"
2011-01-01 00:15:36
\n",
"
31400
\n",
"
Georgia & New Hampshire Ave NW
\n",
"
31104
\n",
"
Adams Mill & Columbia Rd NW
\n",
"
W00357
\n",
"
Member
\n",
"
\n",
"
\n",
"
3
\n",
"
434
\n",
"
2011-01-01 00:09:21
\n",
"
2011-01-01 00:16:36
\n",
"
31111
\n",
"
10th & U St NW
\n",
"
31503
\n",
"
Florida Ave & R St NW
\n",
"
W00970
\n",
"
Member
\n",
"
\n",
"
\n",
"
4
\n",
"
233
\n",
"
2011-01-01 00:28:26
\n",
"
2011-01-01 00:32:19
\n",
"
31104
\n",
"
Adams Mill & Columbia Rd NW
\n",
"
31106
\n",
"
Calvert & Biltmore St NW
\n",
"
W00346
\n",
"
Casual
\n",
"
\n",
"
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
\n",
"
\n",
"
1226762
\n",
"
300
\n",
"
2011-12-31 23:41:19
\n",
"
2011-12-31 23:46:20
\n",
"
31201
\n",
"
15th & P St NW
\n",
"
31214
\n",
"
17th & Corcoran St NW
\n",
"
W01459
\n",
"
Member
\n",
"
\n",
"
\n",
"
1226763
\n",
"
387
\n",
"
2011-12-31 23:46:43
\n",
"
2011-12-31 23:53:10
\n",
"
31223
\n",
"
Convention Center / 7th & M St NW
\n",
"
31201
\n",
"
15th & P St NW
\n",
"
W01262
\n",
"
Member
\n",
"
\n",
"
\n",
"
1226764
\n",
"
261
\n",
"
2011-12-31 23:47:27
\n",
"
2011-12-31 23:51:49
\n",
"
31107
\n",
"
Lamont & Mt Pleasant NW
\n",
"
31602
\n",
"
Park Rd & Holmead Pl NW
\n",
"
W00998
\n",
"
Member
\n",
"
\n",
"
\n",
"
1226765
\n",
"
2060
\n",
"
2011-12-31 23:55:12
\n",
"
2012-01-01 00:29:33
\n",
"
31205
\n",
"
21st & I St NW
\n",
"
31222
\n",
"
New York Ave & 15th St NW
\n",
"
W00042
\n",
"
Member
\n",
"
\n",
"
\n",
"
1226766
\n",
"
468
\n",
"
2011-12-31 23:55:56
\n",
"
2012-01-01 00:03:45
\n",
"
31221
\n",
"
18th & M St NW
\n",
"
31111
\n",
"
10th & U St NW
\n",
"
W01319
\n",
"
Member
\n",
"
\n",
" \n",
"
\n",
"
1226767 rows × 9 columns
\n",
"
"
],
"text/plain": [
" Duration Start date End date \\\n",
"0 3548 2011-01-01 00:01:29 2011-01-01 01:00:37 \n",
"1 346 2011-01-01 00:02:46 2011-01-01 00:08:32 \n",
"2 562 2011-01-01 00:06:13 2011-01-01 00:15:36 \n",
"3 434 2011-01-01 00:09:21 2011-01-01 00:16:36 \n",
"4 233 2011-01-01 00:28:26 2011-01-01 00:32:19 \n",
"... ... ... ... \n",
"1226762 300 2011-12-31 23:41:19 2011-12-31 23:46:20 \n",
"1226763 387 2011-12-31 23:46:43 2011-12-31 23:53:10 \n",
"1226764 261 2011-12-31 23:47:27 2011-12-31 23:51:49 \n",
"1226765 2060 2011-12-31 23:55:12 2012-01-01 00:29:33 \n",
"1226766 468 2011-12-31 23:55:56 2012-01-01 00:03:45 \n",
"\n",
" Start station number Start station \\\n",
"0 31620 5th & F St NW \n",
"1 31105 14th & Harvard St NW \n",
"2 31400 Georgia & New Hampshire Ave NW \n",
"3 31111 10th & U St NW \n",
"4 31104 Adams Mill & Columbia Rd NW \n",
"... ... ... \n",
"1226762 31201 15th & P St NW \n",
"1226763 31223 Convention Center / 7th & M St NW \n",
"1226764 31107 Lamont & Mt Pleasant NW \n",
"1226765 31205 21st & I St NW \n",
"1226766 31221 18th & M St NW \n",
"\n",
" End station number End station Bike number \\\n",
"0 31620 5th & F St NW W00247 \n",
"1 31101 14th & V St NW W00675 \n",
"2 31104 Adams Mill & Columbia Rd NW W00357 \n",
"3 31503 Florida Ave & R St NW W00970 \n",
"4 31106 Calvert & Biltmore St NW W00346 \n",
"... ... ... ... \n",
"1226762 31214 17th & Corcoran St NW W01459 \n",
"1226763 31201 15th & P St NW W01262 \n",
"1226764 31602 Park Rd & Holmead Pl NW W00998 \n",
"1226765 31222 New York Ave & 15th St NW W00042 \n",
"1226766 31111 10th & U St NW W01319 \n",
"\n",
" Member type \n",
"0 Member \n",
"1 Casual \n",
"2 Member \n",
"3 Member \n",
"4 Casual \n",
"... ... \n",
"1226762 Member \n",
"1226763 Member \n",
"1226764 Member \n",
"1226765 Member \n",
"1226766 Member \n",
"\n",
"[1226767 rows x 9 columns]"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"cudf.read_csv(files[0])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We are only interested in the events when a bicicle was rented. Let us read the first column from all files, by specifying the `usecols` argument to [read_csv](https://docs.rapids.ai/api/cudf/nightly/api.html#cudf.io.csv.read_csv). We can use the `parse_dates` argument to parse the date string into a datetime variable, or the [to_datetime](https://docs.rapids.ai/api/cudf/nightly/api.html#cudf.to_datetime) function that we have used for the weather dataset. After all the tables are read we will concatenate them.\n",
"\n",
"Note: one has to specify a list of columns [ column1, column2 ] for the `usecol` argument."
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [],
"source": [
"def read_bike_data(files):\n",
" # Reads a list of files and concatenates them\n",
" tables = []\n",
" for filename in files:\n",
" ### TODO read column 1 ('Start date') from the CSV file, and convert it to datetime format\n",
" ### (1-2 lines of code)\n",
" tmp_df = cudf.read_csv(filename, parse_dates=[1], usecols=[1])\n",
" \n",
" ### END TODO\n",
" tables.append(tmp_df) \n",
" \n",
" merged_df = cudf.concat(tables, ignore_index=True)\n",
" \n",
" # Sanity checks\n",
" if merged_df.columns != ['Start date']:\n",
" raise ValueError(\"Error incorrect set of columns read\")\n",
" if merged_df['Start date'].dtype != 'datetime64[ns]':\n",
" raise TypeError(\"Stard date should be converted to datetime type\")\n",
" \n",
" return merged_df"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We will also measure the execution time of reading and processing the data (you can execute the cell multiple times to have a better measurement)."
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: user 91.6 ms, sys: 330 ms, total: 422 ms\n",
"Wall time: 421 ms\n"
]
}
],
"source": [
"%%time\n",
"bikes_raw = read_bike_data(files)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For comparision, we can repeat the same operation on the CPU. We have prepared a helper function for that."
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: user 4.31 s, sys: 192 ms, total: 4.51 s\n",
"Wall time: 4.5 s\n"
]
}
],
"source": [
"%%time\n",
"bikes_raw_pd = read_bike_data_pandas(files)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We want to count the number of rental events in every hour. We will define a new feature where we remove the minutes and seconds part of the time stamp. Since pandas has a convenient `floor` function defined to do it, we will convert the column to a pandas Series, transform it with the floor operation, and then put it back on the GPU."
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [],
"source": [
"bikes_raw['Hour'] = bikes_raw['Start date'].to_pandas().dt.floor('h')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We will aggregate the number of bicicle rental events for each hour. We use the [groupby](https://docs.rapids.ai/api/cudf/nightly/api.html#groupby) function."
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
cnt
\n",
"
\n",
"
\n",
"
Hour
\n",
"
\n",
"
\n",
" \n",
" \n",
"
\n",
"
2011-01-01 00:00:00
\n",
"
16
\n",
"
\n",
"
\n",
"
2011-01-01 01:00:00
\n",
"
38
\n",
"
\n",
"
\n",
"
2011-01-01 02:00:00
\n",
"
31
\n",
"
\n",
"
\n",
"
2011-01-01 03:00:00
\n",
"
12
\n",
"
\n",
"
\n",
"
2011-01-01 04:00:00
\n",
"
1
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" cnt\n",
"Hour \n",
"2011-01-01 00:00:00 16\n",
"2011-01-01 01:00:00 38\n",
"2011-01-01 02:00:00 31\n",
"2011-01-01 03:00:00 12\n",
"2011-01-01 04:00:00 1"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bikes = bikes_raw.groupby('Hour').agg('count')\n",
"bikes.columns = ['cnt']\n",
"bikes.head(5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's add a column to the new dataset: the date without the time of the day. We can derive that similarly to the 'Hour' feature above. After the groupby operation, the 'Hour' became the index of the dataset, we will apply the `floor` operation on the index. "
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [],
"source": [
"bikes['date'] = bikes.index.to_pandas().floor('D')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It will be usefull to define a set of additional features: hour of the day, day of month, month and year https://docs.rapids.ai/api/cudf/nightly/api.html#datetimeindex"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"bikes['hr'] = bikes.index.hour\n",
"\n",
"### TODO add year and month features (~ 2 lines of code)\n",
"bikes['year'] = bikes.index.year\n",
"bikes['month'] = bikes.index.month"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Remove the offset from year"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [],
"source": [
"bikes['year'] = bikes['year'] - 2011"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Visualize data\n",
"It is a good practice to visulize the data. We will have to use the to_array() method to convert the cudF Series objects to numpy arrays that can be plotted."
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[]"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"
"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"plt.plot(bikes.index.to_array(), bikes['cnt'].to_array())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It is hard to see much apart from the global trend. Let's have a look how the 'cnt' variable looks like as a function the 'month' and 'hr' features. We will use [boxplot](https://seaborn.pydata.org/generated/seaborn.boxplot.html) from the Seaborn package."
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"
"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"fig, axes = plt.subplots(nrows=1,ncols=2)\n",
"fig.set_size_inches(12, 5)\n",
"sns.boxplot(data=bikes.to_pandas(), y=\"cnt\",x=\"month\",orient=\"v\",ax=axes[0])\n",
"sns.boxplot(data=bikes.to_pandas(), y=\"cnt\",x=\"hr\",orient=\"v\",ax=axes[1])\n",
"axes[0].set(xlabel='Months', ylabel='Count',title=\"Box Plot On Count Across months\")\n",
"axes[1].set(xlabel='Hour Of The Day', ylabel='Count',title=\"Box Plot On Count Across Hour Of The Day\")\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 3.2.1 Combine weather data with bike rental data"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
"
],
"text/plain": [
" cnt date hr year month Hour Temperature \\\n",
"0 16 2011-01-01 0 0 1 2011-01-01 00:00:00 0.224490 \n",
"1 38 2011-01-01 1 0 1 2011-01-01 01:00:00 0.204082 \n",
"2 31 2011-01-01 2 0 1 2011-01-01 02:00:00 0.204082 \n",
"3 12 2011-01-01 3 0 1 2011-01-01 03:00:00 0.224490 \n",
"4 1 2011-01-01 4 0 1 2011-01-01 04:00:00 0.224490 \n",
"... ... ... .. ... ... ... ... \n",
"17374 118 2012-12-31 19 1 12 2012-12-31 19:00:00 0.244898 \n",
"17375 89 2012-12-31 20 1 12 2012-12-31 20:00:00 0.244898 \n",
"17376 90 2012-12-31 21 1 12 2012-12-31 21:00:00 0.244898 \n",
"17377 61 2012-12-31 22 1 12 2012-12-31 22:00:00 0.244898 \n",
"17378 50 2012-12-31 23 1 12 2012-12-31 23:00:00 0.244898 \n",
"\n",
" Humidity Wind Weather \n",
"0 0.81 0.000000 0 \n",
"1 0.80 0.000000 0 \n",
"2 0.80 0.000000 0 \n",
"3 0.75 0.000000 0 \n",
"4 0.75 0.000000 0 \n",
"... ... ... ... \n",
"17374 0.60 0.193018 3 \n",
"17375 0.60 0.193018 3 \n",
"17376 0.60 0.193018 0 \n",
"17377 0.56 0.157870 0 \n",
"17378 0.65 0.157870 0 \n",
"\n",
"[17378 rows x 10 columns]"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"### TODO sort the table according to the index (1 line of code)\n",
"gdf_bw = gdf_bw.sort_values(by='Hour')\n",
"\n",
"# Inspect the sorted table\n",
"gdf_bw"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 3.3 Add working day feature\n",
"\n",
"Apart from the weather, in important factor that influences people's daily activities is whether it is a working day or not. In this section we will create a working day feature. First we add the weekday as a new feature column. \n",
"We can use the [weekday](https://docs.rapids.ai/api/cudf/nightly/api.html#cudf.core.series.DatetimeProperties.weekday) attribute of the [datetime](https://docs.rapids.ai/api/cudf/nightly/api.html#datetimeindex)"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [],
"source": [
"gdf_bw['Weekday'] = gdf_bw['date'].dt.weekday"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next create a table with all the holidays in Washington DC in 2011-2011"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
date
\n",
"
Description
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2011-01-17
\n",
"
Martin Luther King Jr. Day
\n",
"
\n",
"
\n",
"
1
\n",
"
2011-02-21
\n",
"
Washington's Birthday
\n",
"
\n",
"
\n",
"
2
\n",
"
2011-04-15
\n",
"
Emancipation Day
\n",
"
\n",
"
\n",
"
3
\n",
"
2011-05-30
\n",
"
Memorial Day
\n",
"
\n",
"
\n",
"
4
\n",
"
2011-07-04
\n",
"
Independence Day
\n",
"
\n",
"
\n",
"
5
\n",
"
2011-09-05
\n",
"
Labor Day
\n",
"
\n",
"
\n",
"
6
\n",
"
2011-11-11
\n",
"
Veterans Day
\n",
"
\n",
"
\n",
"
7
\n",
"
2011-11-24
\n",
"
Thanksgiving
\n",
"
\n",
"
\n",
"
8
\n",
"
2011-12-26
\n",
"
Christmas Day
\n",
"
\n",
"
\n",
"
9
\n",
"
2012-01-02
\n",
"
New Year's Day
\n",
"
\n",
"
\n",
"
10
\n",
"
2012-01-16
\n",
"
Martin Luther King Jr. Day
\n",
"
\n",
"
\n",
"
11
\n",
"
2012-02-20
\n",
"
Washington's Birthday
\n",
"
\n",
"
\n",
"
12
\n",
"
2012-04-16
\n",
"
Emancipation Day
\n",
"
\n",
"
\n",
"
13
\n",
"
2012-05-28
\n",
"
Memorial Day
\n",
"
\n",
"
\n",
"
14
\n",
"
2012-07-04
\n",
"
Independence Day
\n",
"
\n",
"
\n",
"
15
\n",
"
2012-09-03
\n",
"
Labor Day
\n",
"
\n",
"
\n",
"
16
\n",
"
2012-11-12
\n",
"
Veterans Day
\n",
"
\n",
"
\n",
"
17
\n",
"
2012-11-22
\n",
"
Thanksgiving
\n",
"
\n",
"
\n",
"
18
\n",
"
2012-12-25
\n",
"
Christmas Day
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" date Description\n",
"0 2011-01-17 Martin Luther King Jr. Day\n",
"1 2011-02-21 Washington's Birthday\n",
"2 2011-04-15 Emancipation Day\n",
"3 2011-05-30 Memorial Day\n",
"4 2011-07-04 Independence Day\n",
"5 2011-09-05 Labor Day\n",
"6 2011-11-11 Veterans Day\n",
"7 2011-11-24 Thanksgiving\n",
"8 2011-12-26 Christmas Day\n",
"9 2012-01-02 New Year's Day\n",
"10 2012-01-16 Martin Luther King Jr. Day\n",
"11 2012-02-20 Washington's Birthday\n",
"12 2012-04-16 Emancipation Day\n",
"13 2012-05-28 Memorial Day\n",
"14 2012-07-04 Independence Day\n",
"15 2012-09-03 Labor Day\n",
"16 2012-11-12 Veterans Day\n",
"17 2012-11-22 Thanksgiving\n",
"18 2012-12-25 Christmas Day"
]
},
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"holidays = cudf.DataFrame({'date': ['2011-01-17', '2011-02-21', '2011-04-15', '2011-05-30', '2011-07-04', '2011-09-05', '2011-11-11', '2011-11-24', '2011-12-26', '2012-01-02', '2012-01-16', '2012-02-20', '2012-04-16', '2012-05-28', '2012-07-04', '2012-09-03', '2012-11-12', '2012-11-22', '2012-12-25'],\n",
"'Description': [\"Martin Luther King Jr. Day\", \"Washington's Birthday\", \"Emancipation Day\", \"Memorial Day\", \"Independence Day\", \"Labor Day\", \"Veterans Day\", \"Thanksgiving\", \"Christmas Day\", \n",
"\"New Year's Day\", \"Martin Luther King Jr. Day\", \"Washington's Birthday\", \"Emancipation Day\", \"Memorial Day\", \"Independence Day\", \"Labor Day\", \"Veterans Day\", \"Thanksgiving\", \"Christmas Day\"]})\n",
"\n",
"# Print the dataframe\n",
"holidays"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We convert the date from string to datetime type, and drop the description column. Additionally we add a new column marked 'Holiday'. This will be useful to mark the holidays after we merge the tables."
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
date
\n",
"
Holiday
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2011-01-17
\n",
"
1
\n",
"
\n",
"
\n",
"
1
\n",
"
2011-02-21
\n",
"
1
\n",
"
\n",
"
\n",
"
2
\n",
"
2011-04-15
\n",
"
1
\n",
"
\n",
"
\n",
"
3
\n",
"
2011-05-30
\n",
"
1
\n",
"
\n",
"
\n",
"
4
\n",
"
2011-07-04
\n",
"
1
\n",
"
\n",
"
\n",
"
5
\n",
"
2011-09-05
\n",
"
1
\n",
"
\n",
"
\n",
"
6
\n",
"
2011-11-11
\n",
"
1
\n",
"
\n",
"
\n",
"
7
\n",
"
2011-11-24
\n",
"
1
\n",
"
\n",
"
\n",
"
8
\n",
"
2011-12-26
\n",
"
1
\n",
"
\n",
"
\n",
"
9
\n",
"
2012-01-02
\n",
"
1
\n",
"
\n",
"
\n",
"
10
\n",
"
2012-01-16
\n",
"
1
\n",
"
\n",
"
\n",
"
11
\n",
"
2012-02-20
\n",
"
1
\n",
"
\n",
"
\n",
"
12
\n",
"
2012-04-16
\n",
"
1
\n",
"
\n",
"
\n",
"
13
\n",
"
2012-05-28
\n",
"
1
\n",
"
\n",
"
\n",
"
14
\n",
"
2012-07-04
\n",
"
1
\n",
"
\n",
"
\n",
"
15
\n",
"
2012-09-03
\n",
"
1
\n",
"
\n",
"
\n",
"
16
\n",
"
2012-11-12
\n",
"
1
\n",
"
\n",
"
\n",
"
17
\n",
"
2012-11-22
\n",
"
1
\n",
"
\n",
"
\n",
"
18
\n",
"
2012-12-25
\n",
"
1
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" date Holiday\n",
"0 2011-01-17 1\n",
"1 2011-02-21 1\n",
"2 2011-04-15 1\n",
"3 2011-05-30 1\n",
"4 2011-07-04 1\n",
"5 2011-09-05 1\n",
"6 2011-11-11 1\n",
"7 2011-11-24 1\n",
"8 2011-12-26 1\n",
"9 2012-01-02 1\n",
"10 2012-01-16 1\n",
"11 2012-02-20 1\n",
"12 2012-04-16 1\n",
"13 2012-05-28 1\n",
"14 2012-07-04 1\n",
"15 2012-09-03 1\n",
"16 2012-11-12 1\n",
"17 2012-11-22 1\n",
"18 2012-12-25 1"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"holidays['date'] = cudf.to_datetime(holidays['date'])\n",
"holidays.drop(['Description'],axis=1,inplace=True)\n",
"holidays['Holiday'] = 1\n",
"holidays"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we are ready to merge the tables using the commond `date` column. We want keep every element from the gdf_bw table (our *left* table), so we use a left join. Hint: use [merge](https://docs.rapids.ai/api/cudf/nightly/api.html#cudf.core.dataframe.DataFrame.merge) with the `on` and `how` attributes"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
cnt
\n",
"
date
\n",
"
hr
\n",
"
year
\n",
"
month
\n",
"
Hour
\n",
"
Temperature
\n",
"
Humidity
\n",
"
Wind
\n",
"
Weather
\n",
"
Weekday
\n",
"
Holiday
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
297
\n",
"
2011-12-03
\n",
"
16
\n",
"
0
\n",
"
12
\n",
"
2011-12-03 16:00:00
\n",
"
0.367347
\n",
"
0.46
\n",
"
0.000000
\n",
"
0
\n",
"
5
\n",
"
<NA>
\n",
"
\n",
"
\n",
"
1
\n",
"
229
\n",
"
2011-12-03
\n",
"
17
\n",
"
0
\n",
"
12
\n",
"
2011-12-03 17:00:00
\n",
"
0.346939
\n",
"
0.62
\n",
"
0.000000
\n",
"
0
\n",
"
5
\n",
"
<NA>
\n",
"
\n",
"
\n",
"
2
\n",
"
220
\n",
"
2011-12-03
\n",
"
18
\n",
"
0
\n",
"
12
\n",
"
2011-12-03 18:00:00
\n",
"
0.326531
\n",
"
0.53
\n",
"
0.157870
\n",
"
0
\n",
"
5
\n",
"
<NA>
\n",
"
\n",
"
\n",
"
3
\n",
"
174
\n",
"
2011-12-03
\n",
"
19
\n",
"
0
\n",
"
12
\n",
"
2011-12-03 19:00:00
\n",
"
0.285714
\n",
"
0.61
\n",
"
0.105325
\n",
"
0
\n",
"
5
\n",
"
<NA>
\n",
"
\n",
"
\n",
"
4
\n",
"
124
\n",
"
2011-12-03
\n",
"
20
\n",
"
0
\n",
"
12
\n",
"
2011-12-03 20:00:00
\n",
"
0.285714
\n",
"
0.61
\n",
"
0.105325
\n",
"
0
\n",
"
5
\n",
"
<NA>
\n",
"
\n",
"
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
\n",
"
\n",
"
17373
\n",
"
15
\n",
"
2011-12-25
\n",
"
19
\n",
"
0
\n",
"
12
\n",
"
2011-12-25 19:00:00
\n",
"
0.306122
\n",
"
0.56
\n",
"
0.157870
\n",
"
0
\n",
"
6
\n",
"
<NA>
\n",
"
\n",
"
\n",
"
17374
\n",
"
25
\n",
"
2011-12-25
\n",
"
20
\n",
"
0
\n",
"
12
\n",
"
2011-12-25 20:00:00
\n",
"
0.306122
\n",
"
0.49
\n",
"
0.105325
\n",
"
0
\n",
"
6
\n",
"
<NA>
\n",
"
\n",
"
\n",
"
17375
\n",
"
18
\n",
"
2011-12-25
\n",
"
21
\n",
"
0
\n",
"
12
\n",
"
2011-12-25 21:00:00
\n",
"
0.285714
\n",
"
0.56
\n",
"
0.157870
\n",
"
0
\n",
"
6
\n",
"
<NA>
\n",
"
\n",
"
\n",
"
17376
\n",
"
17
\n",
"
2011-12-25
\n",
"
22
\n",
"
0
\n",
"
12
\n",
"
2011-12-25 22:00:00
\n",
"
0.265306
\n",
"
0.61
\n",
"
0.193018
\n",
"
0
\n",
"
6
\n",
"
<NA>
\n",
"
\n",
"
\n",
"
17377
\n",
"
16
\n",
"
2011-12-25
\n",
"
23
\n",
"
0
\n",
"
12
\n",
"
2011-12-25 23:00:00
\n",
"
0.244898
\n",
"
0.65
\n",
"
0.157870
\n",
"
0
\n",
"
6
\n",
"
<NA>
\n",
"
\n",
" \n",
"
\n",
"
17378 rows × 12 columns
\n",
"
"
],
"text/plain": [
" cnt date hr year month Hour Temperature \\\n",
"0 297 2011-12-03 16 0 12 2011-12-03 16:00:00 0.367347 \n",
"1 229 2011-12-03 17 0 12 2011-12-03 17:00:00 0.346939 \n",
"2 220 2011-12-03 18 0 12 2011-12-03 18:00:00 0.326531 \n",
"3 174 2011-12-03 19 0 12 2011-12-03 19:00:00 0.285714 \n",
"4 124 2011-12-03 20 0 12 2011-12-03 20:00:00 0.285714 \n",
"... ... ... .. ... ... ... ... \n",
"17373 15 2011-12-25 19 0 12 2011-12-25 19:00:00 0.306122 \n",
"17374 25 2011-12-25 20 0 12 2011-12-25 20:00:00 0.306122 \n",
"17375 18 2011-12-25 21 0 12 2011-12-25 21:00:00 0.285714 \n",
"17376 17 2011-12-25 22 0 12 2011-12-25 22:00:00 0.265306 \n",
"17377 16 2011-12-25 23 0 12 2011-12-25 23:00:00 0.244898 \n",
"\n",
" Humidity Wind Weather Weekday Holiday \n",
"0 0.46 0.000000 0 5 \n",
"1 0.62 0.000000 0 5 \n",
"2 0.53 0.157870 0 5 \n",
"3 0.61 0.105325 0 5 \n",
"4 0.61 0.105325 0 5 \n",
"... ... ... ... ... ... \n",
"17373 0.56 0.157870 0 6 \n",
"17374 0.49 0.105325 0 6 \n",
"17375 0.56 0.157870 0 6 \n",
"17376 0.61 0.193018 0 6 \n",
"17377 0.65 0.157870 0 6 \n",
"\n",
"[17378 rows x 12 columns]"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"### TODO merge tables and on the column 'date', use a left merge \n",
"gdf = gdf_bw.merge(holidays, on='date', how='left')\n",
"\n",
"# inspect the result\n",
"gdf"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We reset the index to 'Hour' and sort the table accordingly. Notice that most of the rows in the 'Holiday' column are filled with ``, only the dates that appeared in the holiday table are filled with 1. We shall fill the empty fields with zero."
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
cnt
\n",
"
date
\n",
"
hr
\n",
"
year
\n",
"
month
\n",
"
Temperature
\n",
"
Humidity
\n",
"
Wind
\n",
"
Weather
\n",
"
Weekday
\n",
"
Holiday
\n",
"
\n",
"
\n",
"
Hour
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
" \n",
" \n",
"
\n",
"
2011-01-01 00:00:00
\n",
"
16
\n",
"
2011-01-01
\n",
"
0
\n",
"
0
\n",
"
1
\n",
"
0.224490
\n",
"
0.81
\n",
"
0.000000
\n",
"
0
\n",
"
5
\n",
"
0
\n",
"
\n",
"
\n",
"
2011-01-01 01:00:00
\n",
"
38
\n",
"
2011-01-01
\n",
"
1
\n",
"
0
\n",
"
1
\n",
"
0.204082
\n",
"
0.80
\n",
"
0.000000
\n",
"
0
\n",
"
5
\n",
"
0
\n",
"
\n",
"
\n",
"
2011-01-01 02:00:00
\n",
"
31
\n",
"
2011-01-01
\n",
"
2
\n",
"
0
\n",
"
1
\n",
"
0.204082
\n",
"
0.80
\n",
"
0.000000
\n",
"
0
\n",
"
5
\n",
"
0
\n",
"
\n",
"
\n",
"
2011-01-01 03:00:00
\n",
"
12
\n",
"
2011-01-01
\n",
"
3
\n",
"
0
\n",
"
1
\n",
"
0.224490
\n",
"
0.75
\n",
"
0.000000
\n",
"
0
\n",
"
5
\n",
"
0
\n",
"
\n",
"
\n",
"
2011-01-01 04:00:00
\n",
"
1
\n",
"
2011-01-01
\n",
"
4
\n",
"
0
\n",
"
1
\n",
"
0.224490
\n",
"
0.75
\n",
"
0.000000
\n",
"
0
\n",
"
5
\n",
"
0
\n",
"
\n",
"
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
\n",
"
\n",
"
2012-12-31 19:00:00
\n",
"
118
\n",
"
2012-12-31
\n",
"
19
\n",
"
1
\n",
"
12
\n",
"
0.244898
\n",
"
0.60
\n",
"
0.193018
\n",
"
3
\n",
"
0
\n",
"
0
\n",
"
\n",
"
\n",
"
2012-12-31 20:00:00
\n",
"
89
\n",
"
2012-12-31
\n",
"
20
\n",
"
1
\n",
"
12
\n",
"
0.244898
\n",
"
0.60
\n",
"
0.193018
\n",
"
3
\n",
"
0
\n",
"
0
\n",
"
\n",
"
\n",
"
2012-12-31 21:00:00
\n",
"
90
\n",
"
2012-12-31
\n",
"
21
\n",
"
1
\n",
"
12
\n",
"
0.244898
\n",
"
0.60
\n",
"
0.193018
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
\n",
"
\n",
"
2012-12-31 22:00:00
\n",
"
61
\n",
"
2012-12-31
\n",
"
22
\n",
"
1
\n",
"
12
\n",
"
0.244898
\n",
"
0.56
\n",
"
0.157870
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
\n",
"
\n",
"
2012-12-31 23:00:00
\n",
"
50
\n",
"
2012-12-31
\n",
"
23
\n",
"
1
\n",
"
12
\n",
"
0.244898
\n",
"
0.65
\n",
"
0.157870
\n",
"
0
\n",
"
0
\n",
"
0
\n",
"
\n",
" \n",
"
\n",
"
17378 rows × 11 columns
\n",
"
"
],
"text/plain": [
" cnt date hr year month Temperature Humidity \\\n",
"Hour \n",
"2011-01-01 00:00:00 16 2011-01-01 0 0 1 0.224490 0.81 \n",
"2011-01-01 01:00:00 38 2011-01-01 1 0 1 0.204082 0.80 \n",
"2011-01-01 02:00:00 31 2011-01-01 2 0 1 0.204082 0.80 \n",
"2011-01-01 03:00:00 12 2011-01-01 3 0 1 0.224490 0.75 \n",
"2011-01-01 04:00:00 1 2011-01-01 4 0 1 0.224490 0.75 \n",
"... ... ... .. ... ... ... ... \n",
"2012-12-31 19:00:00 118 2012-12-31 19 1 12 0.244898 0.60 \n",
"2012-12-31 20:00:00 89 2012-12-31 20 1 12 0.244898 0.60 \n",
"2012-12-31 21:00:00 90 2012-12-31 21 1 12 0.244898 0.60 \n",
"2012-12-31 22:00:00 61 2012-12-31 22 1 12 0.244898 0.56 \n",
"2012-12-31 23:00:00 50 2012-12-31 23 1 12 0.244898 0.65 \n",
"\n",
" Wind Weather Weekday Holiday \n",
"Hour \n",
"2011-01-01 00:00:00 0.000000 0 5 0 \n",
"2011-01-01 01:00:00 0.000000 0 5 0 \n",
"2011-01-01 02:00:00 0.000000 0 5 0 \n",
"2011-01-01 03:00:00 0.000000 0 5 0 \n",
"2011-01-01 04:00:00 0.000000 0 5 0 \n",
"... ... ... ... ... \n",
"2012-12-31 19:00:00 0.193018 3 0 0 \n",
"2012-12-31 20:00:00 0.193018 3 0 0 \n",
"2012-12-31 21:00:00 0.193018 0 0 0 \n",
"2012-12-31 22:00:00 0.157870 0 0 0 \n",
"2012-12-31 23:00:00 0.157870 0 0 0 \n",
"\n",
"[17378 rows x 11 columns]"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"gdf = gdf.set_index('Hour')\n",
"gdf = gdf.sort_index()\n",
"\n",
"### TODO fill empty holiday values with zero\n",
"gdf['Holiday'] = gdf['Holiday'].fillna(0)\n",
"gdf"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we create a workingday feature. Assuming that the first five days of the week are working days, one could do that simply with the following operation:\n",
"```\n",
"gdf['Workingday'] = (gdf['Weekday'] < 5) & (gdf['Holiday']!=1)\n",
"```\n",
"But we could do it with user defined functions too. Previously we have only used UDF to process elements of a series. Now we will process rows of a dataframe and\n",
"combine the 'Weekday' and 'Holiday' columns to calculate the new feature 'Workingday'.\n",
"\n",
"More on user defined functions in our [blog](https://medium.com/rapids-ai/user-defined-functions-in-rapids-cudf-2d7c3fc2728d) and in the [documentation](https://docs.rapids.ai/api/cudf/nightly/guide-to-udfs.html)."
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [],
"source": [
"def workday_kernel(Weekday, Holiday, Workingday):\n",
" for i, (w, h) in enumerate(zip(Weekday, Holiday)):\n",
" # variable w will take values from the Weekday column\n",
" # variable h will take values from the Holiday column\n",
" Workingday[i] = w < 5 and h != 1"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {},
"outputs": [],
"source": [
"gdf = gdf.apply_rows(workday_kernel, incols=['Weekday', 'Holiday'], outcols=dict(Workingday=np.float64), kwargs=dict())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"After this step we will not need the 'Holiday' and 'date' columns, we can drop them"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {},
"outputs": [],
"source": [
"gdf = gdf.drop(['Holiday', 'date'],axis=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2.4 One-hot encoding\n",
"\n",
"We have all now the data in a single table, but we still want to change their encoding. We're going to create one-hot encoded variables, also known as dummy variables, for each of the time variables as well as the weather situation.\n",
"\n",
"\n",
"A summary from https://machinelearningmastery.com/why-one-hot-encode-data-in-machine-learning/:\n",
"\n",
"\"The integer values have a natural ordered relationship between each other and machine learning algorithms may be able to understand and harness this relationship.\n",
"For categorical variables where no such ordinal relationship exists, the integer encoding is not enough.\n",
"\n",
"In fact, using this encoding and allowing the model to assume a natural ordering between categories may result in poor performance or unexpected results (predictions halfway between categories).\n",
"\n",
"In this case, a one-hot encoding can be applied to the integer representation. This is where the integer encoded variable is removed and a new binary variable is added for each unique integer value.\n",
"\"\n",
"\n",
"We start by one-hot encoding the 'Weather' column using the [one_hot_encoding](https://docs.rapids.ai/api/cudf/nightly/api.html#cudf.core.dataframe.DataFrame.one_hot_encoding) method from cuDF DataFrame. This is very the [get_dummies](https://docs.rapids.ai/api/cudf/nightly/api.html#cudf.core.reshape.get_dummies) function (which might be more familiar for Pandas users), but one_hot_encoding works on a single input column and performs the operation in place. "
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
cnt
\n",
"
hr
\n",
"
year
\n",
"
month
\n",
"
Temperature
\n",
"
Humidity
\n",
"
Wind
\n",
"
Weather
\n",
"
Weekday
\n",
"
Workingday
\n",
"
Weather_dummy_0
\n",
"
Weather_dummy_1
\n",
"
Weather_dummy_2
\n",
"
Weather_dummy_3
\n",
"
\n",
"
\n",
"
Hour
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
"
\n",
" \n",
" \n",
"
\n",
"
2011-01-01 00:00:00
\n",
"
16
\n",
"
0
\n",
"
0
\n",
"
1
\n",
"
0.224490
\n",
"
0.81
\n",
"
0.0
\n",
"
0
\n",
"
5
\n",
"
0.0
\n",
"
1.0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.0
\n",
"
\n",
"
\n",
"
2011-01-01 01:00:00
\n",
"
38
\n",
"
1
\n",
"
0
\n",
"
1
\n",
"
0.204082
\n",
"
0.80
\n",
"
0.0
\n",
"
0
\n",
"
5
\n",
"
0.0
\n",
"
1.0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.0
\n",
"
\n",
"
\n",
"
2011-01-01 02:00:00
\n",
"
31
\n",
"
2
\n",
"
0
\n",
"
1
\n",
"
0.204082
\n",
"
0.80
\n",
"
0.0
\n",
"
0
\n",
"
5
\n",
"
0.0
\n",
"
1.0
\n",
"
0.0
\n",
"
0.0
\n",
"
0.0
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" cnt hr year month Temperature Humidity Wind \\\n",
"Hour \n",
"2011-01-01 00:00:00 16 0 0 1 0.224490 0.81 0.0 \n",
"2011-01-01 01:00:00 38 1 0 1 0.204082 0.80 0.0 \n",
"2011-01-01 02:00:00 31 2 0 1 0.204082 0.80 0.0 \n",
"\n",
" Weather Weekday Workingday Weather_dummy_0 \\\n",
"Hour \n",
"2011-01-01 00:00:00 0 5 0.0 1.0 \n",
"2011-01-01 01:00:00 0 5 0.0 1.0 \n",
"2011-01-01 02:00:00 0 5 0.0 1.0 \n",
"\n",
" Weather_dummy_1 Weather_dummy_2 Weather_dummy_3 \n",
"Hour \n",
"2011-01-01 00:00:00 0.0 0.0 0.0 \n",
"2011-01-01 01:00:00 0.0 0.0 0.0 \n",
"2011-01-01 02:00:00 0.0 0.0 0.0 "
]
},
"execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"codes = gdf['Weather'].unique()\n",
"gdf = gdf.one_hot_encoding('Weather', 'Weather_dummy', codes)\n",
"# Inspect the results\n",
"gdf.head(3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We're going to drop the original variable as well as one of the new dummy variables so we don't create colinearity (more about this problem [here](https://towardsdatascience.com/one-hot-encoding-multicollinearity-and-the-dummy-variable-trap-b5840be3c41a))."
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {},
"outputs": [],
"source": [
"gdf = gdf.drop(['Weather', 'Weather_dummy_1'],axis=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We create a copy of the dataset. It will make it easier to start over in case something would go wrong during the next excercise. "
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {},
"outputs": [],
"source": [
"gdf_backup = gdf.copy()"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {},
"outputs": [],
"source": [
"dummies_list = ['month', 'hr', 'Weekday']\n",
"\n",
"gdf = gdf_backup.copy()\n",
"\n",
"for item in dummies_list:\n",
" ### Todo implement one-hot encoding for item\n",
" codes = gdf[item].unique()\n",
" gdf = gdf.one_hot_encoding(item, item + '_dummy', codes)\n",
" gdf = gdf.drop('{}_dummy_1'.format(item),axis=1)\n",
" gdf = gdf.drop(item,axis=1) # drop the original item"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"