赞
踩
本文使用Python Matplotlib、Pyecharts、Seaborn、Plotl,以及百度提供的绘制可视化地图接口BMap等工具,对武汉市14个区的房价数据进行可视化分析,绘制了房价分布热力地图、房价分布旭日图等众多图表,数据来源为使用Python Scrapy 和 Selenium 从链家、贝壳网上爬取的房价及其相关数据,共5056条数据。
数据预览:
数据地址:
作者:A WHU SIMer
目录
3.5 房源到市中心距离、建筑类型、物业费用与房价关系散点图
Matplotlib 是一个 Python 2D 绘图库,同时它也提供了一部分 3D 绘图接口。 Matplotlib 是 Python 中最受欢迎的数据可视化软件包之一,通常与 NumPy、 Pandas 一起使用,只需几行代码就可以生成图表、直方图、功率谱、条形图、 误差图、散点图等,是数据分析中不可或缺的重要工具之一。本文使用matplotlib参与绘制房价直方图、箱型图、条形图、散点图。
Matplotlib — Visualization with Pythonhttps://matplotlib.org/
Pyecharts ( https://pyecharts.org )是一个 Python Echarts 绘图库,Python 是一门富有表达力的语言,很适合用于数据处理,Echarts 是一个由百度开源的用于 快速构建基于 Web 的可视化的声明式框架,凭借着其良好的交互性,精巧的图 表设计,得到了众多开发者的认可,当数据分析遇上数据可视化时,pyecharts 便 诞生了。Pyecharts 囊括了 30 多种常见图表,可以说应有尽有,通过高度灵活的 配置项,可轻松搭配出精美的图表。本文使用Pyecharts绘制了全市房价总体分布地图。
Seaborn是基于matplotlib的图形可视化python包。它提供了一种高度交互式界面,便于用户能够做出各种有吸引力的统计图表。Seaborn是在Matplotlib的基础上进行了更高级的API封装,从而使得作图更加容易,在大多数情况下使用seaborn能做出很具有吸引力的图。同时它能高度兼容numpy与pandas数据结构以及scipy与statsmodels等统计模式。本文使用Seaborn绘制了全市房价总体分布直方图、各区房价分布箱型图、各区房价中位数柱形图、楼房离市中心的距离与价格关系散点图。
seaborn: statistical data visualization — seaborn 0.11.2 documentationhttps://seaborn.pydata.org/
Plotly是一个在快速完善并崛起的交互式、开源的绘图库,Python plotly库是它的一个重要分支。现已支持超过40种独特的图表类型,涵盖了广泛的统计、金融、地理、科学和三维用例。Plotly 通过JavaScript构建,能基于Web显示实现交互式的可视化效果,所以它的图形可以方便地显示在Jupyter notebook以及独立的html中。本文使用plotly绘制了各区各板块房价分布旭日图。
BMap是百度地图提供的绘制地图可视化图表接口,需要在百度地图中注册应用并获取密钥后才可调用百度map API来绘制地图热力图。使用BMap的方法有两种:一是使用python.pyecharts.charts 中BMap库,二是在html页面中使用JavaScript创建BMap对象。本文使用方式二来绘制全市房价分布热力地图。
jspopularGL | 百度地图API SDKhttps://lbsyun.baidu.com/index.php?title=jspopularGL
<script type="text/javascript" src="http://api.map.baidu.com/library/Heatmap/2.0/src/Heatmap_min.js"></script>
数据预处理部分,只需要用到pandas,即可完成对各字段数据的处理,如缺失值、更改数据格式等。
- import pandas as pd
- # 读取数据
- data = pd.read_excel("武汉市房价数据.xlsx")
- #查看数据基本信息
- print(data)
- print(data.info())
可以看到总共有5056条楼房样本信息,共有17个字段,用小区楼房的平均价格来代表该小区楼价水平。其中地铁字段存在较多缺失值,“楼栋总数”、“房屋总数”字段的数据类型本应为数值型,但是从上图中两者的数据类型为对象,说明存在一些问题,其他字段在用于可视化之前也或多或少存在需要修改的地方,下文将描述具体修改措施。
- # 地铁字段处理,提取地铁线路数字:
- metro = []
- for i in range(len(data["地铁"])):
- metroStation = data["地铁"][i]
- if pd.isnull(metroStation): # 当不存在地铁时
- metro.append(0) # 0 表示附近无地铁站
- else: # 当存在地铁时,提取地铁编号
- lineNum = metroStation[metroStation.index("铁") + 1: metroStation.index("号")]
- metro.append(int(lineNum))
- data["metro"] = metro
- data.drop('地铁',axis=1,inplace=True) # 删除原有的“地铁字段”
- print(data[0:10])
- print(data.info())
由于地铁字段存在较多缺失值,若将缺失值删除,则会使样本数据量大大降低,遂采取补的方式,用0代替缺失值。并对有地铁的单元格提取地铁编号,如“近地铁3号线王家湾站”提取的地铁编号为3,保存在新字段metro中。
- year = []
- for i in range(len(data["建筑年代"])):
- yearNum = data["建筑年代"][i]
- if yearNum == "暂无信息":
- year.append(0) # 0 代表未知
- else:
- year.append(int(yearNum[0:-1]))
- data["year"] = year
- data.drop('建筑年代',axis=1,inplace=True)
- print(data[["小区名称","year"]][0:10])
- print(data.info())
建筑年代字段原格式为“***年”,而且存在间接意义上的缺失值“暂无信息”,所以用0表示“暂无信息”,提取年份来表示“***年”,这样便于可视化时的计算。
可以看到建筑类型字段存在多种值:“板楼”、“塔楼”、“板楼/塔板结合”、“未知类型”、“塔板结合”、“塔楼/板楼”······但是归根究底是只有四种值,即未知类型、板楼、塔楼、板塔结合。所以分别用0,1,2,3分别表示这四种值。
- buildingType = []
- for i in range(len(data["建筑类型"])):
- type = data["建筑类型"][i]
- if type == "未知类型":
- buildingType.append(0)
- # print(0)
- elif type == "板楼":
- buildingType.append(1)
- # print(1)
- elif type == "塔楼":
- buildingType.append(2)
- # print(2)
- else:
- buildingType.append(3)
- # print(3)
- data["buildingType"] = buildingType
- data.drop('建筑类型',axis=1,inplace=True)
- print(data[["小区名称","buildingType"]][0:10])
- print(data.info())
可以看到“物业费用”字段的值存在一定的规律性,即以“元/平米/月”结尾,存在固定费用和区间费用两者形式。所以对于固定费用,提取固定费用数值,对于区间费用,用中间值代表,对于“暂无信息”则用-1代表(不用0表示,是因为考虑到物业费为0的情况,而且0在此处也不适合表示缺失值)。
- propertyExpense = []
- for i in range(len(data["物业费用"])):
- expense = data["物业费用"][i]
- if expense == "暂无信息":
- propertyExpense.append(-1)
- # print(-1)
- elif "至" in expense:
- minPrice = float(expense[0 : expense.index("至")])
- maxPrice = float(expense[expense.index("至")+1 : expense.index("元")])
- price = round((minPrice+maxPrice)/2, 2)
- propertyExpense.append(price)
- # print(price)
- else:
- price = float(expense[0 : expense.index("元")])
- propertyExpense.append(price)
- # print(price)
- data["propertyExpense"] = propertyExpense
- data.drop('物业费用',axis=1,inplace=True)
- print(data[["小区名称","propertyExpense"]][0:10])
- print(data.info())
可以看到“楼栋总数”与“房屋总数”字段的数据分别以“栋”和“户”字结尾,为方便计算,遂删除这两字,并将数据改为数值型。
- # 楼栋总数字段处理,去掉”栋“字,将字段值的类型改为数值型
- data["楼栋总数"] = data["楼栋总数"].apply(lambda x: int(x[0:-1]))
- # 房屋总数字段处理,去掉”户“字,将字段值的类型改为数值型
- data["房屋总数"] = data["房屋总数"].apply(lambda x: int(x[0:-1]))
- print(data.info())
- print(data[["小区名称","楼栋总数", "房屋总数"]])
保存预处理后的数据是为了方便在可视化时直接读取新数据文件,而不用每次用时都得再进行一次数据预处理过程。
- data.to_csv("WuHan.csv", encoding="utf8",index=False)
- newData = pd.read_csv("WuHan.csv")
- print(newData.info())
【注意】:以下房价简称x,具体含义为:x元/平方米,如1万,表示1万元/平方米。
绘制pyecharts.charts.Geo用于地图,所用的坐标为“经度_百度坐标”和“纬度_百度坐标”,绘制的图表如下:
从上图,可以总体看出房源集中在近长江的武昌区、汉阳区、硚口区、江汉区、江岸区、洪山区。位于武汉市中部长江两岸的房价是相对较高的,在3、4万以上。1万到2万的房源是最多的,并且紧围着中心高价房区。1万以下的房源主要分布在蔡甸区、黄陂区、新洲区和江夏区,距离武汉市中心较远,并且这四个区中,江夏区的房价较高,这也侧面说明江夏区的经济实力要高于其他三个。
代码:
- import pyecharts
- import pandas as pd
- from pyecharts.charts import Geo
- from pyecharts import options as opts
- from pyecharts.datasets import register_url
- from pyecharts.globals import ThemeType
- from pyecharts.globals import GeoType
-
- data = pd.read_csv("WuHan.csv", encoding="utf8")
- dataList = data.to_dict(orient='records')
- try:
- register_url("https://echarts-maps.github.io/echarts-china-counties-js/")
- except Exception:
- import ssl
-
- ssl._create_default_https_context = ssl._create_unverified_context
- register_url("https://echarts-maps.github.io/echarts-china-counties-js/")
- geo=Geo(init_opts=opts.InitOpts(theme=ThemeType.DARK,
- width="100%",
- height="700px",
- page_title="武汉市2018年房价数据可视化",
- bg_color="black"))
-
- geo.add_schema(maptype='武汉',
- label_opts=opts.LabelOpts(is_show=True),
- itemstyle_opts=opts.ItemStyleOpts(color="black", border_color="#1E90FF", border_width=1.5))
-
- data_pair = []
- for item in dataList:
- name = item["小区名称"]
- value = item["均价"]
-
- longitude = item["经度_百度坐标"]
- latitude = item["纬度_百度坐标"]
- # 将楼房坐标添加到地图中
- geo.add_coordinate(name, longitude, latitude)
- data_pair.append((name, value))
- # 添加数据项,即为地图中楼房位置赋值
- geo.add("房价",
- data_pair=data_pair,
- type_="scatter",
- symbol_size=1.5,
- is_large=True,
- )
- # 配置分组颜色
- pricePieces = [
- {"max": 10000, "label":"1W以下", "color": "#F0F0BF"},
- {"min": 10000, "max": 20000, "label": "1W~2W", "color": "#08830A"},
- {"min": 20000, "max": 30000, "label": "2W~3W", "color": "#EA760F"},
- {"min": 30000, "max": 40000, "label": "3W~4W", "color": "#E800FF"},
- {"min": 40000, "label": "4W以上", "color": "#FF0005"},
- ]
- geo.js_dependencies.add("echarts-gl")
- geo.set_series_opts(label_opts=opts.LabelOpts(is_show=False))
- geo.set_global_opts(title_opts=opts.TitleOpts(title="武汉市2018年房价数据可视化", pos_left="left", title_textstyle_opts=opts.TextStyleOpts(color="red")),
- visualmap_opts=opts.VisualMapOpts(is_piecewise=True, pieces=pricePieces))
- geo.render("武汉Geo.html")
使用seaborn绘制的全部样本房价分布直方图如下。从下图可以估计出武汉市房价集中在4千~4万的区间内,其中1万到2.5万的房源占多数。4万以上的房源凤毛麟角,最高的接近8万,结合3.1图1可知这些高价房源位于武昌区、汉阳区、硚口区、江汉区、江岸区。
代码:
- print(data["均价"].max())
- # 查看总体房价直方图----------------------------
- sns.displot(data["均价"],
- kde_kws={"color": "r", "lw": 1, "label": "KDE"},
- color="purple"
- )
- plt.title("全市房价总体分布直方图")
- plt.show()
使用seaborn绘制的武汉市各区房价分布箱型图如下。图表中已按各区房价中位数的大小对各区进行降序排序,因此可以直观看出房价中位数排名前三的区分别为:武昌区、洪山区、江岸区,其房价中位数接近2万。
从异常值角度上分析,可以得出洪山区、江岸区、江汉区各自区域内房价差异较大,高价的房源价格甚至可以达到7万或8万,而低价的房源最低约在5千左右。从下图中还可以确定本次统计的全部样本中,房价最高的房源在江汉区。
代码:
- my_order = data.groupby(by=["区域"])["均价"].median().sort_values(ascending=False).index
- print(data.groupby(by=["区域"])["均价"].median().sort_values(ascending=False))
- print(my_order)
- # sns.catplot(x='区域', y='均价', data=data, order=my_order, kind="violin") # 绘制小提琴图
- sns.boxplot(x='区域', y='均价', data=data, order=my_order)
- plt.title("各区房价箱型图")
- plt.show()
使用seaborn绘制的武汉市各区房价中位数柱形图如下。由于当一组数据差异性较大时,中位数比平均数能更好地代表这组数据的中等水平,遂使用中位数作为评价指标。从下图中,不仅能直观看出各区房价中位数的排名情况,也能直观比较它们房价中位数之间的差距。此外,在武汉市的14个区中,只有蔡甸区和新洲区的房价中位数在1万以下,说明武汉房价总体偏高。
代码:
- x = data.groupby(by=["区域"])["均价"].median().sort_values(ascending=False).index
- y = data.groupby(by=["区域"])["均价"].median().sort_values(ascending=False).values
- ax = sns.barplot(x,y)
- print(data.groupby(by=["区域"])["均价"].median().sort_values(ascending=False).reset_index())
- for index,row in data.groupby(by=["区域"])["均价"].median().sort_values(ascending=False).reset_index().iterrows():
- ax.text(row.name, row["均价"], row["均价"],color="red", ha="center")
- plt.title("各区房价中位数柱形图")
- plt.show()
使用seaborn绘制的武汉市房源到市中心距离、建筑类型、物业费用与房价关系散点图如下。本文设定武汉市政府所在位置为武汉市中心,其百度坐标为:(114.311754, 30.598604)。利用房源的百度坐标和武汉市政府位置坐标来计算房源到武汉市政府的实际距离,其计算公式如下:
设地球上任意两个点的坐标分别为(X1,Y1)、(X2,Y2),其中X1、X2为经度,Y1、Y2为纬度,且已知地球赤道半径R= 6371.0 km,则这两点之间的距离d计算式为:
d= R*arcos[cos(Y1)*cos(Y2)*cos(X1-X2)+sin(Y1)*sin(Y2)]
利用“黄金口岸”小区来验证计算结果的正确性,计算结果与测距结果一致。
从上图可以看出房价与房源到武汉中心的距离成负相关关系,大部分房源到武汉市中心的距离在20km以内。此外,板楼结构的房源较多,价格在4万以上的房源几乎均为板楼或者塔板结合结构,说明板楼更受买房者的青睐。这与板楼的特性有直接联系。板楼大多是正南北方向,南北通透,便于采光与通风,而且户型方正,平面布局合理,各功能空间尺度适宜,其相对于塔楼有着采光好、密度低、管理成本低的优点,这就意味着板楼的售价往往要高于塔楼,上图也可以证明这一点。
代码:
- centerPoint = (114.311754, 30.598604)
- R = 6371
- data["distance"] = data[["经度_百度坐标", "纬度_百度坐标"]].apply(lambda x: math.fabs(R*math.acos(math.cos(x["纬度_百度坐标"]*math.pi/180)*math.cos(centerPoint[1]*math.pi/180)*math.cos(x["经度_百度坐标"]*math.pi/180-centerPoint[0]*math.pi/180)+math.sin(x["纬度_百度坐标"]*math.pi/180)*math.sin(centerPoint[1]*math.pi/180))),
- axis=1)
- print(data[["经度_百度坐标", "纬度_百度坐标", "distance"]])
- data["buildingType"].loc[data["buildingType"] == 0] = "未知类型"
- data["buildingType"].loc[data["buildingType"] == 1] = "板楼"
- data["buildingType"].loc[data["buildingType"] == 2] = "塔楼"
- data["buildingType"].loc[data["buildingType"] == 3] = "板塔结合"
- sns.scatterplot(data=data,
- x='distance',
- y='均价',
- hue="buildingType", # 设置分组颜色
- style='区域', # 设置分组样式
- size='propertyExpense' # 设置分组大小
- )
- plt.title("楼房离市中心的距离与价格散点图")
- plt.show()
使用plotly绘制的武汉市各区各板块房价分布旭日图如下。从图1中可以一眼看出武昌区的水果湖板块房价中位数值最大,其次是洪山区的楚河汉街板块和武昌区的楚河汉街板块。点击“洪山”,查看洪山区各板块房价中位数占比情况,如图2,可以看到,随着板块到武汉市中心的距离的增大,板块内的房价在逐步下降。
代码:
- newdata = data.groupby(["区域", "板块"])["均价"].median().reset_index()
- print(newdata)
- chart = express.sunburst(newdata,path=["区域", "板块"], values="均价", color="均价", title="各区各板块房价中位数旭日图")
- chart.show()
为了更加直观地展现每一个房源的地理与价格之间的关系,本文调用了百度JavaScript开发API,来在html页面中绘制武汉市地图,并根据各房源的百度坐标将房源展示在地图上,并用颜色的深浅来表示其价格的高低,以此形成全市的房价分布热力地图。
绘制结果如下:
(图1)
(图2)
(图3)
从图1中可以总体上看出房源主要分布在武汉市四环线以内,外围的房源集中区域则分布在黄陂区、蔡甸区、江夏区和新洲区,这与3.1图1的显示结果一致。
从图2中可以看出,长江北岸的高价房源要多于南岸的高价房源。长江北岸的高价房源分布在北岸的几个商业区中,而南岸的高级房源分布在高校和商业区之间。长江南岸的房源明显分布在地铁线路的两边。
从图3中可以看出,紧靠政府机构、教育机构、医疗机构、主干道等的房源价格要比一般的房源价格高。
代码:
HTML,(ak=你的密钥)
- <!DOCTYPE html>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
- <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=*****************9C"></script>
- <script type="text/javascript" src="http://api.map.baidu.com/library/Heatmap/2.0/src/Heatmap_min.js"></script>
- <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
- <script src="jquery-csv.js"></script>
- <script src="getData.js"></script>
- <title>武汉市房价分布热力地图</title>
- <style type="text/css">
- ul,
- li {
- list-style: none;
- margin: 0;
- padding: 0;
- float: left;
- }
-
- html {
- height: 100%
- }
-
- body {
- height: 100%;
- margin: 0px;
- padding: 0px;
- font-family: "微软雅黑";
- }
-
- #container {
- height: 90%;
- width: 100%;
- }
-
- #r-result {
- width: 100%;
- }
- </style>
- </head>
-
- <body>
- <div id="container"></div>
- <div id="r-result">
- <input type="button" onclick="openHeatmap();" value="显示热力图" /><input type="button" onclick="closeHeatmap();"
- value="关闭热力图" />
- </div>
- </body>
-
- </html>
- <script type="text/javascript">
- var map = new BMap.Map("container"); // 创建地图实例
-
- var point = new BMap.Point(114.311754, 30.598604);
- map.centerAndZoom(point, 12); // 初始化地图,设置中心点坐标和地图级别
- map.enableScrollWheelZoom(); // 允许滚轮缩放
-
- var data = getData()
- console.log(data)
- var points = data
-
- if (!isSupportCanvas()) {
- alert('热力图目前只支持有canvas支持的浏览器,您所使用的浏览器不能使用热力图功能~')
- }
-
- heatmapOverlay = new BMapLib.HeatmapOverlay({ "radius": 10 });
- map.addOverlay(heatmapOverlay);
- heatmapOverlay.setDataSet({ data: points, max: 90000 });
- //是否显示热力图
- function openHeatmap() {
- heatmapOverlay.show();
- }
- function closeHeatmap() {
- heatmapOverlay.hide();
- }
- closeHeatmap();
- function setGradient() {
- var gradient = {};
- var colors = document.querySelectorAll("input[type='color']");
- colors = [].slice.call(colors, 0);
- colors.forEach(function (ele) {
- gradient[ele.getAttribute("data-key")] = ele.value;
- });
- heatmapOverlay.setOptions({ "gradient": gradient });
- }
- //判断浏览区是否支持canvas
- function isSupportCanvas() {
- var elem = document.createElement('canvas');
- return !!(elem.getContext && elem.getContext('2d'));
- }
- </script>
getData.js
- function getData() {
- var points = [
- {'lat': 30.590072, 'lng': 114.176442, 'count': 10001} ,
- {'lat': 30.590072, 'lng': 114.176442, 'count': 10001} ,
- {'lat': 30.881746472273, 'lng': 114.39374109924, 'count': 10008} ,
- {'lat': 30.881746472273, 'lng': 114.39374109924, 'count': 10008} ,
- {'lat': 30.49259, 'lng': 114.292619, 'count': 10078} ,
- {'lat': 30.49259, 'lng': 114.292619, 'count': 10078} ,
- {'lat': 30.585092, 'lng': 114.048935, 'count': 10084} ,
- .........
- .........] // 5056 条房源经纬度值,以及房价:count
- return points
- }
武汉市只有蔡甸区和新洲区的房价中位数在1万以下,若要在四环线以内买房,房价大概率会高于1万元,再结合实际月收入,可以考虑购买中等水平房价的房源,即房价在1万~2万之间。在这个房价区间内的房源数量最多,则可选择性多,而且在4环线以内,离市中心不算太远。再深入分析,可以发现长江北岸的绿色房源均位于商业区外围,而南岸的绿色房源有少数甚至在中心商业区内,而且南岸高校众多,文化气息更加浓厚。因此建议在长江南岸、靠近高校、离主干道较近的位置购买房价在1万到2万的房子。若购买面积为100平方米,则总费用在100万到200万之间,则不吃不喝工作约8年到17年可以付清。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。