规划问道

【论文放送】基于R与Google API的中文地址编码及可视化研究

摘要:

近年来,不同学科和政策部门对地理编码技术都有较迫切的需求。然而,目前国内对地理编码的理论和实证研究仍然很缺乏。为此,本文主要从实现技术的角度介绍了基于R语言和Google API的一种实现方法。


其实现思路为首先整理地址数据的格式和结构,进而将地址生成GoogleAPI规定的查询格式,最后调用和保存返回的查询结果。支持这一过程的R软件包主要包括RCurlRJSONIOggmapplyr等。这些包的函数功能比较强大,应用比较灵活,执行速度较快,且可以应用到其他API平台(如YahooBing等)。


从生成效果来看,基于Google API的地理编码技术还存在免费编码的额度限制、数据库差异和对地址结构敏感等不足。总体上,这种地理编码方法更适用于比较容易在地图上识别且数量不多的情况,尤其适用于大型公司或居住区尺度或以上的调查。





地理编码(Geocoding)又称地址编码,是基于空间定位技术把文字形式的地址信息转换成可以被GIS系统识别的地理坐标的方法[1]。简言之,地理编码指的是将空间地址数据与空间位置(坐标)相关联。该方法目前在学术研究和政策制定中具有广阔的应用前景。一方面,随着空间经济学的兴起[2]和社会学的“空间转向”[3],空间位置信息及对各种社会经济现象的空间可视化变得日益重要;而由于社会学和经济学调查中对地址信息的编码往往以文字形式为主(如经济学常用的“中国工业企业数据库”中对企业地址的编码即采用文字形式),对文字格式的地址进行地理编码并将其与其他社会经济信息关联对社会经济问题的空间分析和可视化就显得至关重要。笔者在与一些经济学者交流的过程中已感觉到他们近来对地理编码技术的迫切需求。同时,尽管很多地理学者在活动的时空调查和分析中开始采用GPS等定位技术[4-8],但是,其高昂的成本与选取受访者的难度(如很多受访者会因为涉及个人隐私而拒绝接受访谈)使其无法完全替代传统的、基于自报告的地址信息的调查。因此,地理信息技术的发展还不能完全支撑不同学科对地理编码的技术需求。另一方面,随着地理信息技术在社会管理中的广泛应用,在地理空间参考范围内确定事件(如传染病、犯罪或种族隔离等)或资源(如可达范围内的商店数、选址区位附近的人文矿产资源等)的位置对制定社会政策(如资源环境管理、城市规划建设以及报警系统等)或经济决策(如商业选址)具有重要的参考意义[1, 9]。这些信息很多情况下同样以文字的形式收集,因而也需要使用地理编码的技术。


目前,与地理编码相关的地址匹配和定位软件主要有ArcInfoGeocoding模块、MapInfoMap-Marker、北京长地计算机公司的“寻址神”[1]、基于GIS软件的二次开发[10, 11]、一些用户开发的小软件或插件[12]等。还有很多在线网站提供免费的地理编码服务如[13, 14]。但是,这些地理编码工具存在以下缺陷:(1)大部分地理编码软件工具已经商品化(如Arc InfoMapInfo等),用户需要支付不菲的费用。(2)很多软件难以实现对地址的批量编码。(3)很多软件不支持中文的地名,需要转换为中文形式。同时,由于中国现有的地名、地址体系很复杂,很多国外已有的地理编码软件并不适合中国国情。(4)很多空间软件仅仅针对地理编码功能而开发,一方面使得很多不熟悉空间分析软件的经济学者不太容易入门,另一方面也使得这些软件所生成的结果不太容易与已有社会经济变量相关联而快速实现可视化。


上述问题不仅限制了地理编码技术在经济学等社会科学中的使用,也造成很多不必要的经济负担和时间浪费(如手动查找的低效、结果数据关联的耗时等)。实际上,随着近几年R语言在空间分析中的广泛应用和很多大型公司大型地理编码API开发接口的推出,很多地理编码和空间可视化问题能够借助这两个平台高效地实现。更重要的是,基于这两个平台的地理编码基本上不存在上述缺陷。一方面,R语言和很多API接口(包括底图)都是免费、开源的,并且能够实现数据的批量处理,因此是十分容易获取的地理编码平台;另一方面,R语言作为统计学家开发的开源软件,具有大量针对数据管理、空间分析和空间可视化的函数或程序包,从而能够快速地将地理编码的结果导出到已有数据文件或可视化到地图上。为此,本文将主要介绍基于R语言和Google API对中文地址进行地理编码的思路和技术细节,以期方便研究者对空间问题的处理。


