Fork me on GitHub

kaggle实战_6大回归模型预测机票价格

kaggle实战:6大回归模型预测机票价格

本文带来的是一篇新的kaggle案例文章:基于6大回归模型预测航空公司机票。这篇文章涉及到的知识点很多:

原notebook的学习地址为:

https://www.kaggle.com/anshigupta01/flight-price-prediction/notebook

导入库

数据基本信息

先把数据导进来:

1
2
df = pd.read_excel("data_air.xlsx")
df.head()

查看数据的基本信息,包含:数据形状、字段类型等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 字段类型
df.dtypes

Airline object
Date_of_Journey object
Source object
Destination object
Route object
Dep_Time object
Arrival_Time object
Duration object
Total_Stops object
Additional_Info object
Price int64
dtype: object

# 全部字段
columns = df.columns.tolist()
columns

['Airline',
'Date_of_Journey',
'Source',
'Destination',
'Route',
'Dep_Time',
'Arrival_Time',
'Duration',
'Total_Stops',
'Additional_Info',
'Price']

具体字段的中文含义:

  • Airline:不同类型的航空公司
  • Date_of_Journey:旅客的旅行开始日期
  • Source:旅客出发地
  • Destination:旅客目的地
  • Route:航班路线
  • Dep_Time:出发时间
  • Arrival_Time:抵达时间
  • Duration:持续时间;指的是航班完成从出发到目的地的旅程的整个时间
  • Total_Stops:总共停留地
  • Additional_Info:其他信息,比如:食物、设备信息等
  • Price:整个旅程的航班票价

希望可以理解中文含义,帮助进行数据分析~

数值型字段的描述统计信息,这里主要是针对Price字段:

缺失值处理

通过上面的缺失值检查,我们看到有两个字段是存在缺失值的,进行可视化。

missingno是一个可视化缺失值的库,方便使用,我们可以用pip install missingno 即可下载该库

1
2
3
import missingno as mso
mso.bar(df,color="blue")
plt.show()

缺失值删除

正常的字段是10683条,其中两个字段是10682条;缺失值的占比很小,考虑直接删除的数据

时间相关字段处理

时间处理

  1. 通过pd.to_datetime()直接将字符型的数据转成时间类型的数据
  2. 通过dt.day或者df.month 直接获取天或者月的信息
1
2
3
4
# 将字段类型转成时间相关类型

def change_to_datetime(col):
df[col] = pd.to_datetime(df[col])

对3个字段实施转换:

1
2
3
4
# 3个字段的转换

for col in ['Date_of_Journey','Dep_Time', 'Arrival_Time']:
change_to_datetime(col)

查看转换之后的字段类型:

1
df.dtypes
1
2
3
4
5
6
7
8
9
10
11
12
Airline                    object
Date_of_Journey datetime64[ns]
Source object
Destination object
Route object
Dep_Time datetime64[ns]
Arrival_Time datetime64[ns]
Duration object
Total_Stops object
Additional_Info object
Price int64
dtype: object

提取天和月

乘客旅程日期中(Date_of_Journey)单独提取天和月,作为两个字段

1
2
3
df["day"] = df["Date_of_Journey"].dt.day
df["month"] = df["Date_of_Journey"].dt.month
df.head()

最终生成了两个新的字段:

1
2
# 删除字段
df.drop('Date_of_Journey', axis=1, inplace=True)

起飞时间和抵达时间处理

主要提取两个时间中的“小时”和“分钟”信息;同时删除原字段:

分别调用函数来提取信息:

1
2
3
extract_hour(df,'Dep_Time')
extract_minute(df,'Dep_Time')
drop_col(df,'Dep_Time') # 删除原字段
1
2
3
extract_hour(df,'Arrival_Time')
extract_minute(df,'Arrival_Time')
drop_col(df,'Arrival_Time')
1
df.head()

航班持续时间duration

1、将持续时间规范化处理,统一变成0h 1m

1
2
3
4
5
6
7
8
9
10
11
12
# # 原文方法

# duration=list(df['Duration'])

# for i in range(len(duration)):
# if len(duration[i].split(' '))==2:
# pass
# else:
# if 'h' in duration[i]:
# duration[i]=duration[i] + ' 0m'
# else:
# duration[i]='0h '+ duration[i]

