大家好,我是老班~ 今天给大家带来一篇kaggle案例文章:基于6大回归模型预测航空公司机票的价格。 这篇文章涉及到的知识点会比较多,关键是数据预处理和特征工程部分: ![]() 导入库![]() 数据基本信息先把数据导进来: df = pd.read_excel('data_air.xlsx')df.head() ![]() 查看数据的基本信息,包含:数据形状、字段类型等 ![]()
具体字段的中文含义:
希望可以理解中文含义,帮助进行数据分析~ ![]() 数值型字段的描述统计信息,这里主要是针对Price字段: ![]() 缺失值处理通过上面的缺失值检查,我们看到有两个字段是存在缺失值的,进行可视化。 missingno是一个可视化缺失值得库,方便使用,我们可以用pip install missingno 即可下载该库 import missingno as msomso.bar(df,color='blue')plt.show() ![]() 缺失值删除正常的字段是10683条,其中两个字段是10682条;缺失值得占比很小,考虑直接删除的数据 ![]() 时间相关字段处理时间处理
对3个字段实施转换: # 3个字段的转换for col in ['Date_of_Journey','Dep_Time', 'Arrival_Time']: change_to_datetime(col) 查看转换之后的字段类型:
Airline objectDate_of_Journey datetime64[ns]Source objectDestination objectRoute objectDep_Time datetime64[ns]Arrival_Time datetime64[ns]Duration objectTotal_Stops objectAdditional_Info objectPrice int64dtype: object 提取天和月乘客旅程日期中(Date_of_Journey)单独提取天和月,作为两个字段
最终生成了两个新的字段: ![]() # 删除字段df.drop('Date_of_Journey', axis=1, inplace=True) 起飞时间和抵达时间处理主要提取两个时间中的“小时”和“分钟”信息;同时删除原字段: ![]() 分别调用函数来提取信息:
extract_hour(df,'Arrival_Time')extract_minute(df,'Arrival_Time')drop_col(df,'Arrival_Time')
![]() 航班持续时间duration1、将持续时间规范化处理,统一变成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] 下面是个人版本写法: ![]() ![]() 2、从Duration字段中提取小时和分钟: ![]()
3、字段类型转化:查看dur_hour和dur_minute的字段类型变化 ![]() 字段编码字段类型区分主要是区分object和非object类型的字段信息。 1、针对字符型的字段 column = [column for column in df.columns if df[column].dtype == 'object']column
2、数值型(连续型)字段 continuous_col = [column for column in df.columns if df[column].dtype != 'object']continuous_col
2种编码技术Nominal data -- Data that are not in any order -->one hot encodingordinal data -- Data are in order --> labelEncoder
生成标称型字段组成的数据![]() 不同字段编码处理航空公司-Airline1、不同航空公司的数量统计: ![]() ![]() 2、查看航空公司与价格关系
![]() 3、2个明显的结论 从上面的图形中可以看出来:
4、实现独热编码 由于航空公司属性是一个标称数据的字段,我们进行独热编码,通过哑变量的方式来实现: ![]() 停留地-Total_Stops旅行期间的总共停留地,实施上面的同样操作: 1、和价格的关系 plt.figure(figsize=(15,8))sns.boxplot(x='Total_Stops', y='Price', data=df.sort_values('Price',ascending=False))plt.show() ![]() 2、实施硬编码;区别于航空公司的独热编码 ![]() 出发地source出发地和价格的关系:
![]() 独热编码的过程: ![]() 目的地-destination目的地的数量统计: ![]() 目的地和价格的关系: ![]() 独热编码的实现: ![]() 路线Route1、不同路线的数量统计: ![]() 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() ![]() 3、缺失值字段 ![]()
4、类型编码LabelEncoder from sklearn.preprocessing import LabelEncoderle = LabelEncoder()for i in ['Route1', 'Route2', 'Route3', 'Route4', 'Route5']: categorical[i]=le.fit_transform(categorical[i]) categorical.head() ![]() 抵达时间/小时-Arrival_Time_hour抵达目的地时间和价格的关系:
![]() 建模数据删除无效字段生成的全部字段信息: categorical.columnsIndex(['Airline', 'Source', 'Destination', 'Total_Stops', 'Additional_Info', 'Route1', 'Route2', 'Route3', 'Route4', 'Route5'], dtype='object') 将原始的无效字段直接删除:
最终数据将多个DataFrame进行拼接,组成最终的建模,其中Price进行最终的输出特征 final_df=pd.concat([categorical,Airline,source,destination,df[continuous_col]],axis=1)final_df.head() ![]() 离群点检测对上面生成的最终数据进行离群点检测: ![]() ![]() 对离群点填充均值,查看填充后的效果:
![]() 数据切分X=final_df.drop('Price',axis=1)y=final_df['Price']from sklearn.model_selection import train_test_splitX_train,X_test,y_train,y_test = train_test_split(X,y, test_size=0.20, random_state=123) 特征选择本文中特征选择使用的是 mutual_info_classif 库:
![]() 评价指标本次建模中引入3个评价指标:
![]() from sklearn.metrics import r2_score,mean_absolute_error,mean_squared_errordef 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) 建模导入多种模型:
随机森林回归树-RandomForestRegressor![]() 逻辑回归-LogisticRegression ![]() K近邻回归-KNeighborsRegressor ![]() 决策树回归DecisionTreeRegressor ![]() 支持向量机回归-SVR ![]() 梯度提升回归-GradientBoostingRegressor ![]() 模型调优-Hypertunning the model调优寻参# 采用随机搜索调优from sklearn.model_selection import RandomizedSearchCV
# 建模拟合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指标假设我们用表示数据真实的观测值,用表示真实观测值的平均值,用表示通过模型得到的预测值,则: 回归平方和:SSRSSR可以表示为; ![]() 即估计值与平均值的误差,反映自变量与因变量之间的相关程度的偏差平方和 残差平方和:SSESSE可以表示为: ![]() 即估计值与真实值的误差,反映的是整个模型拟合程度 总离差平方和:SST![]() R2_score计算公式R^2 score,即决定系数,反映因变量的全部变异能通过回归关系被自变量解释的比例。计算公式: ![]() 也可以写成: ![]() 进一步可以转成: ![]() 此时分子就变成了我们常用的评价指标均方误差MSE,分母就变成了方差Var。r2_score在0-1之间,越接近1越好。 两种常见的求解r2的方式:
|
|