数据分析 - 开放街道地图(OpenStreetMap)

Reinhard使用OpenStreetMap的开放地图数据作为本次数据分析的数据源,使用Python进行数据清洗,使用MongoDB进行数据探索和分析。
这里先看看什么是OpenStreetMap:

开放街道地图(英语:OpenStreetMap,缩写为OSM)目标是创造一个内容自由且能让所有人编辑的世界地图,并且让一般便宜的移动设备有方便的导航方案。

在地图中遇到的问题

Reinhard下载了台北市的地图数据后,对地址进行审查时,主要发现存在以下几个问题:

  1. 有些数据过于明细,不仅写出了街道地址,还将单位名称写在后面,如:“235新北市中和區中山路三段122號、中和環球購物中心”。
  2. 有些英文地址中,存在过度简写的情况。比如:“Ln 26 Taishun St.”。
  3. 有些地址中即包含中文地址,又包含英文地址,比如:“台北市市民大道四段207號/ English: No. 207, Section 4, Civic Blvd, Songshan District, Taipei City, Taiwan 105”。
  4. 这里将node和way作为文档的type的值,但是会被地址描述tag中的值替换。比如:<tag k="type" v="multipolygon" />,会将文档的type变成multipolygon 。
  5. 地址的邮政编码和台北市的邮政编码不一致。比如:<tag k="addr:city" v="桃園市龜山區" /><tag k="addr:postcode" v="333" />

地址过于明细的情况

Reinhard通过定位到问题地址中的分隔符,将单位名称从地址信息中去除。比如将“235新北市中和區中山路三段122號、中和環球購物中心”,转换成“235新北市中和區中山路三段122號”。

改进的益处和预期的问题

经过这样的清洗,使得地址的格式更加一致。
Reinhard仅仅是通过分隔符将单位名称从地址信息中去除,但是因为分隔符的多样性,甚至压根就没有分隔符,所以清洗过的数据中,依然可能存在地址过于明细的情况。

英文地址中有过度简写的情况

Reinhard用全称,替换问题地址中的简称,比如将“Ln 26 Taishun St.”,转换成“Lane 26 Taishun Street”。

改进的益处和预期的问题

Reinhard将数据导入到数据库中后,是通过地址关键字进行查询的。Reinhard将关键字进行统一后,便于今后的使用。
Reinhard仅仅是用有限的几个特定简写,定位到问题数据,并进行处理。但是因为英文简写的多样性,很难进行穷举。所以清洗过的数据中,依然可能存在英文地址中有过度简写的情况。

即包含中文地址,又包含英文地址的情况

Reinhard定位到问题地址中的分隔符,只保留分隔符前面的地址。比如将“台北市市民大道四段207號/ English: No. 207, Section 4, Civic Blvd, Songshan District, Taipei City, Taiwan 105”,转换成“台北市市民大道四段207號”。

改进的益处和预期的问题

经过这样的清洗,使得地址的格式更加一致。
Reinhard这里仅仅是通过分隔符将英文地址从地址信息中去除,但是因为分隔符的多样性,甚至压根就没有分隔符,所以清洗过的数据中,依然可能存在即包含中文地址,又包含英文地址的情况。

文档的type被替换的情况

Reinhard这里在生成json文档的时候,会判断node和way节点下的tag的键,如果键是type或某些关键字,就不将tag的值添加到json文档中,防止文档的type被替换。

改进的益处和预期的问题

Reinhard这里通过一些关键字,对address中的数据进行了过滤,排除了文档关键信息被替换掉的可能。
但是这样的过滤方式,可能会损失一些有用的信息。

地址的邮政编码和台北市的邮政编码不一致

Reinhard这里主要通过邮政编码对地址进行过滤。
台湾的邮政编码是5位,其中前3位是投递区号,只写3位也能投递。
在数据探索的过程中,通过将邮政编码前3位的邮递区号提取出来,发现了以下两个问题:

  • 一些不属于台北市范围的数据。包括新北、基隆、桃源的数据。
  • 还有一些邮政编码长度不足3位的。

