用python预测车牌价格_利用python预测二手车售价

思路:影响二手汽车售价的特征很多,比如汽车品牌,汽车性能,上牌年限等,同样的零部件参数,不一样的品牌,对应的售价是不一样的,而车的品牌众多,不在参数范围之内,所以本文将售价与新车价的比例作为目标进行分析预测。正文提供了三种求解方法:K近邻,线性回归,随机森林,以均方根误差为评判标准。

一:数据来源

瓜子二手车北京地区的二手车售卖信息。

本数据只包含了基本信息,其它参数未进行爬取。

import numpy as np

import pandas as pd

import matplotlib.pyplot as plt

%matplotlib inline

df = pd.read_excel("北京二手车.xlsx")

二:数据清洗

1.我们将上牌时间与2018年8月的时间差记为使用时间的长短,并将其他字段的字符中提取有用的信息

df['time'] = '2018-08'

df['使用时间'] = (pd.to_datetime(df.time)-pd.to_datetime(df.上牌时间)).map(lambda x :x.days)#单位是天

df['里程'] = df['里程数'].str[:-3]

df['排标'] = df.排放标准.str[:2]

df['过户次数'] = df.过户次数.str[0].astype(int)

df['售价'] = df.保价.str.strip('万').str[1:].astype(float)

df['原价'] = df.新车价.str.strip('新车指导价').str.strip('万(含税)').astype(float)

df.drop(['上牌时间','time','里程数','排放标准','保价','新车价','车名','时间急迫度'],axis=1,inplace = True)

得到初步清洗的数据

接下来将文字数字化

label_mapping = {"自动": 1, "手动": 0}

df['变速箱'] = df.变速箱.map(label_mapping)

label_mapping = {"国四": 4, "国五": 5,"国三": 3, "国二": 2}

df['排标'] = df.排标.map(label_mapping)

得到如下数据:

因为在日常中进行时间估计不会说我的车开了多少天,基本都是一年半,两年之类的大概说法,想将使用时间按年(365天)换算。一样的指标不一样的品牌也会导致原价不一样,售价不一样,故此我们以售价与原价的占比为目标进行估计。

注意到数据中含有空值,且“原价”字段中空值最多,但数量比较少,故删去。

df.dropna(inplace = True)

df['占比'] = round(df.售价/df.原价,2) #保留2位小数

df['时间'] = round(df.时间/365,1) #保留1一位小数

df.drop(['售价','原价'],axis=1,inplace = True)

得到最终清洗好的数据集干净的数据集

三:特征选取

虽然特征不多,但是也要进行特征工程,特征共线性对于一些模型(比如线性回归)影响很大,也去掉一些无用特征,使得模型的拟合能力更强。

先来看一下各个特征对于目标的分布:

mpl.rcParams['font.sans-serif'] = 'FangSong' # 中文字体设置-仿宋

mpl.rcParams['axes.unicode_minus'] = False

for i in df.columns[:-1]:

fig,ax = plt.subplots(1,1,figsize=(18,4))

df_1=df[['占比',i]].groupby([i],as_index=False).mean()

ax.set_xlabel(i,fontsize = 45)

ax.set_ylabel('占比',fontsize = 45)

sns.barplot(x=i,y='占比',data=df_1)

从上图图看汽车排量对于售价的影响不大,后续建模可以考虑将其删去

上图可知,虽不明显,但是随着过户次数增多,汽车售价降低

由上图发现,自动挡的车比手动挡车更值钱,平均售价更高

很明显,用车年限对于车的售价起着至关重要的作用

行驶的里程数越高,售价越低,对于目标的影响明显

汽车排放标准越高越值钱,排放标准对于售价影响很大

接着来看各个特诊之间是否具有线性关系:

Correlation = pd.DataFrame(df[['排量','过户次数','变速箱','使用时间','里程','排标']])

colormap = plt.cm.viridis

plt.figure(figsize=(14,12))

plt.title('Pearson Correaltion of Feature',y=1.05,size=15)

