08六大回归模型预测航班票价

导入库

import pandas as pd
import numpy as np
pd.set_option("display.max_columns",33)

import seaborn as sns
import matplotlib.pyplot as plt
import plotly.express as px

from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.metrics import accuracy_score,confusion_matrix

import warnings
warnings.filterwarnings("ignore")

数据基本信息

df = pd.read_excel("Data_Train.xlsx")
df.head()
image.png
df.shape
image.png
df.isnull().sum()
image.png
df.dtypes
image.png
columns = df.columns.tolist()
columns

image.png

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

df.info()
image.png
df.describe()
image.png

缺失值处理

import missingno as mso

mso.bar(df,color="blue")

plt.show()
image.png
# 缺失值删除
df.dropna(inplace=True)
df.isnull().sum()
image.png

时间相关字段处理

# 时间处理
# 通过pd.to_datetime()直接将字符型的数据转成时间类型的数据
# 通过dt.day或者df.month 直接获取天或者月的信息
def change_to_datetime(col):
    df[col] = pd.to_datetime(df[col])
for col in ["Date_of_Journey","Dep_Time","Arrival_Time"]:
    change_to_datetime(col)
df.dtypes
image.png
# 提取天和月
df["day"] = df["Date_of_Journey"].dt.day
df["month"] = df["Date_of_Journey"].dt.month
df.head()
image.png
df.drop("Date_of_Journey",axis=1,inplace=True)
# 起飞时间和抵达时间处理
def extract_hour(data,col):
    data[col+ "_hour"] = data[col].dt.hour
    
def extract_minute(data,col):
    data[col+ "_minute"] = data[col].dt.minute
    
def drop_col(data,col):
    data.drop(col,axis=1,inplace=True)
extract_hour(df,"Dep_Time")
extract_minute(df,"Dep_Time")
drop_col(df,"Dep_Time")
extract_hour(df,"Arrival_Time")
extract_minute(df,"Arrival_Time")
drop_col(df,"Arrival_Time")
df.head()
image.png
# 航班持续时间
# 1、将持续时间规范化处理,统一变成0h 1m
# 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]
def change_duration(x):
    if "h" in x and "m" in x:
        return x
    else:
        if "h" in x:
            return x + " 0m"
        else:
            return "0h " + x
        
df["Duration"] = df["Duration"].apply(change_duration)
df.head()
image.png
# 2、从Duration字段中提取小时和分钟
df1 = df["Duration"].str.extract(r'(?P<dur_hour>\d+)h (?P<dur_minute>\d+)m')
df1.head()
image.png
df = df.join(df1)
df.head()
image.png
df.drop("Duration",inplace=True,axis=1)
# 3、字段类型转化:查看dur_hour和dur_minute的字段类型变化
df.dtypes
image.png
df["dur_hour"] = df["dur_hour"].astype(int)
df["dur_minute"] = df["dur_minute"].astype(int)
df.dtypes
image.png

字段编码

# 1、针对字符型的字段
column = [column for column in df.columns if df[column].dtype == "object"]
column
image.png
# 2、数值型(连续型)字段
continuous_col = [column for column in df.columns if df[column].dtype != "object"]
continuous_col

image.png

2种编码技术
标称数据:没有任何顺序,使用独热编码oneot encoding
有序数据:存在一定的顺序,使用类型编码labelEncoder

# 生成标称型字段组成的数据
categorical = df[column]
categorical.head()
image.png

不同字段编码处理

# 航空公司-Airline
# 1、不同航空公司的数量统计:
airline = categorical["Airline"].value_counts().reset_index()
airline
image.png
# 2、查看航空公司与价格关系
plt.figure(figsize=(15,8))

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

plt.show()
image.png

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

# 3、实现独热编码
Airline = pd.get_dummies(categorical["Airline"],drop_first=True)
Airline.head()
image.png
# 停留地-Total_Stops
# 1、和价格的关系
plt.figure(figsize=(15,8))

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

plt.show()
image.png
# 2、实施硬编码;区别于航空公司的独热编码
dict_stops = {"non-stop":0, "1 stop":1, "2 stops":2, "3 stops":3, "4 stops":4}
categorical["Total_Stops"] = categorical["Total_Stops"].map(dict_stops)
categorical.head()
image.png
# 出发地source
# 出发地和价格的关系:
plt.figure(figsize=(18,12))

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

