如何使用Python預(yù)測機票價格
印度的機票價格基于供需關(guān)系浮動,很少受到監(jiān)管機構(gòu)的限制。因此它通常被認為是不可預(yù)測的,而動態(tài)定價機制更增添了人們的困惑。
我們的目的是建立一個機器學習模型,根據(jù)歷史數(shù)據(jù)預(yù)測未來航班的價格,這些航班價格可以給客戶或航空公司服務(wù)提供商作為參考價格。

1.準備
開始之前,你要確保Python和pip已經(jīng)成功安裝在電腦上,如果沒有,請訪問這篇文章:超詳細Python安裝指南?進行安裝。
如果你用Python的目的是數(shù)據(jù)分析,可以直接安裝Anaconda:Python數(shù)據(jù)分析與挖掘好幫手—Anaconda,它內(nèi)置了Python和pip.
此外,推薦大家用VSCode編輯器,它有許多許多的優(yōu)點:Python 編程的最好搭檔—VSCode 詳細指南。
輸入命令安裝依賴:
1. Windows 環(huán)境 打開 Cmd (開始-運行-CMD)
2. MacOS 環(huán)境 打開 Terminal (command+空格輸入Terminal)
3. 如果你用的是 VSCode編輯器 或 Pycharm,可以直接使用界面下方的Terminal
pip install?pandas
pip install?numpy
pip install?matplotlib
pip install?seaborn
pip install?scikit-learn2.導入相關(guān)數(shù)據(jù)集
本文的數(shù)據(jù)集是 Data_Train.xlsx,首先看看訓練集的格式:
import?pandas as?pd
import?numpy as?np
import?matplotlib.pyplot as?plt
import?seaborn as?sns
sns.set_style('whitegrid')
flights = pd.read_excel('./Data_Train.xlsx')
flights.head()
可見訓練集中的字段有航空公司(Airline)、日期(Date_of_Journey)、始發(fā)站(Source)、終點站(Destination)、路線(Route)、起飛時間(Dep_Time)、抵達時間(Arrival_Time)、歷經(jīng)時長(Duration)、總計停留站點個數(shù)(Total_Stops)、額外信息(Additional_Info),最后是機票價格(Price)。
與其相對的測試集,除了缺少價格字段之外,與訓練集的其他所有字段均一致。
下載完整數(shù)據(jù)源和代碼請訪問:
https://pythondict.com/download/predict-ticket/
或在Python實用寶典后臺回復(fù):預(yù)測機票。
3.探索性數(shù)據(jù)分析
3.1 清理缺失數(shù)據(jù)
看看所有字段的基本信息:
flights.info()
其他的非零值數(shù)量均為10683,只有路線和??空军c數(shù)是10682,說明這兩個字段缺少了一個值。
謹慎起見,我們刪掉缺少數(shù)據(jù)的行:
# clearing the missing data
flights.dropna(inplace=True)
flights.info()
現(xiàn)在非零值達到一致數(shù)量,數(shù)據(jù)清理完畢。
3.2 航班公司分布特征
接下來看看航空公司的分布特征:
sns.countplot('Airline', data=flights)
plt.xticks(rotation=90)
plt.show()
前三名的航空公司分別是 IndiGo, Air India, JetAirways.
其中可能存在廉價航空公司。
3.3 再來看看始發(fā)地的分布
sns.countplot('Source',data=flights)
plt.xticks(rotation=90)
plt.show()
某些地區(qū)可能是冷門地區(qū),存在冷門機票的可能性比較大。
3.4 ??空军c的數(shù)量分布
sns.countplot('Total_Stops',data=flights)
plt.xticks(rotation=90)
plt.show()
看來大部分航班在飛行途中只??恳淮位驘o停靠。
會不會某些??慷嗟暮桨啾容^便宜?
3.5 有多少數(shù)據(jù)含有額外信息
plot=plt.figure()
sns.countplot('Additional_Info',data=flights)
plt.xticks(rotation=90)
大部分航班信息中都沒有包含額外信息,除了部分航班信息有:不包含飛機餐、不包含免費托運。
這個信息挺重要的,是否不包含這兩項服務(wù)的飛機機票比較便宜?
3.6 時間維度分析
首先轉(zhuǎn)換時間格式:
flights['Date_of_Journey'] = pd.to_datetime(flights['Date_of_Journey'])
flights['Dep_Time'] = pd.to_datetime(flights['Dep_Time'],format='%H:%M:%S').dt.time
接下來,研究一下出發(fā)時間和價格的關(guān)系:
flights['weekday'] = flights[['Date_of_Journey']].apply(lambda?x:x.dt.day_name())
sns.barplot('weekday','Price',data=flights)
plt.show()
大體上價格沒有差別,說明這個特征是無效的。
那么月份和機票價格的關(guān)系呢?
flights["month"] = flights['Date_of_Journey'].map(lambda?x: x.month_name())
sns.barplot('month','Price',data=flights)
plt.show()
沒想到4月的機票價格均價只是其他月份的一半,看來4月份是印度的出行淡季吧。
起飛時間和價格的關(guān)系:
flights['Dep_Time'] = flights['Dep_Time'].apply(lambda?x:x.hour)
flights['Dep_Time'] = pd.to_numeric(flights['Dep_Time'])
sns.barplot('Dep_Time','Price',data=flights)
plot.show()
可以看到,紅眼航班(半夜及早上)的機票比較便宜,這是符合我們的認知的。
3.7 清除無效特征
把那些和價格沒有關(guān)聯(lián)關(guān)系的字段直接去除掉:
flights.drop(['Route','Arrival_Time','Date_of_Journey'],axis=1,inplace=True)
flights.head()
4.模型訓練
接下來,我們可以準備使用模型來預(yù)測機票價格了,不過,還需要對數(shù)據(jù)進行預(yù)處理和特征縮放。
4.1 數(shù)據(jù)預(yù)處理
將字符串變量使用數(shù)字替代:
from?sklearn.preprocessing import?LabelEncoder
var_mod = ['Airline','Source','Destination','Additional_Info','Total_Stops','weekday','month','Dep_Time']
le = LabelEncoder()
for?i in?var_mod:
????flights[i] = le.fit_transform(flights[i])
flights.head()
對每列數(shù)據(jù)進行特征縮放,提取自變量(x)和因變量(y):
flights.corr()
def?outlier(df):
????for?i in?df.describe().columns:
????????Q1=df.describe().at['25%',i]
????????Q3=df.describe().at['75%',i]
????????IQR= Q3-Q1
????????LE=Q1-1.5*IQR
????????UE=Q3+1.5*IQR
????????df[i]=df[i].mask(df[i]????????df[i]=df[i].mask(df[i]>UE,UE)
????return?df
flights = outlier(flights)
x = flights.drop('Price',axis=1)
y = flights['Price'] 劃分測試集和訓練集:
from?sklearn.model_selection import?train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=101)
4.2 模型訓練及測試
使用隨機森林進行模型訓練:
from?sklearn.ensemble import?RandomForestRegressor
rfr=RandomForestRegressor(n_estimators=100)
rfr.fit(x_train,y_train)在隨機森林中,我們有一種根據(jù)數(shù)據(jù)的相關(guān)性來確定特征重要性的方法:
features=x.columns
importances = rfr.feature_importances_
indices = np.argsort(importances)
plt.figure(1)
plt.title('Feature Importances')
plt.barh(range(len(indices)), importances[indices], color='b', align='center')
plt.yticks(range(len(indices)), features[indices])
plt.xlabel('Relative Importance')
可以看到,Duration(飛行時長)是影響最大的因子。
對劃分的測試集進行預(yù)測,得到結(jié)果:
predictions=rfr.predict(x_test)
plt.scatter(y_test,predictions)
plt.show()
這樣看不是很直觀,接下來我們要數(shù)字化地評價這個模型。
4.3 模型評價
sklearn 提供了非常方便的函數(shù)來評價模型,那就是 metrics :
from?sklearn import?metrics
print('MAE:', metrics.mean_absolute_error(y_test, predictions))
print('MSE:', metrics.mean_squared_error(y_test, predictions))
print('RMSE:', np.sqrt(metrics.mean_squared_error(y_test, predictions)))
print('r2_score:', (metrics.r2_score(y_test, predictions)))結(jié)果:
MAE: 1453.9350628905618
MSE: 4506308.3645551
RMSE: 2122.806718605135
r2_score: 0.7532074710409375這4個值中你可以只關(guān)注R2_score,r2越接近1說明模型效果越好,這個模型的分數(shù)是0.75,算是很不錯的模型了。
看看其殘差直方圖是否符合正態(tài)分布:
sns.distplot((y_test-predictions),bins=50)
plt.show()
不錯,多數(shù)預(yù)測結(jié)果和真實值都在-1000到1000的范圍內(nèi),算是可以接受的結(jié)果。其殘差直方圖也基本符合正態(tài)分布,說明模型是有效果的。
譯自kaggle社區(qū),有較多的增刪:
https://www.kaggle.com/harikrishna9/how-to-predict-flight-ticket-price/notebook
我們的文章到此就結(jié)束啦,如果你喜歡今天的Python 實戰(zhàn)教程,請持續(xù)關(guān)注Python實用寶典。
有任何問題,可以在公眾號后臺回復(fù):加群,回答相應(yīng)紅字驗證信息,進入互助群詢問。
原創(chuàng)不易,希望你能在下面點個贊和在看支持我繼續(xù)創(chuàng)作,謝謝!
點擊下方閱讀原文可獲得更好的閱讀體驗
Python實用寶典?(pythondict.com)
不只是一個寶典
歡迎關(guān)注公眾號:Python實用寶典