1 基于R与Google API的地理编码思路与过程

地理编码的过程主要包括地址的标准化、地址信息的读取、地址匹配、结果的输出和检查、数据可视化等步骤。地址的标准化是地理编码的前提,也关系到地理编码质量的优劣。一个良好的地址编码通常具有以下特征:统一的地址结构、能够被唯一识别和尽量精简。统一的地址结构便于软件对其进行系统化的处理,也能够保证在无法确切定位的时候不会偏离实际距离太远。如所有地址都采用国家+++/+(路+号)+公司或小区名称的格式编码,那么即使软件无法识别出唯一的最终地址(如“中国广东省广州市海珠区中山大学校门”可能对应四个方向的校门),也能够保证对应的地址不会偏离上一尺度(如中山大学)的范围;这在很多对空间区位精度要求不高的研究中尤其重要。能够唯一识别是保证地理编码精度的重要标准。需要注意的是,这里的“唯一”不仅指没有其他干扰选项(如一个城市的“麦当劳”可能有多家,因而无法一一对应),还要求能够有选项对应,而不是无法查找的地址。因此,有时候地址也不能过细,否则地理编码会无法识别而生成空值(如×××小区##单元#楼可能在数据库中并无相应的地址与其对应)。此时一个可以考虑的办法是只记录周边较近的标志性建筑物——这在需要保护用户空间信息隐私(如具体的居住位置)时[15, 16]尤其可行。精简的地址则往往能够更快速、准确地进行地理编码。


如果完成了对地址信息的标准化处理,就可以用R读取和编码相应的地址。R可以读取多种格式的数据,包括excelstatatxt/datcsvSASSPSS、数据库甚至网络抓取的各种数据。R的数据读取方式也十分灵活,既可以使用系统自带的read.tablescanreadLines等函数,也可以使用用户开发的importrio包)、readHTMLTableXML包)、odbcConnectExcelsqlQueryRODBC包)等函数。R对地址数据的解码主要借助各种API的开发接口实现。常用的地图API平台包括YahooOpen AddressesCloud MadeBingGoogle[17]。不同API的平台具有不同的规则;这里主要以Google API为例。选择Google API主要基于以下两点:一是Google地图对中文的支持较好,并且能够通过google map网页对相关的编码结果进行核查和校对;二是David KahleHadley Wickham开发的ggmap[18]已经实现地址编码、图形可视化等一系列功能,大大方便了R用户对Google API平台的调用和基于Google map底图进行可视化。ggmap包中实现地理编码的函数为geocode。其基本思路为将具体的地址信息黏贴到Google API平台的网址(参见https://developers.google.com/maps/documentation/geocoding/的介绍),进而生成相应的经纬度信息输出。然而,目前geocode函数还不支持中文地址。为此,本文在geocode函数的基础上提出来一个二次开发的思路——对中文地址进行编码转化,生成浏览器可查询的形式(如utf-8格式),从而能够实现与英文地址名类似的查询结果。


对中文地址完成地理编码后并不能直接将其用于空间分析和空间可视化。这里存在的问题有三点:(1)地理编码的结果是否完整可靠?(2)地理编码的数据如何与已有结果相连接?(3)如何对数据进行可视化和空间分析。由于Google API对免费的地址解析数额和速度存在限制(如每天一个IP地址只能进行2500次编码;过快的循环调用也会产生空值),因此对地址进行一次地理编码后需要检查是否存在空值,并将其重新进行编码。同时,由于某些地址信息可能不准确而导致编码错误,因此还需要检查编码误差。这一过程可以通过上层编码或逆编码实现。前者的思路为:首先对上一层级的地址信息进行编码,然后比较与基于详细地址编码的位置差异;后者对基于原数据解析出的经纬度进行逆向编码,生成经纬度对应的地址,然后比较两类地址的差异来查验编码的准确度。编码数据与其他数据的连接/导出以及经纬度数据的空间可视化实际上已经不属于地理编码的范畴,且可以通过R以外的其他软件实现。不过,为了保证数据处理的效率和连续性,本文也介绍了R对这两个问题的处理思路和方法。


2 案例:珠三角外来工的工作地与迁出地的地理编码

2.1 案例地数据

为了方便对上述地理编码思路的理解和对R语言的使用,本文以一份人口迁移数据为例介绍了如何利用R语言调用Google API对中文地址信息进行地理编码和空间可视化。此份数据来自中山大学社会学与社会工作系所做的“2009年珠三角城市外来工调查”(N=1766)。该调查采取按性别、行业和地区比例分层抽样的方法,收集了珠三角九个城市金融危机后外来工的基本信息和流动意愿。其中包含地理位置信息的变量主要是其目前所在城市、家乡的县/区以及工作单位。其中,城市或区县的地理编码最为容易和准确,但是由于目前存在很多现成的数字化底图,因此对研究意义不大;工作单位的地址往往比较详细,也存在诸多难题——如命名的结构混乱、很多单位重名、地址过粗或过细等。地理学者收集地址信息的结构性和严谨性往往优于这些社会学者,但也存在类似的问题。因此,本着难题一解决简单问题也能迎刃而解的原则,本文主要利用R对这些工作单位的信息进行编码,而主要利用外来工来源地的信息介绍R的可视化。作为地理编码方法的一个例示,本文抽取了广州市10个外来工工作地的详细地址(如表1),以此检查R基于Google API进行地理编码的效率。这些地址有的包含了过于详细的信息(如已具体到楼号),还有的存在地址信息冗余(如前面还有广州市名)、错位(如有的区名在后面)及错误(如误录)。这些难题大体涵盖了目前地理编码中原始数据所存在的主要问题。本文使用这些外来工迁出省份的汇总信息(如表2)介绍R的可视化功能,即做出来自不同省份外来工人数的空间分布地图。这一问题也代表了目前很多试图对社会现象进行空间分布的可视化的需要。



2.2 地理编码程序及效果

如前所述,目前Rggmap包的地理编码不支持中文的地址(未包含语言选项),而实际上Google API中能够返回中文地址的查询结果。这一问题的主要原因在于geocode函数没有对语言编码进行转换。因此,这一问题可通过将中文地址(GB2312代码)转换为浏览器可读取的通用格式(utf-8)来解决;Riconv函数能够实现这一功能。为了能够使浏览器顺利编译相关查询,还需要将查询地址中的空格替换为“%20”;这可以通过R中的gsub函数实现。针对上述过程,笔者编写了一个Rgeocode.url函数(见附件);该函数需要输入两个变量——subdistrict对应县、区名,address对应详细的地址。可以稍加修改将该函数用于其它地区或仅适用一个地址变量。


有了可以从浏览器返回相应信息的查询地址,就可以将其输入浏览器生成相应的区位信息。但是,使用R的优势绝不是仅仅对中文进行编码——这完全可以通过手动在GoogleMap中搜索实现,而是能够批量保存生成的数据信息。为了实现这一目的,必须实现将网址输入浏览器和将浏览器返回结果保存的过程自动化。前者可以通过RRCurl包中的getURL函数实现;该函数的主要功能为通过输入查询网址下载浏览器的返回结果。后者则可以通过RRJSONIO包中的fromJSON函数实现;该函数主要用于读取Google API返回的XML格式的地址信息。而对地址变量的调用可以使用Rplyr包中的alply等函数实现对地址的逐个编码。笔者将上述过程编写为一个GeoCode的函数(见附件);该函数同样需要输入subdistrictaddress两个变量的信息。需要注意的是,由于Google API的地理编码需要频繁访问Google的服务器,因此可能会不定期返回空值。对这些空值的处理可以使用while函数对空值的地址重新编码;进而通过is.na函数将空值替换为新的编码数据。


最后,为了检查地理编码结果的准确性,本文提出了两种解决思路。由于基于R的解码设定了县区变量,因此即使address变量的地址无法解码,Google API也能够返回上一级行政地域的地理信息(即区县的行政中心)。这种“错误的”编码质量当然要低于那些能够准确编码的结果。为了将这些信息与准确的编码信息加以区分,可以通过一个可以称之为“上层解码”的方法加以检查,即只输入非重复的subdistrict变量;如果对这些subdistrict的经纬度信息与加入address后的编码重合,说明address变量未发挥作用,即该地址无效。还有时候可能因存在多个类似信息(如前面的“中山大学校门”的例子)或地址较粗(如只有路名)而使得Google API返回的信息并非所编码地址的确切位置。针对这种情况,可以通过一个可称之为“解码逆解码”的方法检查其编码质量,即将经纬度信息反向编码为地址信息,再通过地址的比较查看编码的准确性。这一过程可以通过循环调用ggmap包中的revgeocode函数实现。不过由于Google API中返回的地址信息为英文,因此需要用肉眼检查,数量较多时只能通过抽查的方式。当然,也可以再将其中的函数改写应用到其他API平台,然后通过比较两个平台的编码结果检查不同编码方式的优劣。



由于上述地址的区/县信息未单独列出,并且存在很多结构性问题,因此,编码前笔者对原始的地址格式进行了初步整理——这些处理方式在所有地址的问题类似时可以进行批量修改。表3为这些整理过的地址信息的编码结果。可以发现,其中三个地址(ID号为178)因过于特殊在GoogleAPI中无法识别。不过,这三个地址能在Google Map中定位,说明Google API的编码数据库可能较Google Map背后的数据库存在一定的更新时滞(time lag)或对中文的支持更弱。如果返回的结果中空值很多但是在地图上都能查到相应的坐标,可以使用Google Place API的功能[i],其处理过程类似,只是可能会有多个返回结果,需要进一步筛选。另一比较奇怪的地方是地理编码中无法识别的地址所返回的结果不是子区的中心而是广州市的中心,即subdistrict的限制作用并未发挥。其原因有待进一步探索。


2.3基于R地理编码数据的空间可视化

在完成地理编码后,可以根据生成的信息对相关社会经济现象进行可视化。尽管经纬度信息可以通过导入Arc Info或通过坐标转换进行可视化和空间分析,但是,基于数据衔接和统计分析的方便,最好在R中进行相关的空间可视化。这里主要以广东省外来工来源地的分布数据为例,介绍R在空间可视化中的应用。其中,表2中相关省份的经纬度可以依据上述地理编码过程迅速生成——不过要对前面的编码函数稍作修改,以便不必输入subdistrict的信息;各省地理编码的结果实际上是其省会所在地的经纬度。本文拟基于这些编码数据采用线图形式做出珠三角外来工的空间分布图。其作图过程主要基于以下两个R程序包实现:ggmapmaptools包。前者可以免费使用Google MapOpenStreetMap的底图,背景信息较全;后者可以读取用户的Polygon数据(既可以是polygon也可以是polyline)。两者可以方便地在ggplot2的作图平台上进行整合。效果如图1所示。其中,底图为从OpenStreetMap截取的中国周边海陆边界及国家的分布图,其中包含了水体和国界等信息[ii];上一层是maptoolsreadShapeSpatial函数读取的中国主要省份的省界和国界。读者如果有完整的投影文件,还可通过Rrgdal包的readOGR函数或shapefiles包的read.shapefile函数读取);最上层的蓝线表示各省外来工的空间分布,线的粗细表示外来工人数。可以发现,其可视化效果比较美观,控制过程比较灵活,且能够与各种统计数据高效地衔接,因而是一种十分不错的可视化工具。

