{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# This walkthrough shows how to build a model to predict Fare prices"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"# again, import the necessary packages"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import warnings\n",
"warnings.filterwarnings('ignore')\n",
"# these two lines is used to suppress warnings (i.e., keep them from showing up in the results)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"data = pd.read_csv(\"flight_prices.csv\")\n",
"# read the data"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"data[\"Position_flight\"] = data[\"Position\"].str.split(\"|\").str[0].astype(int)\n",
"data[\"Position_fare\"] = data[\"Position\"].str.split(\"|\").str[1].astype(int)\n",
"# with this line I want to create the \"Position_flight\" column by taking the item to the left of the | symbol in the \"Position\" column\n",
"# in the same way I'm creating the \"Position_fare\" column by taking the item to the right of the | symbol"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
DepartureDate
\n",
"
ReturnDate
\n",
"
OutboundDuration
\n",
"
InboundDuration
\n",
"
FlightDeparture
\n",
"
FlightDestination
\n",
"
Fare
\n",
"
Position
\n",
"
\n",
" \n",
" \n",
"
\n",
"
4
\n",
"
2017-09-05 00:00:00 UTC
\n",
"
2017-09-25 00:00:00 UTC
\n",
"
6.50
\n",
"
11.33
\n",
"
AMS
\n",
"
ADB
\n",
"
213.28
\n",
"
26|1
\n",
"
\n",
"
\n",
"
5
\n",
"
2017-08-02 00:00:00 UTC
\n",
"
2017-08-22 00:00:00 UTC
\n",
"
5.58
\n",
"
8.08
\n",
"
AMS
\n",
"
ADB
\n",
"
311.84
\n",
"
4|1
\n",
"
\n",
"
\n",
"
6
\n",
"
2017-07-24 00:00:00 UTC
\n",
"
2017-08-13 00:00:00 UTC
\n",
"
12.08
\n",
"
12.42
\n",
"
AMS
\n",
"
ADB
\n",
"
374.03
\n",
"
11|1
\n",
"
\n",
"
\n",
"
8
\n",
"
2017-07-17 00:00:00 UTC
\n",
"
2017-08-06 00:00:00 UTC
\n",
"
12.08
\n",
"
9.92
\n",
"
AMS
\n",
"
ADB
\n",
"
308.58
\n",
"
7|1
\n",
"
\n",
"
\n",
"
13
\n",
"
2017-07-27 00:00:00 UTC
\n",
"
2017-08-16 00:00:00 UTC
\n",
"
8.33
\n",
"
9.33
\n",
"
AMS
\n",
"
ADB
\n",
"
348.47
\n",
"
4|1
\n",
"
\n",
"
\n",
"
14
\n",
"
2017-07-24 00:00:00 UTC
\n",
"
2017-08-13 00:00:00 UTC
\n",
"
7.33
\n",
"
9.42
\n",
"
AMS
\n",
"
ADB
\n",
"
448.47
\n",
"
24|1
\n",
"
\n",
"
\n",
"
16
\n",
"
2017-06-18 00:00:00 UTC
\n",
"
2017-07-08 00:00:00 UTC
\n",
"
3.50
\n",
"
7.50
\n",
"
AMS
\n",
"
ADB
\n",
"
179.04
\n",
"
17|1
\n",
"
\n",
"
\n",
"
19
\n",
"
2017-06-15 00:00:00 UTC
\n",
"
2017-07-05 00:00:00 UTC
\n",
"
7.58
\n",
"
12.25
\n",
"
AMS
\n",
"
ADB
\n",
"
170.98
\n",
"
18|1
\n",
"
\n",
"
\n",
"
20
\n",
"
2017-09-08 00:00:00 UTC
\n",
"
2017-09-28 00:00:00 UTC
\n",
"
3.33
\n",
"
12.25
\n",
"
AMS
\n",
"
ADB
\n",
"
189.43
\n",
"
16|1
\n",
"
\n",
"
\n",
"
22
\n",
"
2017-06-13 00:00:00 UTC
\n",
"
2017-07-03 00:00:00 UTC
\n",
"
6.42
\n",
"
18.67
\n",
"
AMS
\n",
"
ADB
\n",
"
163.57
\n",
"
11|1
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" DepartureDate ReturnDate OutboundDuration \\\n",
"4 2017-09-05 00:00:00 UTC 2017-09-25 00:00:00 UTC 6.50 \n",
"5 2017-08-02 00:00:00 UTC 2017-08-22 00:00:00 UTC 5.58 \n",
"6 2017-07-24 00:00:00 UTC 2017-08-13 00:00:00 UTC 12.08 \n",
"8 2017-07-17 00:00:00 UTC 2017-08-06 00:00:00 UTC 12.08 \n",
"13 2017-07-27 00:00:00 UTC 2017-08-16 00:00:00 UTC 8.33 \n",
"14 2017-07-24 00:00:00 UTC 2017-08-13 00:00:00 UTC 7.33 \n",
"16 2017-06-18 00:00:00 UTC 2017-07-08 00:00:00 UTC 3.50 \n",
"19 2017-06-15 00:00:00 UTC 2017-07-05 00:00:00 UTC 7.58 \n",
"20 2017-09-08 00:00:00 UTC 2017-09-28 00:00:00 UTC 3.33 \n",
"22 2017-06-13 00:00:00 UTC 2017-07-03 00:00:00 UTC 6.42 \n",
"\n",
" InboundDuration FlightDeparture FlightDestination Fare Position \n",
"4 11.33 AMS ADB 213.28 26|1 \n",
"5 8.08 AMS ADB 311.84 4|1 \n",
"6 12.42 AMS ADB 374.03 11|1 \n",
"8 9.92 AMS ADB 308.58 7|1 \n",
"13 9.33 AMS ADB 348.47 4|1 \n",
"14 9.42 AMS ADB 448.47 24|1 \n",
"16 7.50 AMS ADB 179.04 17|1 \n",
"19 12.25 AMS ADB 170.98 18|1 \n",
"20 12.25 AMS ADB 189.43 16|1 \n",
"22 18.67 AMS ADB 163.57 11|1 "
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data_cheapest = data[data[\"Position_fare\"]==1]\n",
"data_cheapest[['DepartureDate', 'ReturnDate', 'OutboundDuration', 'InboundDuration', 'FlightDeparture'\n",
" , 'FlightDestination', 'Fare', 'Position']].iloc[:10]\n",
"# let's get the rows where the fare is the cheapest (i.e., equal to 1)\n",
"# display the top 10 rows"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"import statsmodels.api as sm\n",
"import statsmodels.formula.api as smf\n",
"# statsmodels is a package we use for multiple linear regression\n",
"# these packages must be imported for use"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" OLS Regression Results \n",
"==============================================================================\n",
"Dep. Variable: Fare R-squared: 0.594\n",
"Model: OLS Adj. R-squared: 0.594\n",
"Method: Least Squares F-statistic: 4.452e+04\n",
"Date: Sat, 23 Jan 2021 Prob (F-statistic): 0.00\n",
"Time: 12:28:47 Log-Likelihood: -1.2606e+06\n",
"No. Observations: 182621 AIC: 2.521e+06\n",
"Df Residuals: 182614 BIC: 2.521e+06\n",
"Df Model: 6 \n",
"Covariance Type: nonrobust \n",
"======================================================================================\n",
" coef std err t P>|t| [0.025 0.975]\n",
"--------------------------------------------------------------------------------------\n",
"Intercept 92.3226 1.233 74.847 0.000 89.905 94.740\n",
"OutboundDuration 26.0401 0.184 141.318 0.000 25.679 26.401\n",
"InboundDuration 21.0637 0.191 110.183 0.000 20.689 21.438\n",
"OutboundStops 0.0787 1.418 0.056 0.956 -2.701 2.859\n",
"InboundStops 5.3968 1.405 3.842 0.000 2.644 8.150\n",
"OutboundGroundtime -22.9620 0.203 -112.967 0.000 -23.360 -22.564\n",
"InboundGroundtime -21.3819 0.216 -98.982 0.000 -21.805 -20.959\n",
"==============================================================================\n",
"Omnibus: 166355.105 Durbin-Watson: 1.330\n",
"Prob(Omnibus): 0.000 Jarque-Bera (JB): 22983156.638\n",
"Skew: 3.912 Prob(JB): 0.00\n",
"Kurtosis: 57.399 Cond. No. 78.2\n",
"==============================================================================\n",
"\n",
"Notes:\n",
"[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.\n"
]
}
],
"source": [
"model = smf.ols('Fare ~ OutboundDuration + InboundDuration + OutboundStops \\\n",
" + InboundStops + OutboundGroundtime + InboundGroundtime', data=data_cheapest).fit()\n",
"print(model.summary())\n",
"# here is a regression model that estimates the relationships of 6 independent variables with Fare"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
OutboundDuration
\n",
"
InboundDuration
\n",
"
OutboundStops
\n",
"
InboundStops
\n",
"
OutboundGroundtime
\n",
"
InboundGroundtime
\n",
"
Fare
\n",
"
predicted_price
\n",
"
\n",
" \n",
" \n",
"
\n",
"
4
\n",
"
6.50
\n",
"
11.33
\n",
"
2
\n",
"
1
\n",
"
2.00
\n",
"
6.83
\n",
"
213.28
\n",
"
313.826305
\n",
"
\n",
"
\n",
"
5
\n",
"
5.58
\n",
"
8.08
\n",
"
1
\n",
"
1
\n",
"
1.42
\n",
"
3.58
\n",
"
311.84
\n",
"
304.143044
\n",
"
\n",
"
\n",
"
6
\n",
"
12.08
\n",
"
12.42
\n",
"
1
\n",
"
1
\n",
"
8.00
\n",
"
8.00
\n",
"
374.03
\n",
"
319.221830
\n",
"
\n",
"
\n",
"
8
\n",
"
12.08
\n",
"
9.92
\n",
"
1
\n",
"
1
\n",
"
8.00
\n",
"
5.75
\n",
"
308.58
\n",
"
314.672054
\n",
"
\n",
"
\n",
"
13
\n",
"
8.33
\n",
"
9.33
\n",
"
1
\n",
"
1
\n",
"
4.42
\n",
"
5.17
\n",
"
348.47
\n",
"
299.199600
\n",
"
\n",
"
\n",
"
14
\n",
"
7.33
\n",
"
9.42
\n",
"
1
\n",
"
1
\n",
"
3.42
\n",
"
5.25
\n",
"
448.47
\n",
"
296.306673
\n",
"
\n",
"
\n",
"
16
\n",
"
3.50
\n",
"
7.50
\n",
"
0
\n",
"
1
\n",
"
0.00
\n",
"
2.25
\n",
"
179.04
\n",
"
298.727979
\n",
"
\n",
"
\n",
"
19
\n",
"
7.58
\n",
"
12.25
\n",
"
1
\n",
"
1
\n",
"
2.67
\n",
"
7.08
\n",
"
170.98
\n",
"
340.519419
\n",
"
\n",
"
\n",
"
20
\n",
"
3.33
\n",
"
12.25
\n",
"
0
\n",
"
1
\n",
"
0.00
\n",
"
7.08
\n",
"
189.43
\n",
"
291.078753
\n",
"
\n",
"
\n",
"
22
\n",
"
6.42
\n",
"
18.67
\n",
"
1
\n",
"
1
\n",
"
1.75
\n",
"
13.33
\n",
"
163.57
\n",
"
333.029483
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" OutboundDuration InboundDuration OutboundStops InboundStops \\\n",
"4 6.50 11.33 2 1 \n",
"5 5.58 8.08 1 1 \n",
"6 12.08 12.42 1 1 \n",
"8 12.08 9.92 1 1 \n",
"13 8.33 9.33 1 1 \n",
"14 7.33 9.42 1 1 \n",
"16 3.50 7.50 0 1 \n",
"19 7.58 12.25 1 1 \n",
"20 3.33 12.25 0 1 \n",
"22 6.42 18.67 1 1 \n",
"\n",
" OutboundGroundtime InboundGroundtime Fare predicted_price \n",
"4 2.00 6.83 213.28 313.826305 \n",
"5 1.42 3.58 311.84 304.143044 \n",
"6 8.00 8.00 374.03 319.221830 \n",
"8 8.00 5.75 308.58 314.672054 \n",
"13 4.42 5.17 348.47 299.199600 \n",
"14 3.42 5.25 448.47 296.306673 \n",
"16 0.00 2.25 179.04 298.727979 \n",
"19 2.67 7.08 170.98 340.519419 \n",
"20 0.00 7.08 189.43 291.078753 \n",
"22 1.75 13.33 163.57 333.029483 "
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"predictions = model.predict(data_cheapest)\n",
"data_cheapest[\"predicted_price\"] = predictions\n",
"data_cheapest[[\"OutboundDuration\", \"InboundDuration\", \"OutboundStops\", \"InboundStops\"\n",
" , \"OutboundGroundtime\", \"InboundGroundtime\", \"Fare\", \"predicted_price\"]].iloc[:10]\n",
"# after fitting a regression model, you can make predictions using the predict() function on the model\n",
"# you need to input as a parameter the dataset that you want to make predictions for, including the predictor variables\n",
"# show the predictors, Fare, and the predicted price"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Evaluating the model's prediction performance"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[]"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"
"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"import matplotlib.pyplot as plt\n",
"%matplotlib inline\n",
"\n",
"y_line = 1*np.linspace(0, 1600, 1600)\n",
"x_line = np.linspace(0, 1600, 1600)\n",
"\n",
"fig, ax = plt.subplots(figsize=(8,5))\n",
"data_cheapest.iloc[::1000].plot.scatter(\"predicted_price\", \"Fare\", ax=ax) \n",
"ax.plot(x_line, y_line, zorder=-1, c=\"red\")\n",
"\n",
"# this block of code is used to show graphically how the predicted price and Fare differ\n",
"# if the regression model was perfect, then we would expect all dots to be on the line\n",
"# vertical distance between the dots and the line represents prediction error"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Fare
\n",
"
predicted_price
\n",
"
error
\n",
"
\n",
" \n",
" \n",
"
\n",
"
4
\n",
"
213.28
\n",
"
313.826305
\n",
"
-100.546305
\n",
"
\n",
"
\n",
"
79808
\n",
"
165.75
\n",
"
253.386518
\n",
"
-87.636518
\n",
"
\n",
"
\n",
"
159613
\n",
"
460.12
\n",
"
334.675409
\n",
"
125.444591
\n",
"
\n",
"
\n",
"
239384
\n",
"
246.12
\n",
"
266.344910
\n",
"
-20.224910
\n",
"
\n",
"
\n",
"
319793
\n",
"
235.38
\n",
"
299.139201
\n",
"
-63.759201
\n",
"
\n",
"
\n",
"
398557
\n",
"
962.56
\n",
"
627.050914
\n",
"
335.509086
\n",
"
\n",
"
\n",
"
479155
\n",
"
212.48
\n",
"
258.015342
\n",
"
-45.535342
\n",
"
\n",
"
\n",
"
558413
\n",
"
200.70
\n",
"
275.651092
\n",
"
-74.951092
\n",
"
\n",
"
\n",
"
637718
\n",
"
388.03
\n",
"
560.648287
\n",
"
-172.618287
\n",
"
\n",
"
\n",
"
717285
\n",
"
532.00
\n",
"
710.171340
\n",
"
-178.171340
\n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" Fare predicted_price error\n",
"4 213.28 313.826305 -100.546305\n",
"79808 165.75 253.386518 -87.636518\n",
"159613 460.12 334.675409 125.444591\n",
"239384 246.12 266.344910 -20.224910\n",
"319793 235.38 299.139201 -63.759201\n",
"398557 962.56 627.050914 335.509086\n",
"479155 212.48 258.015342 -45.535342\n",
"558413 200.70 275.651092 -74.951092\n",
"637718 388.03 560.648287 -172.618287\n",
"717285 532.00 710.171340 -178.171340"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"predictions = model.predict(data_cheapest)\n",
"data_cheapest[\"predicted_price\"] = predictions\n",
"data_cheapest[\"error\"] = data_cheapest[\"Fare\"] - data_cheapest[\"predicted_price\"]\n",
"data_cheapest[[\"Fare\", \"predicted_price\", \"error\"]].iloc[::20000]\n",
"# let's get the prediction error in value and take a look at a few rows"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1.5486148186028004e-07"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data_cheapest[\"error\"].sum()\n",
"# notice that the sum of the prediction error is nearly 0"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"8.432355343369867e-13"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data_cheapest[\"error\"].mean()\n",
"# notice that the mean of the prediction error is nearly 0"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"
"
],
"text/plain": [
" error error_abs error_squared\n",
"count 1.826210e+05 182621.000000 1.826210e+05\n",
"mean 8.432355e-13 148.777489 5.796182e+04\n",
"std 2.407533e+02 189.280951 4.352893e+05\n",
"min -1.460074e+03 0.000560 3.132923e-07\n",
"25% -1.100040e+02 49.526002 2.452825e+03\n",
"50% -4.665469e+01 98.906375 9.782471e+03\n",
"75% 6.007065e+01 185.271040 3.432536e+04\n",
"max 7.587112e+03 7587.112281 5.756427e+07"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data_cheapest[[\"error\", \"error_abs\", \"error_squared\"]].describe()\n",
"# we often use the mean absolute error (MAE) to measure how good a model predicts\n",
"# another common metric is mean squared error (MSE), but it has a very large value (i.e., 57961.82)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"240.75261861193295"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"rmse = np.sqrt(data_cheapest[\"error_squared\"].mean())\n",
"rmse\n",
"# therefore, instead of using MSE, we often take the square root of it, resulting in root mean squared error (RMSE)\n",
"# notice that RMSE is more readible (although it is still difficult to interpret)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"