在台湾的行政区划中,台北市只包含城市范围,周围的郊区是归台北县的。台北县与基隆、桃源相邻。后来台北县提升为新北市,成为与台北市一样的直辖市。
所以,Reinhard需要使用台北市12个区的邮递区号,将台北市以外的数据,和邮政编码长度不足3位的数据,全部过滤掉。

改进的益处和预期的问题

这样的过滤方式,显然可以过滤掉一部分有问题的数据。
我这里只通过邮政编码进行过滤,但是并非所有的文档都提供了邮政编码信息,所以清洗过的数据中,依然可能存在地址超出台北市范围的情况。

数据概览

这里,Reinhard使用了台北市的地图数据,清洗后转换为json格式,导入到MongoDB中。

文件大小

taipei_taiwan.osm ......... 167.6 MB

taipei_taiwan.osm.json .... 182.8 MB

文档的数量

def print_doc_num(query):
    print db.test_collection.find(query).count()

print_doc_num({})

826198

node的数量

def print_doc_num(query):
    print db.test_collection.find(query).count()

print_doc_num({"type":"node"})

732147

way的数量

def print_doc_num(query):
    print db.test_collection.find(query).count()

print_doc_num({"type":"way"})

94051

用户的数量

result= db.test_collection.distinct("created.user")
print len(result)

1566  

贡献最多的用户

def print_doc_aggregate(query):
    result=db.test_collection.aggregate(query)
    pprint.pprint(list(result))

print_doc_aggregate([
        {"$group":{"_id":"$created.user","count":{"$sum":1}}},
        {"$sort":{"count":-1}},
        {"$limit":1}
])

[{u'count': 180515, u'_id': u'Supaplex'}]

只贡献过一次的用户

def print_doc_aggregate(query):
    result=db.test_collection.aggregate(query)
    pprint.pprint(list(result))

print_doc_aggregate([
        {"$group":{"_id":"$created.user","count":{"$sum":1}}},
        {"$match":{"count":1}},
        {"$group":{"_id":"$count","num_users":{"$sum":1}}}
])

[{u'num_users': 314, u'_id': 1}]

额外的想法

贡献者的统计信息

用户的贡献呈现出非常严重的倾斜。少量的用户贡献了绝大多数的地图信息。这里,有一些关于用户贡献的统计信息:

  • 贡献最多的用户(Supaplex),占全部贡献的21.8% 。
  • 贡献最多的前10个用户(占全部用户的0.6%),合计占全部贡献的57.8% 。
  • 贡献最多的前100个用户(占全部用户的6.4%),他们的贡献占全部贡献的94.3% 。
  • 贡献最少的前1200个用户(占全部用户的76.6%),他们的贡献只占全部贡献的1% 。

Reinhard认为贡献度高的用户,提供的数据可能在一致性和可靠性上更好一些。而那些贡献度低的用户,可能并不是很熟悉OpenStreetMap地图的使用方法,他们的数据的一致性和可靠性可能会差一些。所以可以考虑删除掉这部分数据,以提高数据的一致性和可靠性。

改进的益处和预期的问题

删除贡献度低的用户所提供的数据后,数据集更一致和可靠。
与此同时,可能会损失一些有用的信息,并且数据集会变小。但是因为这部分用户所提供的数据相对来说非常少,所以只会删除很少的数据。
总的来说,删除这部分数据比保留要好。

使用MongoDB进行额外的数据探索

出现次数最多的便利设施

def print_doc_aggregate(query):
    result=db.test_collection.aggregate(query)
    pprint.pprint(list(result))

print_doc_aggregate([
        {'$match':{'amenity':{'$exists':1}}},
        {'$group':{'_id':'$amenity','count':{'$sum':1}}},
        {'$sort':{'count':-1}},
        {'$limit':10}
])

