随着人们生活水平的提高,越来越多的人会选择购买轿车。购买二手车的人也增长迅速,各种各样的二手车交易平台(瓜子二手车,人人车等)也应运而生。由于购买轿车对于大多数普通人来说是一笔很大的支出,所以二手车的价格是一个很重要的考量,怎样根据车辆状况买到价格合适的轿车也是很多人关心的问题。
本项目以利用来自某交易平台的二手车交易记录来预测二手车的交易价格为任务。所采用数据集总数据量超过40w,包含31列变量信息,其中15列为匿名变量。从中抽取出15万条作为训练集,5万条作为测试集A,5万条作为测试集B,同时对name、model、brand和regionCode等敏感信息进行脱敏。
Field | Description |
---|---|
SaleID | 交易ID,唯一编码 |
name | 汽车交易名称,已脱敏 |
regDate | 汽车注册日期 |
model | 车型编码,已脱敏 |
brand | 汽车品牌,已脱敏 |
bodyType | 车身类型 |
fuelType | 燃油类型 |
gearbox | 变速箱 |
power | 发动机功率 |
kilometer | 汽车已行驶公里 |
notRepairedDamage | 汽车有尚未修复的损坏 |
regionCode | 地区编码,已脱敏 |
seller | 销售方 |
offerType | 报价类型 |
creatDate | 汽车上线时间 |
price | 二手车交易价格(预测目标) |
v系列特征 | 匿名特征,包含v0-14在内15个匿名特征 |
对数据集进行缺失值处理等预处理,并对数据集进行分析(数据总览,分布情况等)及可视化。
此问题为回归问题,我们拟采用两种不同的算法(如线性回归模型,决策树等)对其进行预测,并对预测结果进行对比。
利用数据集中的不同属性建立模型并利用模型实现对测试集数据中二手车价格的预测。
本项目最后采用MAE(Mean Absolute Error)作为评价标准:
$$MAE = \frac{\sum_{i=1}^{n}\left | y_{i} - \hat{y}_{i}\right |}{n}$$MAE越小,说明模型预测越准确。
仓库地址:https://github.com/Zening-Li/BIT_DataMining_project
数据集
代码及结果展示
%matplotlib inline
import pandas as pd
import numpy as np
from datetime import datetime
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
pd.set_option('display.max_columns', None)
sns.set(style='whitegrid')
plt.style.use('seaborn-darkgrid')
plt.rcParams['font.sans-serif']=['simhei'] # 用黑体显示中文
plt.rcParams['axes.unicode_minus']=False # 正常显示负号
train = pd.read_csv('./data/used_car_train_20200313.csv', sep=' ')
test = pd.read_csv('./data/used_car_testB_20200421.csv', sep=' ')
SaleID - 交易ID,唯一编码
name - 汽车交易名称
regDate - 汽车注册时间
model - 车型编码
brand - 品牌
bodyType - 车身类型
fuelType - 燃油类型
gearbox - 变速箱
power - 汽车功率
kilometer - 汽车行驶公里
notRepairedDamage - 汽车有尚未修复的损坏
regionCode - 地区编码
seller - 销售方
offerType - 报价类型
creatDate - 广告发布时间
price - 汽车价格
v_0', 'v_1', ..., 'v_14' - 匿名特征,包含v0-14在内15个匿名特征
# 简略查看训练数据
train.head()
数值属性有发动机功率power,汽车已经行驶公里kilometer,二手车交易价格price以及15个匿名特征,而标称属性有汽车交易名称、车型编码、品牌、车身类型、燃油类型、变速箱、汽车有尚未修复损坏、地区编码、销售方、报价类型
train.shape
# 简略查看测试数据
test.head()
test.shape
# 通过describe()来熟悉训练数据数值属性的相关统计量
train_numeric_features = [
'power', 'kilometer', 'price', 'v_0', 'v_1', 'v_2', 'v_3', 'v_4', 'v_5', 'v_6',
'v_7', 'v_8', 'v_9', 'v_10', 'v_11', 'v_12', 'v_13', 'v_14'
]
train[train_numeric_features].describe()
# 通过describe()来熟悉测试数据数值属性的相关统计量
test_numeric_features = [
'power', 'kilometer', 'v_0', 'v_1', 'v_2', 'v_3', 'v_4', 'v_5', 'v_6',
'v_7', 'v_8', 'v_9', 'v_10', 'v_11', 'v_12', 'v_13', 'v_14'
]
test[test_numeric_features].describe()
# 通过info()来熟悉训练数据类型
train.info()
# 可视化训练数据中的数值属性
f_train = pd.melt(train, value_vars=train_numeric_features)
g_train = sns.FacetGrid(f_train, col="variable", col_wrap=3, sharex=False, sharey=False)
g_train = g_train.map(sns.distplot, "value")
plt.show()
'price'为长尾分布,需要对其做数据转换
'power'应该存在异常值,需要处理
# 可视化测试数据中的数值属性
f_test = pd.melt(test, value_vars=test_numeric_features)
g_test = sns.FacetGrid(f_test, col="variable", col_wrap=3, sharex=False, sharey=False)
g_test = g_test.map(sns.distplot, "value")
plt.show()
# 分析训练数据类别特征nunique分布
category_features = [
'name', 'model', 'brand', 'bodyType', 'fuelType', 'gearbox',
'notRepairedDamage', 'regionCode', 'seller', 'offerType', 'regionCode'
]
for feature in category_features:
print(feature + "的特征分布如下:")
print("{}特征有个{}不同的值".format(feature, train[feature].nunique()))
print(train[feature].value_counts())
print(72 * '-')
# 对训练数据类别特征取值较少的,画出直方图
plt.figure(figsize=(15, 12))
i = 1
for feature in category_features:
if train[feature].nunique() < 50:
plt.subplot(4, 2, i)
i += 1
v = train[feature].value_counts()
fig = sns.barplot(x=v.index, y=v.values)
plt.title(feature)
plt.tight_layout()
plt.show()
# 分析测试数据类别特征nunique分布
for feature in category_features:
print(feature + "的特征分布如下:")
print("{}特征有个{}不同的值".format(feature, test[feature].nunique()))
print(test[feature].value_counts())
print(72 * '-')
# 对测试数据类别特征取值较少的,画出直方图
plt.figure(figsize=(15, 12))
i = 1
for feature in category_features:
if test[feature].nunique() < 50:
plt.subplot(4, 2, i)
i += 1
v = test[feature].value_counts()
fig = sns.barplot(x=v.index, y=v.values)
plt.title(feature)
plt.tight_layout()
plt.show()
可以发现两个类别特征严重倾斜,分别是销售方seller和报价类型offerType,上述两个特征对分析预测没有任何帮助。
另外,汽车有尚未修复的损坏notRepairedDamage有3个不同的属性值:0.0,1.0,'-',其中'-'应该也为空值。
# 'notRepairedDamage'属性中'-'应该也是空值,用nan替换
train['notRepairedDamage'].replace('-', np.nan, inplace=True)
test['notRepairedDamage'].replace('-', np.nan, inplace=True)
# 分析训练数据缺失值
train.isnull().sum()[train.isnull().sum() > 0]
# 训练数据nan可视化
train_missing = train.isnull().sum()
train_missing = train_missing[train_missing > 0]
train_missing.sort_values(inplace=True)
train_missing.plot.bar()
plt.title("训练数据nan可视化")
plt.show()
# 分析测试数据缺失值
test.isnull().sum()[test.isnull().sum() > 0]
# 测试数据nan可视化
test_missing = test.isnull().sum()
test_missing = test_missing[test_missing > 0]
test_missing.sort_values(inplace=True)
test_missing.plot.bar()
plt.title("测试数据nan可视化")
plt.show()
# 对'price'属性进行相关性分析
price_numeric = train[train_numeric_features]
correlation = price_numeric.corr()
print(correlation['price'].sort_values(ascending = False),'\n')
f, ax = plt.subplots(figsize=(8, 8))
plt.title('Correlation of Numeric Features with Price', y=1, size=16)
sns.heatmap(correlation, square=True, vmax=0.8, linewidths=0.1, cmap=sns.cm.rocket_r)
plt.show()
匿名特征v_0, v_3, v_8, v_12与'price'相关性很高
# price 为长尾分布,对该特征进行处理
train['price'] = np.log1p(train['price'])
# 可视化处理后'price'分布
plt.figure(figsize=(10, 8))
sns.distplot(train['price'])
plt.show()
# 合并训练数据和测试数据,方便后续数据预处理
df = pd.concat([train, test], axis=0, ignore_index=True)
df.head()
# SaleID为交易ID,肯定没用,但是我们可以用来统计别的特征的group数量
# name为汽车交易名称,已经脱敏一般没什么好挖掘的,不过同名的好像不少,可以挖掘一下
df['name_count'] = df.groupby(['name'])['SaleID'].transform('count')
df.drop(['name'], axis=1, inplace=True)
# 'seller'、'offerType'特征严重倾斜,训练数据中'seller'有一个特殊值,删除该样本
df.drop(df[df['seller'] == 1].index, inplace=True)
df.drop(['seller'], inplace=True, axis=1)
df.drop(['offerType'], inplace=True, axis=1)
# 在题目中规定了power范围为[0, 600]
df['power'] = df['power'].map(lambda x: 600 if x > 600 else x)
# 可视化处理后'power'分布
plt.figure(figsize=(10, 8))
sns.distplot(df['power'])
plt.show()
# 查看缺失值
df.isnull().sum()[df.isnull().sum() > 0]
# 用众数填充缺失值
df.fuelType.fillna(df.fuelType.mode()[0], inplace=True)
df.gearbox.fillna(df.gearbox.mode()[0], inplace=True)
df.bodyType.fillna(df.bodyType.mode()[0], inplace=True)
df.model.fillna(df.model.mode()[0], inplace=True)
df.notRepairedDamage.fillna(df.notRepairedDamage.mode()[0], inplace=True)
df.isnull().sum()[df.isnull().sum() > 0]
df是由训练数据和测试数据合并而来,测试数据有50000个样本,预测特征是price,因此df中存在50000个缺失price特征的样本
def date_process(x):
year = int(str(x)[:4])
month = int(str(x)[4:6])
day = int(str(x)[6:8])
if month < 1:
month = 1
date = datetime(year, month, day)
return date
df['regDates'] = df['regDate'].apply(date_process)
df['creatDates'] = df['creatDate'].apply(date_process)
df['regDate_year'] = df['regDates'].dt.year
df['regDate_month'] = df['regDates'].dt.month
df['regDate_day'] = df['regDates'].dt.day
df['creatDate_year'] = df['creatDates'].dt.year
df['creatDate_month'] = df['creatDates'].dt.month
df['creatDate_day'] = df['creatDates'].dt.day
# 切割数据,导出数据
output_path = './process_data/'
print(df.shape)
train_num = df.shape[0] - 50000
df[:int(train_num)].to_csv(output_path + 'train_data_v1.csv', index=False, sep=' ')
df[train_num:train_num + 50000].to_csv(output_path + 'test_data_v1.csv', index=False, sep=' ')
数据集
代码实现
说明
代码实现
见下方所示
可视化过程
import numpy as np
import pandas as pd
import seaborn as sns
import lightgbm as lgb
import matplotlib.pyplot as plt
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.metrics import mean_squared_error, mean_absolute_error
from sklearn.linear_model import LinearRegression, Ridge, LassoCV
from sklearn.model_selection import train_test_split, GridSearchCV
%matplotlib inline
# train_data = pd.read_csv('data/train_data_v1.csv', sep=' ')
# test_data = pd.read_csv('data/test_data_v1.csv', sep=' ')
train_data = pd.read_csv(r"C:\Users\shl\Desktop\train_data_v1.csv", sep=' ')
test_data = pd.read_csv(r"C:\Users\shl\Desktop\test_data_v1.csv", sep=' ')
print(train_data.shape)
print(test_data.shape)
train_data.head()
train_data.describe()
numerical_cols = train_data.select_dtypes(exclude = 'object').columns
print(numerical_cols)
feature_cols = [x for x in train_data.columns if x not in ['SaleID','name','regDates','creatDates','price','model','brand','regionCode','creatDate']]
train_X = train_data[feature_cols]
test_X = test_data[feature_cols]
train_Y = train_data['price']
print('X train shape:',train_X.shape)
print('X test shape:',test_X.shape)
print('Y train shape:',train_Y.shape)
x_train, x_val, y_train, y_val = train_test_split(train_X, train_Y, test_size=0.3)
# 线性回归
model_1 = LinearRegression()
model_1.fit(x_train, y_train)
pred_1 = model_1.predict(x_val)
mae_1 = mean_absolute_error(y_val, pred_1)
print('MAE = ', mae_1)
# 可视化预测结果
# 由于'v_12' ,'v_8', 'v_0'与price相关度较高所以进行可视化观察
for i in ['v_12' ,'v_8', 'v_0']:
plt.scatter(x_val[i], y_val, color='red')
plt.scatter(x_val[i], pred_1, color='blue')
plt.xlabel(i)
plt.ylabel('price')
plt.show()
# 岭回归
model_2 = Ridge(alpha=0.8)
model_2.fit(x_train, y_train)
pred_2 = model_2.predict(x_val)
mae_2 = mean_absolute_error(y_val, pred_2)
print('MAE = ', mae_2)
# 可视化预测结果
# 由于'v_12' ,'v_8', 'v_0'与price相关度较高所以进行可视化观察
for i in ['v_12' ,'v_8', 'v_0']:
plt.scatter(x_val[i], y_val, color='red')
plt.scatter(x_val[i], pred_2, color='blue')
plt.xlabel(i)
plt.ylabel('price')
plt.show()
# Lasso回归
model_3 = LassoCV()
model_3.fit(x_train, y_train)
pred_3 = model_3.predict(x_val)
mae_3 = mean_absolute_error(y_val, pred_3)
print('MAE = ', mae_3)
# 可视化预测结果
# 由于'v_12' ,'v_8', 'v_0'与price相关度较高所以进行可视化观察
for i in ['v_12' ,'v_8', 'v_0']:
plt.scatter(x_val[i], y_val, color='red')
plt.scatter(x_val[i], pred_3, color='blue')
plt.xlabel(i)
plt.ylabel('price')
plt.show()
从可视化中可以看出Lasso回归的预测price值全是中间值,高price和低price很少。可能是由于该方法是一种压缩估计,压缩了一些回归系数,得到的是一个较为精炼的模型。从MAE值也可以看出,Lasso回归是最高的。
# GDBT
gdbt = GradientBoostingRegressor()
gdbt.fit(x_train, y_train)
pred_4 = gdbt.predict(x_val)
mae_4 = mean_absolute_error(y_val, pred_4)
print('MAE = ', mae_4)
# 可视化预测结果
# 由于'v_12' ,'v_8', 'v_0'与price相关度较高所以进行可视化观察
for i in ['v_12' ,'v_8', 'v_0']:
plt.scatter(x_val[i], y_val, color='red')
plt.scatter(x_val[i], pred_4, color='blue')
plt.xlabel(i)
plt.ylabel('price')
plt.show()
# LightGBM
estimator = lgb.LGBMRegressor(num_leaves=63, n_estimators=100)
param_grid = {
'learning_rate': [0.01, 0.05, 0.1],
}
gbm = GridSearchCV(estimator, param_grid)
gbm.fit(x_train, y_train)
pred_5 = gbm.predict(x_val)
mae_5 = mean_absolute_error(y_val, pred_5)
print('MAE = ', mae_5)
# 可视化预测结果
# 由于'v_12' ,'v_8', 'v_0'与price相关度较高所以进行可视化观察
for i in ['v_12' ,'v_8', 'v_0']:
plt.scatter(x_val[i], y_val, color='red')
plt.scatter(x_val[i], pred_5, color='blue')
plt.xlabel(i)
plt.ylabel('price')
plt.show()
LightGBM算法MAE值最小,即效果最好。从可视化也可以看出其预测结果很好。对于v_12属性,其他算法效果都不是很好,LightGBM算法则很好。
estimator = lgb.LGBMRegressor(num_leaves=63, n_estimators=100)
param_grid = {
'learning_rate': [0.01, 0.05, 0.1],
}
pred_model = GridSearchCV(estimator, param_grid)
pred_model.fit(train_X, train_Y)
price = pred_model.predict(test_X)
submit = pd.DataFrame()
submit['SaleID'] = test_data.SaleID
submit['price'] = price
submit.to_csv('output/submit.csv',index=False)
submit.head(10)
数据集
代码实现
说明
使用回归决策树模型
训练集中,根据creatDates和creatDates计算得到used_time
作为特征的属性包括:
["bodyType","brand","fuelType","gearbox","kilometer",'model', 'notRepairedDamage', 'power', 'regDate',
'v_0'- 'v_9', 'name_count','used_time']
训练集80%的数据用于训练,20%用于评价模型,使用AE和决定系数R^2评价模型
最后使用模型预测测试集,结果保存在output/algo2_predict.csv文件中
代码实现
如下方所示
可视化过程
import matplotlib
import numpy as np
import pandas as pd
%matplotlib inline
from matplotlib import pyplot as plt
from sklearn import tree
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error
from sklearn.preprocessing import StandardScaler
from xgboost.sklearn import XGBRegressor
from sklearn.ensemble import RandomForestRegressor
import joblib
读入经过预处理的数据
train_path = "data/train_data_v1.csv"
train_data = pd.read_csv(train_path,sep=" ")
test_path = "data/test_data_v1.csv"
test_data = pd.read_csv(test_path,sep=" ")
data = train_data.copy(deep=True)
选择作为特征的属性如choosed_attris所列出,根据检验推测二手车的使用时间与其价格应该成反比,所以计算regdate和createdate的差得到车辆的使用时间,也作为其中一个特征。
data['used_time'] = (pd.to_datetime(data['creatDates'], format='%Y-%m-%d', errors='coerce') -
pd.to_datetime(data['regDates'], format='%Y-%m-%d', errors='coerce')).dt.days
choosed_attris = ["bodyType","brand","kilometer",
'model', 'notRepairedDamage', 'power',
'v_0', 'v_1', 'v_10', 'v_11', 'v_12', 'v_13', 'v_14',
'v_2', 'v_3', 'v_4', 'v_5', 'v_6', 'v_7', 'v_8', 'v_9',
'regDate_year',
'name_count','used_time']
train = data[choosed_attris]
label = data["price"]
train
label
将构建好的数据集划分为训练集<x_train, y_train>和验证集<x_train, y_train>两部分,并将划分前后的这些数据全部转储到文件中。
x_train, x_test, y_train, y_test = train_test_split(train, label, test_size=0.2)
joblib.dump(train, "dataset/train.csv")
joblib.dump(label, "dataset/label.csv")
joblib.dump(x_train, "dataset/x_train.csv")
joblib.dump(x_test, "dataset/x_test.csv")
joblib.dump(y_train, "dataset/y_train.csv")
joblib.dump(y_test, "dataset/y_test.csv")
在最初实现中,使用回归决策树模型进行预测,但是最终的效果还是不够好。所以进一步测试使用随机森林分类器和构建预测模型。
随机森林属于Bagging类算法,在训练阶段,随机森林使用bootstrap采样从输入训练数据集中采集多个不同的子训练数据集来依次训练多个不同决策树;在预测阶段,随机森林将内部多个决策树的预测结果取平均得到最终的结果。
XGBoost算法特征分裂来生长一棵树,每一轮学习一棵树,其实就是去拟合上一轮模型的预测值与实际值之间的残差。当我们训练完成得到k棵树时,我们要预测一个样本的分数,其实就是根据这个样本的特征,在每棵树中会落到对应的一个叶子节点,每个叶子节点就对应一个分数,最后只需将每棵树对应的分数加起来就是该样本的预测值。
def train_decision_tree_regressor(x_train, y_train):
dr = tree.DecisionTreeRegressor()
dr.fit(x_train, y_train)
return dr
def train_random_forest_regressor(x_train, y_train):
#rfr = RandomForestRegressor(n_estimators=80, max_depth=25 )
rfr = RandomForestRegressor(n_estimators=80,)
rfr.fit(x_train, y_train)
return rfr
def train_XGBRegressor(x_train, y_train):
gbm= XGBRegressor()
gbm.fit(x_train, y_train)
return gbm
加载保存的x_train, y_train,训练模型
def load_dataset():
paths = ["dataset/x_train.csv", "dataset/x_test.csv","dataset/y_train.csv", "dataset/y_test.csv"]
x_train, x_test, y_train, y_test = [joblib.load(x) for x in paths]
return x_train, x_test, y_train, y_test
x_train, x_test, y_train, y_test = load_dataset()
执行本目录下的algo2.py文件,开始训练模型,并将模型保存在models目录下。
if sys.argv[1] == "xgbt":
drm = train_XGBRegressor(x_train, y_train)
pkl_name = "XGBRegressor"
if sys.argv[1] == "tree":
drm = train_decision_tree_regressor(x_train, y_train)
pkl_name = "train_decision_tree_regressor"
if sys.argv[1] == "forest":
drm = train_random_forest_regressor(x_train, y_train)
pkl_name = "train_forest_regressor"
else:
sys.exit(0)
t1 = time.time()
print("excute_time: %f"%round(t1 - t0, ndigits=4))
print("dumping model")
joblib.dump(drm, "models/"+pkl_name+".pkl")
载入训练后的模型,使用验证集<x_test,y_test>计算模型的MAE,MAE越小,说明模型预测得越准确。。
import joblib
dtr = joblib.load("models/train_decision_tree_regressor.pkl")
rfr = joblib.load("models/train_forest_regressor.pkl")
xgbr = joblib.load("models/XGBRegressor.pkl")
x_train, x_test, y_train, y_test = load_dataset()
predict_test = dtr.predict(x_test)
mae_result = []
print(mean_absolute_error(predict_test, y_test))
print(mean_absolute_error(np.expm1(predict_test), np.expm1(y_test)))
mae_result.append(mean_absolute_error(np.expm1(predict_test), np.expm1(y_test)))
# 由于'v_12' ,'v_8', 'v_0'与price相关度较高所以进行可视化观察
for i in ['v_12' ,'v_8', 'v_0']:
plt.scatter(x_test[i], y_test, color='red')
plt.scatter(x_test[i], predict_test, color='blue')
plt.xlabel(i)
plt.ylabel('price')
plt.show()
predict_test = rfr.predict(x_test)
print(mean_absolute_error(predict_test, y_test))
print(mean_absolute_error(np.expm1(predict_test), np.expm1(y_test)))
mae_result.append(mean_absolute_error(np.expm1(predict_test), np.expm1(y_test)))
# 由于'v_12' ,'v_8', 'v_0'与price相关度较高所以进行可视化观察
for i in ['v_12' ,'v_8', 'v_0']:
plt.scatter(x_test[i], y_test, color='red')
plt.scatter(x_test[i], predict_test, color='blue')
plt.xlabel(i)
plt.ylabel('price')
plt.show()
predict_test = xgbr.predict(x_test)
print(mean_absolute_error(predict_test, y_test))
print(mean_absolute_error(np.expm1(predict_test), np.expm1(y_test)))
mae_result.append(mean_absolute_error(np.expm1(predict_test), np.expm1(y_test)))
# 由于'v_12' ,'v_8', 'v_0'与price相关度较高所以进行可视化观察
for i in ['v_12' ,'v_8', 'v_0']:
plt.scatter(x_test[i], y_test, color='red')
plt.scatter(x_test[i], predict_test, color='blue')
plt.xlabel(i)
plt.ylabel('price')
plt.show()
#plt.figure(figsize=(8,4),dpi=80)
fig, ax = plt.subplots(figsize=(8,4))
x = ["decision_tree_regressor","random_forest_regressor","XGBRegressor"]
y = mae_result
for a, b in zip(x, y):
ax.text(a, b+1, b, ha='center', va='bottom')
plt.bar(x, mae_result,label="2")
可以看出,相比于决策树,随机森林回归器和xgboost模型的MAE都得到显示降低,模型的预测性能得到提高。
最后,对随机森林回归树模型与xgbt回归模型进行简单的加权融合,计算MAE。
def Weighted_method(test_pre1,test_pre2,w=[1/2,1/2]):
Weighted_result = w[0]*pd.Series(test_pre1)+w[1]*pd.Series(test_pre2)
return Weighted_result
x_train, x_test, y_train, y_test = load_dataset()
m1 = rfr
m2 = xgbr
predict_1 = m1.predict(x_test)
predict_2 = m2.predict(x_test)
predict_test = Weighted_method(predict_1, predict_2)
print(mean_absolute_error(predict_test, y_test))
print(mean_absolute_error(np.expm1(predict_test), np.expm1(y_test)))
MAE有所减小。因此,最终的模型使用随机森林回归树模型与xgbt回归模型预测的均值作为二手车价格的预测值。
使用最终模型在测试集data/test_data_v1.csv进行预测。
test_path = "data/test_data_v1.csv"
test_data = pd.read_csv(test_path,sep=" ")
test_data['used_time'] = (pd.to_datetime(test_data['creatDates'], format='%Y-%m-%d', errors='coerce') -
pd.to_datetime(test_data['regDates'], format='%Y-%m-%d', errors='coerce')).dt.days
test_data_features = test_data[["bodyType","brand","kilometer",
'model', 'notRepairedDamage', 'power',
'v_0', 'v_1', 'v_10', 'v_11', 'v_12', 'v_13', 'v_14',
'v_2', 'v_3', 'v_4', 'v_5', 'v_6', 'v_7', 'v_8', 'v_9',
'regDate_year',
'name_count','used_time']]
model = joblib.load("models/train_forest_regressor.pkl")
model2 = joblib.load("models/XGBRegressor.pkl")
#预测
p1 = model.predict(test_data_features)
p2 = model2.predict(test_data_features)
price = Weighted_method(p1, p2)
#生成用于提交的csv文件
output = pd.DataFrame()
output['SaleID'] = test_data.SaleID
output['price'] = np.expm1(price)
output.to_csv('output/submmit_stack.csv',index=False)
测试集预测结果的MAE为578.4769
感谢老师这一学期以来的付出和教导,尽管由于疫情的原因无法当面向您请教,但在您的指导和帮助下,我们都顺利地完成了课程的学习,并且收获很大,尤其是四次互评作业以及最终的大作业,很好地锻炼了我们代码的实际编写能力,这种方式的教学我们认为会比单纯的考试有用得多。通过您的课程,我们真的学到了很多,再一次感谢您!祝老师工作顺利、身体安康、阖家幸福!