kaggle实战:6大回归模型预测机票价格
本文带来的是一篇新的kaggle案例文章:基于6大回归模型预测航空公司机票。这篇文章涉及到的知识点很多:
原notebook的学习地址为:
https://www.kaggle.com/anshigupta01/flight-price-prediction/notebook
导入库
数据基本信息
先把数据导进来:
1 | df = pd.read_excel("data_air.xlsx") |
查看数据的基本信息,包含:数据形状、字段类型等
1 | # 字段类型 |
具体字段的中文含义:
- Airline:不同类型的航空公司
- Date_of_Journey:旅客的旅行开始日期
- Source:旅客出发地
- Destination:旅客目的地
- Route:航班路线
- Dep_Time:出发时间
- Arrival_Time:抵达时间
- Duration:持续时间;指的是航班完成从出发到目的地的旅程的整个时间
- Total_Stops:总共停留地
- Additional_Info:其他信息,比如:食物、设备信息等
- Price:整个旅程的航班票价
希望可以理解中文含义,帮助进行数据分析~
数值型字段的描述统计信息,这里主要是针对Price字段:
缺失值处理
通过上面的缺失值检查,我们看到有两个字段是存在缺失值的,进行可视化。
missingno是一个可视化缺失值的库,方便使用,我们可以用pip install missingno
即可下载该库
1 | import missingno as mso |
缺失值删除
正常的字段是10683条,其中两个字段是10682条;缺失值的占比很小,考虑直接删除的数据
时间相关字段处理
时间处理
- 通过pd.to_datetime()直接将字符型的数据转成时间类型的数据
- 通过dt.day或者df.month 直接获取天或者月的信息
1 | # 将字段类型转成时间相关类型 |
对3个字段实施转换:
1 | # 3个字段的转换 |
查看转换之后的字段类型:
1 | df.dtypes |
1 | Airline object |
提取天和月
乘客旅程日期中(Date_of_Journey)单独提取天和月,作为两个字段
1 | df["day"] = df["Date_of_Journey"].dt.day |
最终生成了两个新的字段:
1 | # 删除字段 |
起飞时间和抵达时间处理
主要提取两个时间中的“小时”和“分钟”信息;同时删除原字段:
分别调用函数来提取信息:
1 | extract_hour(df,'Dep_Time') |
1 | extract_hour(df,'Arrival_Time') |
1 | df.head() |
航班持续时间duration
1、将持续时间规范化处理,统一变成0h 1m
1 | # # 原文方法 |
下面是个人版本写法:
2、从Duration字段中提取小时和分钟:
1 | df.drop("Duration",inplace=True,axis=1) |
3、字段类型转化:查看dur_hour和dur_minute的字段类型变化
字段编码
字段类型区分
主要是区分object和非object类型的字段信息。
1、针对字符型的字段
1 | column = [column for column in df.columns if df[column].dtype == "object"] |
1 | ['Airline', 'Source', 'Destination', 'Route', 'Total_Stops', 'Additional_Info'] |
2、数值型(连续型)字段
1 | continuous_col = [column for column in df.columns if df[column].dtype != "object"] |
1 | ['Price', |
2种编码技术
1 | Nominal data -- Data that are not in any order -->one hot encoding |
- 标称数据:没有任何顺序,使用独热编码oneot encoding
- 有序数据:存在一定的顺序,使用类型编码labelEncoder
生成标称型字段组成的数据
不同字段编码处理
航空公司-Airline
1、不同航空公司的数量统计:
2、查看航空公司与价格关系
1 | plt.figure(figsize=(15,8)) |
3、2个明显的结论
从上面的图形中看出来:
- Jet Airways Business公司的机票价格是最高的
- 其他公司的价格中位数是比较接近的
4、实现独热编码
由于航空公司属性是一个标称数据的字段,我们进行独热编码,通过哑变量的方式来实现:
停留地-Total_Stops
旅行期间的总共停留地,实施上面的同样操作:
1、和价格的关系
1 | plt.figure(figsize=(15,8)) |
2、实施硬编码;区别于航空公司的独热编码
出发地source
出发地和价格的关系:
1 | plt.figure(figsize=(18,12)) |
独热编码的过程:
目的地-destination
目的地的数量统计:
目的地和价格的关系:
独热编码的实现:
路线Route
1、不同路线的数量统计:
2、路线名称提取
从上面的结果中看出来,最长的路线中有5个地名,我们一次提取。
没有出现的数据则用NaN来表示:
1 | categorical['Route1']=categorical['Route'].str.split('→').str[0] |
3、缺失值字段
1 | for i in ['Route3', 'Route4', 'Route5']: |
4、类型编码LabelEncoder
1 | from sklearn.preprocessing import LabelEncoder |
抵达时间/小时-Arrival_Time_hour
抵达目的地时间和价格的关系:
1 | df.plot.hexbin(x='Arrival_Time_hour', |
建模数据
删除无效字段
生成的全部字段信息:
1 | categorical.columns |
将原始的无效字段直接删除:
1 | drop_col(categorical,'Airline') |
最终数据
将多个DataFrame进行拼接,组成最终的建模,其中Price进行最终的输出特征
1 | final_df=pd.concat([categorical,Airline,source,destination,df[continuous_col]],axis=1) |
离群点检测
对上面生成的最终数据进行离群点检测:
对离群点填充均值,查看填充后的效果:
1 | final_df['Price']=np.where(final_df['Price']>=40000, # 替换部分 |
数据切分
1 | X=final_df.drop('Price',axis=1) |
特征选择
本文中特征选择使用的是 mutual_info_classif 库:
1 | from sklearn.feature_selection import mutual_info_classif |
评价指标
本次建模中引入3个评价指标:
- r2_score(重点关注)
- mean_absolute_error
- mean_squared_error
1 | from sklearn.metrics import r2_score,mean_absolute_error,mean_squared_error |
建模
导入多种模型:
1 | # 逻辑回归 |
随机森林回归树-RandomForestRegressor
逻辑回归-LogisticRegression
K近邻回归-KNeighborsRegressor
决策树回归DecisionTreeRegressor
支持向量机回归-SVR
梯度提升回归-GradientBoostingRegressor
模型调优-Hypertunning the model
调优寻参
1 | # 采用随机搜索调优 |
1 | # 待调优的参数 |
1 | # 建模拟合 |
多次运行调优后找到最佳的参数组合:
调优后结果
通过r2_score指标发现:进行参数调优后,模型的效果得到提升~
补充:如何理解回归模型的r2_score指标
假设我们用$y_i$表示数据真实的观测值,用$\bar{y}$表示真实观测值的平均值,用$\hat{y_i}$表示通过模型得到的预测值,则:
回归平方和:SSR
SSR可以表示为;
即估计值与平均值的误差,反映自变量与因变量之间的相关程度的偏差平方和
残差平方和:SSE
SSE可以表示为:
即估计值与真实值的误差,反映的是整个模型拟合程度
总离差平方和SST
R2_score计算公式
R^2 score,即决定系数,反映因变量的全部变异能通过回归关系被自变量解释的比例。计算公式:
也可以写成:
进一步可以转成:
此时分子就变成了我们常用的评价指标均方误差MSE,分母就变成了方差Var。r2_score在0-1之间,越接近1越好。
两种常见的求解r2的方式:
1 | # 1、利用python间接求解 |