[{u'_id': u'restaurant', u'count': 4729},
 {u'_id': u'parking', u'count': 1553},
 {u'_id': u'place_of_worship', u'count': 1129},
 {u'_id': u'cafe', u'count': 878},
 {u'_id': u'bank', u'count': 698},
 {u'_id': u'bench', u'count': 540},
 {u'_id': u'drinking_water', u'count': 529},
 {u'_id': u'toilets', u'count': 518},
 {u'_id': u'bicycle_rental', u'count': 491},
 {u'_id': u'shelter', u'count': 489}]

出现最多的餐厅

def print_doc_aggregate(query):
    result=db.test_collection.aggregate(query)
    pprint.pprint(list(result))

print_doc_aggregate([
        {'$match':{'amenity':{'$exists':1}}},
        {'$match':{'amenity':'restaurant'}},
        {'$match':{'name':{'$exists':1}}},
        {'$group':{'_id':'$name','count':{'$sum':1}}},
        {'$sort':{'count':-1}},
        {'$limit':3}
])

[{u'_id': u'八方雲集', u'count': 65},
 {u'_id': u'永和豆漿', u'count': 32},
 {u'_id': u'吉野家', u'count': 20}]

出现最多的咖啡店

def print_doc_aggregate(query):
    result=db.test_collection.aggregate(query)
    pprint.pprint(list(result))

