1.缘起
最近由于工作原因,每天通勤时间过长,便动了换租房的念头。于是,在自如(http://www.ziroom.com/) 上刷了又刷,凭借自己的感性不断的对比各个房子,觉得既不靠谱又心累。而自如的选房如下图所示,
我一般是选定一个地铁站,期待的价钱区间,期待的面积进行筛选。可是这里有几个问题。第一个是我如果想比较多个地铁站的房子我就要在这个比较权衡的过程中多次运用自己的判断做决策;第二个是我最关心的房子与公司之间的距离,上面并不会有体现;第三个是这么多维度综合判断,并不能得到一个靠谱的结果,费力不讨好。
那么,我为什么不把数据拿下来完全按照我的需求做一个房屋自动推荐呢?
2.整体思路
用户输入的是公司所在位置,自己感兴趣的几个地铁站租房点,以及自己对于房子各项指标(比如与公司距离、价格、大小等)的权重;输出是推荐的N个房子及其数据。
整体思路大概分为如下几part:
1. 爬虫按(地铁线,地铁站)维度把每一个站点周围的房子全部定时离线的爬取、清洗并存储。
2. 接入高德地图API,获取公司所在位置经纬度、获取每个感兴趣的几个地铁站周边房子的经纬度,分别计算公司与目标房子之间的步行、驾车、公交距离与时间,打车花费,周边繁华程度。
3. 对房子各项指标的数据进行聚类,不同level进行打分,与权重相乘得出最终得分,输出结果。
3.爬虫
首先按照我们的想法,要将自如上的房子按照(地铁线,地铁站)的维度爬取。
观察了自如在选定地铁站后的链接,举例13号线西二旗站: http://www.ziroom.com/z/nl/z2-s13号线-t西二旗.html?p=2
可以看到这个链接还是很规矩的,我们只要遍历北京所有的(地铁线,地铁站)以及关注下每个地铁站房源多页就可以获取所有待爬链接。
接着看下面的房子列表,
上面的信息还是蛮丰富的,我选择把上面的信息都爬下来。因此,在这个页面,我获取了链接、展示图、小区位置、朝向、紧邻地铁、平方米、楼层(第几层)、楼层(共几层)、室、厅、是否合租、与最近地铁距离、是否地铁十分钟、自如版本、价格这些信息。
当然,爬取的过程不可能一帆风顺,有一些异常数据不断在调教我的爬虫,比如下面这个层数丢失:
为了提升速度,我使用了多线程。经过几次测试,发现在线程数设置成5是比较好的,设置更大的话服务器会大量返回”Service Temporarily Unavailable“。
同时,对于每一个房源,会调用高德API计算该小区经纬度以及繁华程度,这个会在下一part具体说。
经过这些处理后,将所有数据存到了数据库。
以上,就是离线操作的部分,大概用时在3min左右。考虑到房源变动情况,可以设置1h的离线定时刷新房源,保证房源最新。
4.接入高德地图API
其实一开始是考虑用百度地图API的,但是实在不得不吐槽一句太难用了,当天还发了朋友圈,引来众多好友共鸣。
主要使用了高德地图如下的几个API:
地理/逆地理编码(通过地点反解经纬度)
http://lbs.amap.com/api/webservice/guide/api/georegeo
输入提示(输入一个模糊地址匹配地址列表)
http://lbs.amap.com/api/webservice/guide/api/inputtips
路径规划(获取两个经纬度的步行、驾车、公交距离与时间,打车花费)
http://lbs.amap.com/api/webservice/guide/api/direction
搜索(获取周边Xkm内Y的数量)
http://lbs.amap.com/api/webservice/guide/api/search
那么地图API能帮我们做什么呢?
比如用户输入了如下信息:
公司位置:国家广告产业园
地铁位置:大望路、金台路、九龙山
那么依据地理/逆地理编码,我可以获取公司所在经纬度;
依据路径规划,可以获取获取公司所在位置经纬度、获取每个感兴趣的几个地铁站周边房子的经纬度,分别计算公司与目标房子之间的步行、驾车、公交距离与时间,打车花费;
根据搜索,可以获取周边Xkm内Y的数量。
接下来,遇到了一个比较感性的问题。有了搜索API,可是房源周围什么东西多代表它的位置会好一些,不那么偏僻呢?商圈?饭店?酒店?于是,经过深思熟虑(灵机一动),我选择了KFC,考虑到这种连锁的快餐在布局上肯定就想到了一个店能cover多少人或者多大的区域,以及一片区域开多少家店,所以选择了KFC,3km内KFC数量去代表一个地区的繁华程度。
由于我是个人用户,所以高德给的每天访问量仅有几千,为了应对这个问题,我批量申请了key,循环使用。
5.关键属性聚类,排序输出结果
前面的步骤我们已经获取了房子的已有属性,也计算出了房子的距离、繁华度等属性,那么理论上只要再有一个核心计算模型,房子就可以按得分排序了。
我理想中的比重是这样的:
# 比重
rates = {\'驾车距离\': 10, \'驾车时间\': 10, \'步行距离\': 20, \'步行时间\': 20, \'公交距离\': 5, \'公交时间\': 5, \'价格\': 20, \'房间大小\': 30, \'周边繁华度\': 10}
我对于每一个属性赋一个基础比重,比如我比较care距离,那么我对距离的赋比重大一些;如果有人比较care房间大小,可能会对房间大小赋比重大一些。
那么,如何计算每一项乘以比重的系数呢?
第一个涌入脑海的想法是分组,比如距离公司0~2km为第一组,2~5km为第二组,5~10km为第三组,每一组有不同的系数。可是,这样的分组太依赖我的主观判断,觉得不太理想。
接着想到,可以使用聚类算法解决这个问题。比如K-means聚类算法(https://en.wikipedia.org/wiki/K-means_clustering) 。这个算法简单说,就是先随机选取K个质心点,对于剩下的进行计算归类。完成后,在每一组总重新计算质心,重复上面的步骤,如果下一次计算质心不再变化的话,即为终结状态。
用keans对某地铁站附近房子价格进行聚类,K输入为3。可以看到价格聚为3组,大概为2030、2550、3200。
那么所有的房子也被分为了这三组,由于价格是一个越低越好的因素,所以三组分别被赋值系数3,2,1,与价格的比重分别相乘即为价格得分。其他的属性也依次得到自己的得分,比如房间大小,就是越大越好,所以房子越大系数越大。最后,按房子为维度计算每件房子的总得分,倒叙输出。
结果举例:
公司位置:国家广告产业园
地铁位置:大望路、金台路、九龙山
可以看到,我价格因素比重很低,几个距离加一块比重很大,推荐的几个房子价格稍贵,但距离是真近。尤其是第一个房子,
因为距离太短,没有公交线路,所以公交距离和时间显示了0。
而当把价格比重提升到50的时候,
推荐的房子价格果然就下来了,但距离普遍超过了2KM。
6.思考
及时反馈
之前生活中也遇到很多恼人的问题,也产生了很多用一些简单的技术解决问题的想法,但都不了了之。这次之所以能够最终产出,我觉得最大的改变就是快速落地,及时反馈。我一贯的做事风格,是把事情想清楚,想透彻,规避一切的风险,避开一切可能踩的坑,再去开始。这种风格在工作中可能还可以。不过对于生活来说,可能做事儿的欲望在这个过程中就消磨掉了。所以,这次我吸取教训,在想法主线清晰之后,快速搞通主线落地,并且过程中及时给自己积极的反馈。这个工具本来预期2天搞完,最后还是搞了接近5天。我觉得,如果再搞2天的话,可能我的欲望又要被消磨掉了。
边界,克制
即使是这么简单的工具,在落地的过程中依然面临自己各种想法的碰撞。比如,要不要最后选出的房子自动规划看房路线,是不是要搞一套漂亮的界面,计算模型要不要再引入一些机器学习的算法。还好,在过程中,时刻提醒自己,先落地主线,不要走偏。否则,可能现在还什么也没搞定,而是陷入到机器学习的算法里。
即使是这么简单的工具,只有我自己的想法,落地的过程都需要自己时刻提醒自己的边界,要克制。可想而知,如果是创业,过程中会面临多大的诱惑。什么都能做,什么都想做的时候,能不能做好减法,做好专注。
7.彩蛋
神秘大房,五棵松区域推荐房间中排名第一。