用机器学习自制二手房估价模型(附完整过程)
本篇会讲如何自制一个上海二手房估价模型,侧重于完整的实现过程和思路,而不是代码部分。完成后会用自己训练的模型来实战预测下Q房网的成交数据,并且对比下房产大数据平台的“房价网”的估价器。
所用到的python库:sickit-learn, numpy, pandas, matplotlib, beautifulsoup
机器学习到底是干什么的?
假设你有一位邻居老张,东北人,平时经常去市场买菜,其中买大白菜最多。由于老张这个人特别会过日子,不希望被摊位随便要价,他就准备自己研究下白菜的价格,买菜都带一个账本记账。买了5次以后记录下来白菜的价格是这样的:
重量(斤) | 价格(元) | |
---|---|---|
0 | 2.0 | 10 |
1 | 5.0 | 25 |
2 | 3.0 | 15 |
3 | 2.2 | 12 |
4 | 8.0 | 39 |
根据账本他推算了下白菜的价格,大约是5元一斤。如果买4斤白菜的话,正常价格应该是20元左右,这个特别简单。数学上描述这个关系是用一个线性方程y = ax,其中x代表白菜的斤数,y代表白菜的价格。a在这个案例里面等于5(每斤白菜的单价),而y = 5x就是白菜价格的模型。
现在老张觉得这个估价方法挺管用,由于价格猜测的准确也没有摊位敢胡乱开价。太平过了一段时间后,有一天他又去买菜,这次摊主却告诉他4斤白菜要28块了。老张很疑惑,问摊主原因。摊主说,哦,因为这批白菜比较新鲜,刚采摘下来不到24小时,所以卖的比较贵。而且,由于家里要买一块新菜地,为了增加点收入,以后白菜也都要按照新鲜程度来卖了…
这样一来,原来那个模型就没用了。于是老张又记录了一段时间的账本,与之前不同的是他这次还记录了白菜的新鲜程度。这个账本是这样的:
重量(斤) | 新鲜程度(天) | 价格(元) | |
---|---|---|---|
0 | 4.0 | 1 | 28 |
1 | 3.5 | 2 | 21 |
2 | 3.0 | 3 | 13 |
3 | 4.5 | 2 | 27 |
4 | 1.0 | 1 | 7 |
5 | 8.0 | 3 | 52 |
6 | 5.6 | 2 | 36 |
7 | 2.8 | 2 | 18 |
8 | 7.8 | 1 | 54 |
9 | 6.0 | 3 | 35 |
10 | 9.3 | 2 | 61 |
这么一看还是能隐约知道白菜的价格与斤数有关,但是似乎关系不那么明显了。现在老张怎么来估算白菜的价格哪?
其实白菜的价格分布还是有规律的。假设把老张的账本投射到一个三维空间里是这样的:
可以看到几乎所有的点在三维空间中都处于同一个平面范围上。根据高中数学我们会知道三维空间平面的表达式是z = ax + by + c。这里的a不再代表白菜的单价了,仅仅是白菜重量的系数。新的账本的表达式是z = 7x - 3.5y + 3.5。
这个白菜价格估算方法用的就是机器学习中最基础也最经典的一种算法,叫做【Linear Regression线性回归】。老张的账本在机器学习中叫做【训练数据集】,重量、新鲜程度等描述白菜属性的数值或者分类叫做【特征】。而求解模型中a,b,c参数具体数值,使得它对所有预测结果与真实值之间综合误差最小的过程就叫做模型的【拟合】。
这看起来很OK,可是你一定会说现实生活中的问题根本不是这样的啊!事实上老张可能会去多个摊位买菜,每次去哪个摊位都是随机的。又或者白菜有大有小,白菜大小也会影响价格。白菜也可能在冬天更便宜,夏天更贵等等…
说的没错,实际生活中我们往往需要多个特征来描述问题,对应一个多维以上的空间。数据分布也并非总是线性的,可能是一个曲面或者高维超曲面,数据也可能并不会正好都在某个曲面上等等。
这样问题就来了,大多数的人对高维想象都很难,怎么去解一个高维空间的问题哪?
这个时候计算机就发挥作用了。因为在机器“眼”里世界是数学抽象的,它不需要理解或者想象高维空间,只需要将低维空间的运算规则推广到高维空间即能处理一系列求解。
进一步,计算机寻找最佳参数的方式叫做【梯度下降法】(理解需要一点入门级别的微积分。)
这种方法很容易让我联想起曾经看过的一系列与时间循环有关的科幻电影。电影讲述主角被困于某段时间线中,每次死亡以后又都会回到时间线的最初。每次重生到再死亡的过程中也都会多获得关于事件一点的信息,最后所有拼凑起来的信息还原了事件的真相。
如果把电影中的每次重生到死亡的过程看成一次“迭代”,那么计算机寻找最佳参数的【梯度下降法】就是迭代,每次迭代都向最优方向前进一点点,当迭代非常多的次数后最终就能非常逼近最优参数。
这跟现实生活中人的学习方法很接近,所以机器学习叫machine learning而不叫machine fitting,或者machine predicting什么的…区别只是计算机的迭代时间可能1万次只用了几秒钟,而人类,因为现实中不会真的有时间循环让你去重复经历同一件事,可能在重大问题上迭代个几次大概一辈子就过去了…
所以,概括的说机器学习做的事情就是输入训练数据集,给定一种建模方式,计算机自动寻找最佳拟合参数使模型可以描述数据集中输入和输出的对应关系。并用这个模型来预测新输入数据的过程。
准备工作
既然已经知道机器学习是什么了,我们就要着手开始制作自己的模型了。参考上方关系图,我们需要准备点什么哪?
首先,我们需要一个开源库,不用自己写一大堆晦涩艰深的数学公式去指导机器计算,只要传参数就可以傻瓜式操作了。Python有一个机器学习的库Scikit-learn就很好用。为了熟悉库,需要看下使用文档。
我们还需要一台能计算的电脑,我就用了公司配发的低配行政笔记本电脑 。
解决特定领域问题的时候,该领域的专业知识会帮助你。比如,你要通过人脸表情照片去识别笑容,就需要了解一点图形学,知道计算机“看”照片是一个像素矩阵,每个像素点的灰度值是一个数字等等。
最后,就是最重要的数据源了。选择数据的质量和规模是直接影响模型表现的最重要因素。更多的时候可能我们想的到要解决哪些问题,却根本不知道从哪儿去找数据源…
这里我们选择做一个上海二手房的成交估价模型,因为相对数据更好采集。
采集还是通过爬虫来实现,对象则是最受广大爬虫玩家欢迎的房产网站“链家网”。动手采集前我们需要先看下链家“二手房成交”板块房产详情页,分析下大致哪些特征可能对判断成交价格有用。
区域,板块、小区名称、成交价格、成交日期这几项是必须采集的。挂牌价格、成交天数、带看、关注、浏览量这几项假设想进一步分析成交时间的话会有用,可采可不采。
户型、楼层、面积、朝向、梯户比这几项是直觉与价格有关的因素,所以采下来。
小区信息中建筑年份、物业费、总楼栋数和总户数这四个特征我们也认为与成交价格有关,所以采集下来。
这里你可能会问为啥没有采集“小区均价”哪?估算房价最直接的不应该是小区均价吗?其实是因为链家网站推算小区均价的逻辑,这里的小区均价计算的是“挂牌价格”的均价。留意下案例中这套房子,成交均价是46259元/平,并且成交时间就是离现在很近的9.30日。而小区的平均挂牌均价是57507元/平。直觉告诉我们房产虽然具有投资属性但并不可能在20天内有这样大规模的波动,既然我们研究的问题是成交,那么就以成交价格为准。
最后要采集的就是配套了。作为一个实验案例我这里并没有采集医院,学校等信息。而是着重采集了小区经纬度和周边1.5公里直线距离内的地铁站个数,地铁线路条数。
整个爬虫的代码是比较简单的,类似爬取“链家网”的博文CSDN上可以找到很多,用到的库就是beautifulsoup,这边就不赘述了。贴一下调试爬取地铁配套部分的代码吧,这里需要调用下百度地图的API来定位到小区经纬度,并且用POI来查找周边地铁站个数和地铁线路数,返回json格式再解析出来。
# 输入上海任意小区名,打印出周边1.5公里直接距离内的地铁站个数,名称,地铁线路和步行距离
name_estate = input("输入小区名字: ")
#中文转码utf-8
name_estate_quoted = quote("上海"+name_estate)
#调用百度地图API获得小区经纬度
find_location = "http://api.map.baidu.com/geocoder/v2/?address="+name_estate_quoted+"&output=json&ak=你申请的ak"
page = urlopen(find_location).read(