plt.show()
image.png
# 独热编码的过程:
source = pd.get_dummies(categorical["Source"],drop_first=True)
source.head()
image.png
# 目的地-destination
# 目的地和价格的关系
plt.figure(figsize=(18, 12))

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

plt.show()
image.png
# 独热编码的实现
destination = pd.get_dummies(categorical["Destination"], drop_first=True)
destination.head()
image.png
# 路线Route
# 1.不同路线的数量统计
categorical["Route"].value_counts()
image.png
# 2.路线名称提取
# 从上面结果看出来最长的路线中有5个地名,我们一次性提取
# 没有出现的数据则用NaN来表示:
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()
image.png
# 3.缺失值字段
categorical.drop("Route", axis=1, inplace=True)
categorical.isnull().sum()
image.png
for i in ["Route3", "Route4", "Route5"]:
    categorical[i].fillna("None", inplace=True)
# 4.类型编码LabelEncoder
from sklearn import preprocessing

le =preprocessing.LabelEncoder()
for i in ["Route1", "Route2", "Route3", "Route4", "Route5"]:
    categorical[i] = le.fit_transform(categorical[i])
    
categorical.head()
image.png
# 抵达时间/小时-Arrival_Time_hour
# 抵达目的地时间和价格的关系
df.plot.hexbin(x="Arrival_Time_hour", y="Price", gridsize=15)

plt.show()
image.png

建模数据

# 删除无效字段
# 生成的全部字段信息
categorical.columns
image.png
# 将原始的无效字段直接删除
drop_col(categorical, "Airline")
drop_col(categorical, "Source")
drop_col(categorical, "Destination")
drop_col(categorical, "Additional_Info")
# 最终数据
final_df = pd.concat([categorical, Airline, source, destination, df[continuous_col]], axis=1)
final_df.head()
image.png
# 离群点检测
# 对上面生成的最终数据进行离群点检测
def plot(data, col):
    fig, (ax1, ax2) = plt.subplots(2, 1)
    sns.distplot(data[col], ax=ax1)
    sns.boxplot(data[col], ax=ax2)
    
plot(final_df, "Price")
image.png
# 对离群点填充均值,查看填充后的效果
final_df["Price"] = np.where(final_df["Price"]>=40000,
                            final_df["Price"].median(),
                            final_df["Price"])
plot(final_df, "Price")
image.png
# 数据切分
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)

特征选择

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)
image.png

评价指标

# r2_score(重点关注), mean_absolute_error, mean_squared_error
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)

建模

# 导入多种模型
# 逻辑回归
from sklearn.linear_model import LogisticRegression
# K近邻回归
from sklearn.neighbors import KNeighborsRegressor
# 决策树回归
from sklearn.tree import DecisionTreeRegressor
# 支持向量机回归
from sklearn.svm import SVR
# 梯度提升回归,随机森林回归
from sklearn.ensemble import GradientBoostingRegressor, RandomForestRegressor
# 随机森林回归树
predict(RandomForestRegressor())
image.png
# 逻辑回归
predict(LogisticRegression())
image.png
# K近邻回归
predict(KNeighborsRegressor())
image.png
# 决策树回归
predict(DecisionTreeRegressor())
image.png
# 支持向量机回归
predict(SVR())
image.png
# 梯度提升回归
predict(GradientBoostingRegressor())
image.png

模型调优

# 调优寻参
# 采用随机搜索调优
from sklearn.model_selection import RandomizedSearchCV

random_grid = {
    "n_estimators":[100, 120, 150, 180, 200, 220],
    "max_features":["auto", "sqrt"],
    "max_depth":[5, 10, 15, 20]
}
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)
image.png
rf_random.best_params_
image.png
# 调优后结果
prediction = rf_random.predict(X_test)
sns.distplot(y_test - prediction)
image.png
r2_score(y_test, prediction)
image.png

两种常见求解r2方式

# 利用python间接求解
from sklearn.metrics import mean_squared_error

y_test = [1, 2, 3]
y_pred = [1.3, 2.1, 3.5]
1 - mean_squared_error(y_test, y_pred)/np.var(y_test)
image.png
# 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)
image.png

来源:尤而小屋

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,755评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,305评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,138评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,791评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,794评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,631评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,362评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,264评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,724评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,900评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,040评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,742评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,364评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,944评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,060评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,247评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,979评论 2 355

推荐阅读更多精彩内容