print_doc_aggregate([
        {'$match':{'amenity':{'$exists':1}}},
        {'$match':{'amenity':'cafe'}},
        {'$match':{'name':{'$exists':1}}},
        {'$group':{'_id':'$name','count':{'$sum':1}}},
        {'$sort':{'count':-1}},
        {'$limit':3}

[{u'_id': u'星巴克', u'count': 39},
 {u'_id': u'85度C', u'count': 38},
 {u'_id': u'Starbucks', u'count': 34}]

出现最多的宗教场所

def print_doc_aggregate(query):
    result=db.test_collection.aggregate(query)
    pprint.pprint(list(result))

print_doc_aggregate([
        {'$match':{'amenity':{'$exists':1}}},
        {'$match':{'amenity':'place_of_worship'}},
        {'$match':{'name':{'$exists':1}}},
        {'$group':{'_id':'$name','count':{'$sum':1}}},
        {'$sort':{'count':-1}},
        {'$limit':3}
])

[{u'_id': u'福德宮', u'count': 38},
 {u'_id': u'土地公廟', u'count': 12},
 {u'_id': u'福興宮', u'count': 7}]

结论

经过本次清洗,数据在一致性和完整性上有了一定的提升。虽然清洗过的数据中,依然可能存在数据一致性和完整性的问题,但是Reinhard相信这次数据清洗已经很好地达到了本次练习的目的。
本次清洗让Reinhard注意到,OpenStreetMap可以让所有人都参与编辑地图、提供数据,这种形式能够提升数据的准确性、增加多样性,但是也带来了数据一致性和完整性上的问题。因为数据的质量会影响分析的结果,所以在使用此类数据进行分析前,要进行必要的数据清洗。

数据分析 - 开放街道地图(OpenStreetMap)的更多相关文章

  1. 我的世界 ParaCraft 结合开源地图 OpenStreetMap 生成3D校园的方法简介

    我的世界ParaCraft结合开源地图OpenStreetMap生成3D校园的方法简介 版本1.0 日期2019.2.3 作者Ray (82735589@qq.com) www.TimeGIS.com ...

  2. LBS数据分析:使用地图展示统计数据——麻点图与麻数图

    作为一个LBS的APP,都获得了用户经纬度,也都使用了友盟统计.google ana等等统计分析系统,不过没有地图展示功能,不能进行直观的展示. 友盟统计.google ana等系统是总体数据统计,无 ...

  3. Android开放百度地图集成

    1.创建应用 获取AK (我理解为Application key)  通过百度账号登录百度地图开放平台,进入API控制台 http://lbsyun.baidu.com/apiconsole/key ...

  4. Bing Maps进阶系列八:在Bing Maps中集成OpenStreetMap地图

    Bing Maps进阶系列八:在Bing Maps中集成OpenStreetMap地图 OSM(OpenStreetMap-开放街道地图)服务就是一种发布自己地图数据图片为服务的一种实现类型,开放街道 ...

  5. 利用OpenStreetMap(OSM)数据搭建一个地图服务

     http://www.cnblogs.com/LBSer/p/4451471.html 图 利用OSM数据简单发布的北京地图服务   一.OSM是什么 开放街道图(OpenStreetMap,简称O ...

  6. OpenStreetMap初探(一)——了解OpenStreetMap

    1. 開始关注OpenStreetMap始于此博文:<微软对抗谷歌的秘密武器:开源地图OpenStreetMap>  http://news.csdn.net/a/20120328/313 ...

  7. ArcGIS API For Silverlight使用在线地图的多种方法总结

    引自:http://www.cnblogs.com/meimao5211/p/3283969.html ArcGIS API For Silverlight使用在线地图的多种方法总结 本人也正在学习A ...

  8. 利用QGIS下载地图数据

    这段时间做了一些利用地理信息进行定位导航的系列工作,其中很重要的一部分是如何获取到地图数据,比如道路的矢量图.某一区域的栅格图,我用到的主要工具是QGIS.QGIS是一个跨平台的免费应用,其中集成了对 ...

  9. Android应用中使用百度地图API定位自己的位置(二)

    官方文档:http://developer.baidu.com/map/sdkandev-6.htm#.E7.AE.80.E4.BB.8B3 百度地图SDK为开发人员们提供了例如以下类型的地图覆盖物: ...

随机推荐

  1. 【5集iCore3_ADP演示视频】5-5 iCore3应用开发平台示波器和信号源校准

    iCore3双核心应用开发平台基于iCore3双核心板,包含ARM.FPGA.7寸液晶屏.双通道数字示波器.任意波发生器.电压表等模块,是一款专为电子爱好者设计的综合性电子学习系统. [视频简介]本视 ...

  2. MySQL数据的主从复制、半同步复制和主主复制详解

    一.MySQL复制概述 ⑴.MySQL数据的复制的基本介绍 目前MySQL数据库已经占去数据库市场上很大的份额,其一是由于MySQL数据的开源性和高性能,当然还有重要的一条就是免费~不过不知道还能免费 ...

  3. 总结-Intellij Idea (快捷键 配置修改)

    忽略大小写 输入sensitive,选择Code Completion,右边第一个下拉框,选择noneEditor 鼠标悬浮show quick docEditor Editor Tabs : Mar ...

  4. java中分页效果的实现代码

    首先是将分页所需的一些个资源 ,抽象出一个javabean对象-PageBean: 先把需要分页的数据或是记录都查询出来 存入一个集合类里如List或是Vector, 然后利用其sublist(int ...

  5. zookeeper+jstorm的集群搭建

    zookeeper的配置: zookeeper有三种配置方式:单机式/伪分布式/集群式 其中伪分布式是在一台电脑上通过不同的端口来模拟分布式情形,需要N份配置文件和启动程序,而集群式是多个zookee ...

  6. Creating Signing Identities 生成签名标识

    Before you can code sign your app, you create your development certificate and later, a distribution ...

  7. Dreamweaver的代码与设计简单结合的运用

    首先在设计里面写好自己需要的内容,在文字设置中,选中要设置的文字,然后点击属性栏的css,把目标规则改为新内联样式,然后在改变字体的大小颜色样式,然后在代码里面根据需要再修改: 图片插入是在菜单栏点击 ...

  8. eclipse下的emacs风格快捷键

    Ieclipse emacs类快捷键 win + shift + b 切换设置断点 win + shift + f 格式化代码 win + shift + l 显示绑定的快捷键 win + shift ...

  9. vim - mark

    Using markshttp://vim.wikia.com/wiki/Using_marks1. There is no visible indication of where marks are ...

  10. Trace-语句启动Profiler中暂停的跟踪会出现什么状况

    2016-09-08 22:09 整理,未发布Profiler创建客户端跟踪.常规页不保存文件.不勾选服务器处理跟踪数据:事件选择RPC:Completed和SQL:BatchCompleted,列筛 ...