下面是个人版本写法:

2、从Duration字段中提取小时和分钟:

1
df.drop("Duration",inplace=True,axis=1)

3、字段类型转化:查看dur_hour和dur_minute的字段类型变化

字段编码

字段类型区分

主要是区分object和非object类型的字段信息。

1、针对字符型的字段

1
2
column = [column for column in df.columns if df[column].dtype == "object"]
column
1
['Airline', 'Source', 'Destination', 'Route', 'Total_Stops', 'Additional_Info']

2、数值型(连续型)字段

1
2
continuous_col = [column for column in df.columns if df[column].dtype != "object"]
continuous_col
1
2
3
4
5
6
7
8
9
['Price',
'day',
'month',
'Dep_Time_hour',
'Dep_Time_minute',
'Arrival_Time_hour',
'Arrival_Time_minute',
'dur_hour',
'dur_minute']

2种编码技术

1
2
Nominal data -- Data that are not in any order -->one hot encoding
ordinal data -- Data are in order --> labelEncoder
  • 标称数据:没有任何顺序,使用独热编码oneot encoding
  • 有序数据:存在一定的顺序,使用类型编码labelEncoder

生成标称型字段组成的数据

不同字段编码处理

航空公司-Airline

1、不同航空公司的数量统计:

2、查看航空公司与价格关系

1
2
3
4
5
6
7
8
plt.figure(figsize=(15,8))

sns.boxplot(x="Airline",
y="Price",
data=df.sort_values('Price',ascending=False)
)

plt.show()

3、2个明显的结论

从上面的图形中看出来:

  • Jet Airways Business公司的机票价格是最高的
  • 其他公司的价格中位数是比较接近的

4、实现独热编码

由于航空公司属性是一个标称数据的字段,我们进行独热编码,通过哑变量的方式来实现:

停留地-Total_Stops

旅行期间的总共停留地,实施上面的同样操作:

1、和价格的关系

1
2
3
4
5
6
plt.figure(figsize=(15,8))

sns.boxplot(x='Total_Stops',
y='Price',
data=df.sort_values('Price',ascending=False))
plt.show()

2、实施硬编码;区别于航空公司的独热编码

出发地source

出发地和价格的关系:

1
2
3
4
5
6
7
plt.figure(figsize=(18,12))

sns.catplot(x='Source',
y='Price',
data=df.sort_values('Price',ascending=False),kind='boxen')

plt.show()

独热编码的过程:

目的地-destination

目的地的数量统计:

目的地和价格的关系:

独热编码的实现:

路线Route

1、不同路线的数量统计:

2、路线名称提取

从上面的结果中看出来,最长的路线中有5个地名,我们一次提取。

没有出现的数据则用NaN来表示:

1
2
3
4
5
6
categorical['Route1']=categorical['Route'].str.split('→').str[0]
categorical['Route2']=categorical['Route'].str.split('→').str[1]
categorical['Route3']=categorical['Route'].str.split('→').str[2]
categorical['Route4']=categorical['Route'].str.split('→').str[3]
categorical['Route5']=categorical['Route'].str.split('→').str[4]
categorical.head()

3、缺失值字段

1
2
for i in ['Route3', 'Route4', 'Route5']:
categorical[i].fillna('None',inplace=True)

4、类型编码LabelEncoder

1
2
3
4
5
6
7
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()

for i in ['Route1', 'Route2', 'Route3', 'Route4', 'Route5']:
categorical[i]=le.fit_transform(categorical[i])

categorical.head()

抵达时间/小时-Arrival_Time_hour

抵达目的地时间和价格的关系:

1
2
3
4
df.plot.hexbin(x='Arrival_Time_hour',
y='Price',
gridsize=15)
plt.show()

建模数据

删除无效字段

生成的全部字段信息:

1
2
3
4
5
categorical.columns

Index(['Airline', 'Source', 'Destination', 'Total_Stops', 'Additional_Info',
'Route1', 'Route2', 'Route3', 'Route4', 'Route5'],
dtype='object')

将原始的无效字段直接删除:

1
2
3
4
drop_col(categorical,'Airline')
drop_col(categorical,'Source')
drop_col(categorical,'Destination')
drop_col(categorical,'Additional_Info')