1 R生成的人口流动空间分布图


3 总结与讨论

目前,不同学科和政策部门对地理编码技术都有较高的需求;然而,目前国内对地理编码的理论和实证研究仍然很缺乏。为此,本文主要从实现技术的角度介绍了基于R语言和Google API的一种实现方法。其实现思路为首先整理地址数据的格式和结构,进而将地址生成GoogleAPI规定的查询格式,最后调用和保存返回的查询结果。支持这一过程的R软件包主要包括RCurlRJSONIOggmapplyr等;这些包的函数功能比较强大,应用比较灵活,执行速度较快。这种地理编码的思路还可以根据相应的查询规则转化到其他API平台(如YahooBing等);也非常容易与统计数据和Polygon数据等相互衔接整合。从生成效果来看,目前基于Google API的地理编码技术还存在一些缺陷。一方面,从技术上来看,Google API所提供的免费编码存在额度限制——每天不超过2500,其服务器的数据库与实时的GoogleMap查询库也存在一定的偏差,因此该方法更适用于比较容易在地图上识别且数量不多的情况,尤其适用于大型公司或居住区尺度或以上的调查。对于查询量较多的情况,可以通过付费、转换IP地址或其他API平台(尤其Yahoo平台不存在额度限制)来实现。另一方面,从编码效果看,原始的地址格式和结构对编码质量的影响非常大,编码结果的精度也存在不同程度的偏差。如果地址的顺序存在错乱、冗余或奇异值,地址解析的效果很可能不理想。为此,在实际的编码过程中,必须做好地址数据的预处理,并且对结果需要通过再编码等方式进行检查。但是,从RGoogle API免费、灵活和高效的特征看,这些弊端能够在未来加以改善和克服,因而是一种不错的地理编码、空间分析和可视化工具。