sns.heatmap(Correlation.astype(float).corr(),linewidths=0.1,vmax=1.0,square=True,cmap=colormap,linecolor='white',annot=True,xticklabels = True)

发现使用年限和里程数具有很大的相关性,后续建模可以考虑去掉里程数这一特征。

四:建模预测

1.KNN模型:

from sklearn.preprocessing import StandardScaler

from sklearn.neighbors import KNeighborsRegressor

from sklearn.metrics import mean_squared_error

features = ['排量','过户次数','变速箱','使用时间','里程','排标']

df1 = df.copy()

df1[features] = StandardScaler().fit_transform(df1[features])

df1_train = df1.iloc[:3000]

df1_test = df1.iloc[3000:]

def k():

knn = KNeighborsRegressor(5)

knn.fit(df1_train[features], df1_train['占比'])

predictions = pd.DataFrame(knn.predict(df1_test[features]))

predictions = round(predictions,2)

mse = mean_squared_error(df1_test['占比'], predictions)

rmse = mse ** (1/2)

score = knn.score(df1_test[features], df1_test['占比'])

print(features)

print("rmse",rmse)

print("score",score)

print("-"*40)

可以看到当特征为'过户次数','变速箱','使用时间','里程','排标'时,模型rmse最低

2.sklearn线性回归预测

#线性回归模型

from sklearn import linear_model

features = ['排量','过户次数','变速箱','使用时间','里程','排标']

df2=df.copy()

df2[features] = StandardScaler().fit_transform(df2[features])

df2_train = df2.iloc[:3000]

df2_test = df2.iloc[3000:]

def L():

model = linear_model.LinearRegression()

model.fit(df2_train[features], df2_train['占比'])

result = pd.DataFrame(model.predict(df2_test[features]))

result = round(result,2)

mse = mean_squared_error(df2_test['占比'], result)

rmse = mse ** (1/2)

score = model.score(df2_test[features], df2_test['占比'])

print(features)

print("rmse",rmse)

print("score",score)

print("theta",model.coef_ )

print("截距",model.intercept_)

print("-"*40)

theta值为负,意味着负相关,即过户次数、里程数、使用时间三特征与售价呈负相关,按照我们的常识,当然三手比二手便宜,开的时间和里程越久汽车的价值越低。

3.随机森林

from sklearn.ensemble import RandomForestRegressor

features = ['排量','过户次数','变速箱','使用时间','里程','排标']

df4 = df.copy()

df4[features] = StandardScaler().fit_transform(df4[features])

df4_train = df4.iloc[:3000]

df4_test = df4.iloc[3000:]

rfr = RandomForestRegressor(n_estimators = 20,max_features = 3)

rfr.fit(df4_train[features],df4_train['占比'])

result3 = pd.DataFrame(rfr.predict(df4_test[features]))

mse = mean_squared_error(df4_test['占比'], y_pred)

rmse = mse ** (1/2)

随机森林暂不做调参,本文仅供参考

3.融合以上三个模型:将三个模型的预测值求平均

比较两个模型的rmse值,以['过户次数', '变速箱', '使用时间', '里程', '排标']为特征比较好。

#融合两个模型,以['过户次数', '变速箱', '使用时间', '里程', '排标']为特征

features = ['过户次数','变速箱','使用时间','里程','排标']

df6=df.copy()

df6[features] = StandardScaler().fit_transform(df2[features])

df6_train = df6.iloc[:3000]

df6_test = df6.iloc[3000:]

model = linear_model.LinearRegression()

model.fit(df6_train[features], df6_train['占比'])

result1 = pd.DataFrame(model.predict(df6_test[features]))

knn = KNeighborsRegressor(5)

knn.fit(df6_train[features], df6_train['占比'])

result2 = pd.DataFrame(knn.predict(df6_test[features]))

result = (result1 + result2 + result3)/3

mse = mean_squared_error(df6_test['占比'], result)

rmse = mse ** (1/2)

print(rmse)

rmse 降低至

可见多个模型预测可降低标准差,模型得到优化。

四 总结:

二手车的售价与里程数、已使用年限、过户次数负相关。与排放标准、排量、变速箱正相关,即排量越大(印象里面豪车都是大排量)、自动、排放标准越大售价定的比例更高(排放标准越高代表废气排放越少)。多模型的融合可降低均方根误差。

当然线性方程也可采用梯度下降求解:(仅当做求解参考,可忽视。)

#建立目标函数模型

def model(X, theta):

return np.dot(X, theta.T)

#定义X,y(target)

df3 = df.copy()

df3.insert(0, 'Ones', 1)

df3_train = df3.iloc[:3000]

df3_test = df3.iloc[3000:]

train = df3_train.as_matrix()

test = df3_test.as_matrix()

cols = train.shape[1]

X = train[:,0:cols-1]

y = train[:,cols-1:cols]

#对于theta赋予初始值,这里赋值为0

theta = np.zeros([1, 7]) #一共7个参数

#定义损失函数

def cost(X, y, theta):

errors =(model(X, theta)-y)**2

return np.sum(errors)/len(X)

#计算梯度

def gradient(X, y, theta):

grad = np.zeros(theta.shape)#每一个参数对应一个下降梯度

error = (model(X, theta)- y).ravel()

for j in range(len(theta.ravel())): #for each parmeter

term = np.multiply(error, X[:,j])

grad[0, j] = np.sum(term) / len(X)

return grad

#梯度下降求解

#iters为梯度下降计算次数,以迭代次数为终止策略,当然也能以损失值小于多少为终止策略或以时间限度为终止策略

#alpha为学习率

import time

def descent(X,y,theta,iters,alpha):

i = 0 #迭代次数

init_time = time.time()

grad = np.zeros(theta.shape) # 计算的梯度

costs = [cost(X, y, theta)] # 损失值

while True:

grad = gradient(X, y, theta) #计算梯度

theta = theta - alpha*grad #更新参数theta

costs.append(cost(X, y, theta)) # 计算新的损失

i += 1

if i >iters: #迭代终止

break

return theta, costs, i-1,grad, time.time() - init_time

#梯度下降可视化(损失与迭代次数)

from matplotlib import pyplot as plt

iters = 5000

theta,costs,n,grad,times = descent(X,y,theta,iters,0.0001)

fig, ax = plt.subplots(figsize=(12,4))

ax.plot(np.arange(n+2), costs, 'r')

ax.set_xlabel('Iterations')

ax.set_ylabel('Cost')

ax.set_title( 'Error vs. Iteration (spent %.2f s)'%times)

可以看到学习率偏大,下降的很快,迭代五千次基本收敛于0.01左右。

将alpha 降为 0.00001,得到如下曲线

计算rsme:

#当学习率是0.00001时,theta=array([[0.00750955, 0.01538768, 0.00186182, 0.00707161, 0.0132343 ,0.01844291, 0.03455897]])

X_test = test[:,0:cols-1]

y_test = test[:,cols-1:cols]

mse = mean_squared_error(y_test, model(X_test,theta))

rmse = mse ** (1/2)

#rmse = 0.3092584574922207

对比rsme,梯度下降的值比前两者较大,说明梯度下降还有待优化,考虑到篇幅过长,但此处不再分析优化。

或者直接用线性方程求解:

直接给出theta的求解方程

from numpy.linalg import inv

X = train[:,0:cols-1]

y = train[:,cols-1:cols]

#计算rsme

theta = np.dot(np.dot(inv(np.dot(X.T, X)), X.T), y)

#theta = array([[ 0.56614127],[ 0.00770775],[-0.006578 ],[ 0.03765713],[-0.04862077],[-0.00399016],[ 0.02989723]]

X_test = test[:,0:cols-1]

y_test = test[:,cols-1:cols]

mse = mean_squared_error(y_test, model(X_test,theta.T))

rmse = mse ** (1/2)

#rmse = 0.0839764322871155

线性方程直接求出来的结果和sk-learn算出来的结果十分相似,当线性相关的时候直接用方程求解是十分便利的。但是有一个缺陷:有时候未必有解。

文章可转载,请注明出处!

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值