深圳小汽车车牌竞拍价格预测
这几个月深圳小汽车车牌竞拍价格持续飙高,令人发指。
现在均价已经来到9.5万。如果能稍微预测得准一点,不仅可以增加拍中几率,而且可以省下近万块钱。于是我决定动用核武器……
不得不说深圳市政府还是很人性化的,往期的报价统计在这里可以查到:
http://xqctk.sztb.gov.cn/bszn/20171206/1512524976335_1.html
我们就以这些数据进行分析预测。
1 数据读取及基本分析
为便于处理,我将原始数据的列名都换成了英文,稍后我会解释。但列的顺序没有变。
此外,2015年第2期和第3期的投放指标与其他期相比差异太大,所以这两期数据舍弃,最后得到共33期数据。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['font.serif'] = ['SimHei']
data = pd.read_csv('sz_car_lic_auction.csv')
print(data.head())
No LicNum Applicant FirstOffer SecondOffer MinDealed Avg \
0 201501 3912 1578 15522 17021 10000 22173
1 201504 3880 10646 11198 11426 12000 13702
2 201505 2947 16393 13806 14321 17800 19496
3 201506 2937 19179 18143 19708 29100 31805
4 201507 2939 14948 27310 30113 49100 54237
MinOfferCnt MinDealedCnt LastOffer Dealed Paid
0 12 12 0.609829 1417 1333
1 1041 58 0.375576 3880 3866
2 88 82 0.619856 2947 2943
3 99 40 0.569745 2937 2931
4 19 10 0.566574 2939 2927
1.1 投放指标数
由下图可以看到,第7期开始投放数量基本稳定。我们以此后数据的均值作为投放量估计。
plt.plot(data.LicNum)
plt.xlabel('期数')
plt.ylabel('投放指标数')
plt.rc('font', family='SimHei', size=13)
plt.show()
print('投放量估计:%s' % np.mean(data.LicNum[7:]))
投放量估计:2943.1153846153848
1.2 播报均价
竞价当日11点和13点,系统会两次播报均价。此均价是除去报价最高的10%和报价最低的10%后的均价。
plt.plot(data.FirstOffer, label='第一次播报均价')
plt.plot(data.SecondOffer, label='第二次播报均价')
plt.xlabel('期数')
plt.ylabel('播报均价')
plt.legend()
plt.show()
可以看到,从第7期开始走势基本稳定。我们试着用3次多项式拟合播报均价的走势。
NumAuction = np.arange(7, len(data))
FirstOffer7 = data.FirstOffer[7:]
p1 = np.poly1d(np.polyfit(NumAuction, FirstOffer7, 3))
SecondOffer7 = data.SecondOffer[7:]
p2 = np.poly1d(np.polyfit(NumAuction, SecondOffer7, 3))
plt.plot(NumAuction, FirstOffer7, 'r+', label='第一次播报均价')
plt.plot(NumAuction, p1(NumAuction), 'r')
plt.plot(NumAuction, SecondOffer7, 'bo', label='第二次播报均价')
plt.plot(NumAuction, p2(NumAuction), 'b')
plt.xlabel('期数')
plt.ylabel('播报均价')
plt.legend()
plt.show()
print('第一次播报均价预测: %s' % p1(len(data)))
print('第二次播报均价预测: %s' % p2(len(data)))
第一次播报均价预测: 65138.52240802652
第二次播报均价预测: 70924.79933110328
1.3 成交价
当然其实我们最关注的的还是最低成交价和平均成交价。初步预测,可以一样像播报均价一样,用3次多项式进行预测。
有了前两次的经验,这次我们也取第7期及之后的数据。
MinDealed7 = data.MinDealed[7:]
pm = np.poly1d(np.polyfit(NumAuction, MinDealed7, 3))
Avg7 = data.Avg[7:]
pa = np.poly1d(np.polyfit(NumAuction, Avg7, 3))
plt.plot(NumAuction, MinDealed7, 'r+', label='最低成交价')
plt.plot(NumAuction, pm(NumAuction), 'r')
plt.plot(NumAuction, Avg7, 'bo', label='平均成交价')
plt.plot(NumAuction, pa(NumAuction), 'b')
plt.xlabel('期数')
plt.ylabel('成交价')
plt.legend()
plt.show()
print('最低成交价预测: %s' % pm(len(data)))
print('平均成交价预测: %s' % pa(len(data)))
最低成交价预测: 95485.41806020001
平均成交价预测: 105011.92307692222
1.4 有效编码数
有效编码数其实就是参加竞拍的人数(虽然不一定所有人都竞拍)。
可视化之后发现,这个差不多用2次多项式就能拟合。简单预测如下。
Applicant7 = data.Applicant[7:]
pp = np.poly1d(np.polyfit(NumAuction, Applicant7, 2))
plt.plot(NumAuction, Applicant7, 'r+', label='竞价人数')
plt.plot(NumAuction, pp(NumAuction), 'r')
plt.xlabel('期数')
plt.ylabel('竞价人数')
plt.legend()
plt.show()
print('竞价人数预测: %s' % pp(len(data)))
竞价人数预测: 11242.497692307721
2 线性回归预测平均成交价
之前做的都是基于历史数据的简单预测。但实际上,已知投放指标、两次播报平均价、竞价人数,再去预测平均成交价,才是更好的方法。
首先播报平均价就是去掉了报价最高最低各10%算出来的。而以最近一期为例,投放指标2968、竞价人数7665,报价最高的10%会占去1/4的指标。再假设报价是呈正态分布,其实差不多是能估算出均价甚至最低成交价的。
然而我数学并不好。所以我决定线性拟合一下……
之前我们也看到第一次和第二次的播报均价高度相关,这里只用其中一个即可,比如第二次播报均价。我们还是取第7期及以后的数据。
X = data.loc[7:, ['LicNum', 'Applicant', 'SecondOffer']]
y = data.loc[7:, ['Avg']]
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
linreg = LinearRegression()
linreg.fit(X_train, y_train)
print(linreg.intercept_, linreg.coef_)
[-420377.26140118] [[ 138.54092194 1.13717101 1.40703695]]
由于X已经是3维的了,不太好画图。不过模型训练完毕,我们还是可以看下模型的RMSE:
y_pred = linreg.predict(X_test)
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
print('测试集RMSE: %s' % rmse)
测试集RMSE: 4404.21317889
好吧,结果是不怎么理想……手动再见。
但无论如何最后还是要试一把的。根据之前得到的,假设本期2943个牌、竞拍人数11242、第二次播报均价70924,那么预测得到均价为:
X_now = np.mat([[2943, 11242, 70924]])
y_now = linreg.predict(X_now)
print('线性回归预测本次均价: %s' % y_now[0][0])
线性回归预测本次均价: 99925.4370278
差不多10万。算了半天和直接拍脑袋并没有什么鬼区别……
好了,那么问题来了,我现在每天上下班如果打车,加起来40元。假设一年工作222天,那么这些钱可以打多少年的车呢?
11年又3个月。
XX专车,邀您共享……(此处应有广告)
注:项目地址在https://github.com/mvpboss1004/sz_car_lic_auction