以下几个问题值得未来研究进一步探讨。(1)生成统一、高效的编码标准。编码标准是关系地理编码质量成败的关键。这一过程需要两方面的努力——一是在实际调查中,地址信息要尽量统一、详尽且便于识别。例如可以对不同层次的地区(省//详细地名)依次标注、记录周边最近的标志性地址(如大型超市、地铁站、公交站点等)、收集比自己研究数据尺度更详细一级的数据(即如果研究地级市的差异收集到县级市层面)等。二是应学习美国等在这方面的经验,促进统一地名标准的推广、数据库的扩充和冗余信息的排除等。(2)对不同编码方法的比较。不同软件和不同平台具有不同的编码规则和准确程度;因此,未来的研究中有必要加强对不同编码方式的比较,选取其中最高效、经济而又符合研究或政策需要的编码方法。(3)加强对基于R语言的空间分析和空间可视化的应用。国内地理学者可能更熟悉Arc GIS等空间分析平台;但是,R实际上是一种更为灵活、强大的空间分析工具。它不仅开源免费,而且更新非常快——目前R中专门用于空间分析和可视化的包已经有多达120多个[i],并且仍然呈现快速增长的趋势。同时,大数据处理、统计建模和图形处理等也日益依赖R语言。然而,目前国内基于R的地理学研究聊聊无几,唯一几个涉及R使用的空间研究还是由其他学科的学者实现[19-21]。因此,有必要推广R语言在中国地理学研究中的应用,从而不仅能促进很多复杂的空间分析方法的应用,还能更好地介入很多新兴的研究话题,从而进一步拓展和丰富地理学的研究。


附录:本文实现地理编码的R语言

1、生成Google API查询代码的函数geocode.url

geocode.url <- function(subdistrict = NULL,address, return.call ="json", sensor = "false") {

root <-"http://maps.google.com/maps/api/geocode/"

subdistrict <-paste(paste('%',unlist(iconv(subdistrict,from='GB2312',to="utf-8",toRaw=T)),sep=''),collapse='')

address <-paste(paste('%',unlist(iconv(address,from='GB2312',to="utf-8",toRaw=T)),sep=''),collapse='')

u <- paste(root,return.call, "?address=", address,"&components=sublocality:", subdistrict,

"|locality:Guangzhou|country:China&sensor=false","&sensor=", sensor, sep = "")

return(u <- gsub('','%20',u)) #Encode URL Parameters, replace space as "20%"

}


2、实现地理编码的函数GeoCode

GeoCode <- function(subdistrict = NULL,address,verbose=FALSE) {

if(verbose)cat(subdistrict,address,"\n") # whether output the address data

u <- mapply(geocode.url,subdistrict, address)

names(u) <-as.character(1:length(address)) # In case there are duplicated names

doc <- aaply(u,1,getURL)

json <-alply(doc,1,fromJSON,simplify = FALSE)

coord =laply(json,function(x) {

if(x$status=="OK") {

lat <-x$results[[1]]$geometry$location$lat

lng <-x$results[[1]]$geometry$location$lng

return(c(lat, lng))

} else {

return(c(NA,NA))

}

Sys.sleep(500)

})

if(length(address)>1)colnames(coord)=c("lat","lng")

elsenames(coord)=c("lat","lng")

return(coord)

}



Email:BeijingCityLab@gmail.com

Emaillist: BCL@freelist.org

新浪微博:北京城市实验室BCL

微信号:beijingcitylab

网址: http://www.beijingcitylab.com


赞(0)