最终数据

将多个DataFrame进行拼接,组成最终的建模,其中Price进行最终的输出特征

1
2
3
final_df=pd.concat([categorical,Airline,source,destination,df[continuous_col]],axis=1)

final_df.head()

离群点检测

对上面生成的最终数据进行离群点检测:

对离群点填充均值,查看填充后的效果:

1
2
3
4
final_df['Price']=np.where(final_df['Price']>=40000,  # 替换部分
final_df['Price'].median(), # 替换数据
final_df['Price']) # 替换字段
plot(final_df, "Price")

数据切分

1
2
3
4
5
6
7
8
X=final_df.drop('Price',axis=1)
y=final_df['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.20,
random_state=123)

特征选择

本文中特征选择使用的是 mutual_info_classif 库:

1
2
3
4
5
6
from sklearn.feature_selection import mutual_info_classif
imp = pd.DataFrame(mutual_info_classif(X,y),
index=X.columns)

imp.columns=['importance']
imp.sort_values(by='importance',ascending=False)

评价指标

本次建模中引入3个评价指标:

  • r2_score(重点关注)
  • mean_absolute_error
  • mean_squared_error

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from sklearn.metrics import r2_score,mean_absolute_error,mean_squared_error

def predict(ml_model):
print("Model is: ", ml_model)

model = ml_model.fit(X_train, y_train)

print("Training score: ", model.score(X_train,y_train))

predictions = model.predict(X_test)
print("Predictions: ", predictions)
print('-----------------')
r2score = r2_score(y_test, predictions)
print("r2 score is: ", r2score)

print('MAE:{}', mean_absolute_error(y_test,predictions))
print('MSE:{}', mean_squared_error(y_test,predictions))
print('RMSE:{}', np.sqrt(mean_squared_error(y_test,predictions)))

# 真实值和预测值的差值
sns.distplot(y_test - predictions)

建模

导入多种模型:

1
2
3
4
5
6
7
8
# 逻辑回归
from sklearn.linear_model import LogisticRegression
# k近邻回归
from sklearn.neighbors import KNeighborsRegressor
# 决策树回归
from sklearn.tree import DecisionTreeRegressor
# 梯度提升回归,随机森林回归
from sklearn.ensemble import GradientBoostingRegressor,RandomForestRegressor

随机森林回归树-RandomForestRegressor

逻辑回归-LogisticRegression

K近邻回归-KNeighborsRegressor

决策树回归DecisionTreeRegressor

支持向量机回归-SVR

梯度提升回归-GradientBoostingRegressor

模型调优-Hypertunning the model

调优寻参

1
2
# 采用随机搜索调优
from sklearn.model_selection import RandomizedSearchCV
1
2
3
4
5
6
# 待调优的参数
random_grid = {
'n_estimators' : [100, 120, 150, 180, 200,220],
'max_features':['auto','sqrt'],
'max_depth':[5,10,15,20],
}
1
2
3
4
5
6
7
8
9
10
# 建模拟合
rf=RandomForestRegressor()
rf_random=RandomizedSearchCV(
estimator=rf,
param_distributions=random_grid,
cv=3,
verbose=2,
n_jobs=-1)

rf_random.fit(X_train,y_train)

多次运行调优后找到最佳的参数组合:

调优后结果

通过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
2
3
4
5
6
7
8
9
# 1、利用python间接求解
from sklearn.metrics import mean_squared_error
1 - mean_squared_error(y_test, y_pred)/ np.var(y_test)

# 2、sklearn直接求解
from sklearn.metrics import r2_score
y_test = [1, 2, 3]
y_pred = [1.3, 2.1, 3.5]
r2_score(y_test,y_pred)

本文标题:kaggle实战_6大回归模型预测机票价格

发布时间:2022年03月09日 - 01:03

原始链接:http://www.renpeter.cn/2022/03/09/kaggle%E5%AE%9E%E6%88%98-6%E5%A4%A7%E5%9B%9E%E5%BD%92%E6%A8%A1%E5%9E%8B%E9%A2%84%E6%B5%8B%E6%9C%BA%E7%A5%A8%E4%BB%B7%E6%A0%BC.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

Coffee or Tea