使用python提取中文地址描述中的省市区信息

转 使用python提取中文地址描述中的省市区信息 2018年03月05日 14:44:00 weixin_34060741 阅读数 188 原文链接: http://www.jianshu.com/p/492440baca87

引言

【使用python提取中文地址描述中的省市区信息】在一次建模比赛中,我手头里的原始数据中有一个“地址描述”地段,如下:
地址描述
广州国际采购中心1401
上海市长宁区金钟路658弄5号楼5楼
徐汇区虹漕路461号58号楼5楼
济南市历下区和平路34号轻骑院内东二层山东朵拉
这样的地址描述字段过于随意,很难使用,但是看这些字符串的样子似乎又可以提取出其所在的省、市和区,即使只能够提取出区或者市,如果我们有一个省、市和区的归属数据库的话,应该也能够将剩下的信息映射出来,如果自己写的话肯定很麻烦,还要去网上找数据库,于是我做了一个可以复用的python模块,一条命令就可以将上面的“地址描述”字段转换成如下的样子:
广东省 广州市
上海市 上海市 长宁区
上海市 上海市 徐汇区
山东省 济南市 历下区
模块安装 目前支持python3
pip install cpca

Github地址 更详细的模块介绍见Github上的README
https://github.com/DQinYuan/chinese_province_city_area_mapper
如果觉得这个模块对你有帮助的话,请给个star啊
基本功能 分词模式 本模块中最主要的方法是cpca.transform,该方法可以输入任意的可迭代类型(如list,pandas的Series类型等),然后将其转换为一个DataFrame,下面演示一个最为简单的使用方法:
  1. location_str = ["徐汇区虹漕路461号58号楼5楼", "泉州市洛江区万安塘西工业区", "朝阳区北苑华贸城"]
  2. from cpca import *
  3. df = transform(location_str)
  4. df

输出的结果为:
  1. 区市省地址
  2. 0徐汇区上海市上海市虹漕路461号58号楼5楼
  3. 1洛江区泉州市福建省万安塘西工业区
  4. 2朝阳区北京市北京市北苑华贸城

注:程序输出的df是一个Pandas的DataFrame类型变量,DataFrame可以非常轻易地转化为csv或者excel文件,如果你对DataFrame不熟悉的话,可以参考Pandas的官方文档:http://pandas.pydata.org/pandas-docs/version/0.20/dsintro.html#dataframe
,或者往下翻到"示例与测试用例"大标题,那里我也展示了DataFrame的拼接与转换成csv文件的操作。
默认情况下transform方法的cut参数为True,即采用分词匹配的方式,这种方式速度比较快,但是准确率可能会比较低,如果追求准确率而不追求速度的话,建议将cut设为False(全文模式),具体见下一小节。
尝试着对代码稍加修改(其实就是将transform方法的umap参数置为空字典):
  1. location_str = ["徐汇区虹漕路461号58号楼5楼", "泉州市洛江区万安塘西工业区", "朝阳区北苑华贸城"]
  2. from cpca import *
  3. df = transform(location_str, umap={})
  4. df

会发现输出变为:
  1. 区市省地址
  2. 0徐汇区上海市上海市虹漕路461号58号楼5楼
  3. 1洛江区泉州市福建省万安塘西工业区
  4. 2朝阳区北苑华贸城

发现这种情况的原因是中国其实不止一个“朝阳区”,除了北京市有一个“朝阳区”外,长春市也有一个“朝阳区”,这样的话,程序就不知道该把“朝阳区”映射到哪个市。之所以前一段程序能够成功地将“朝阳区”映射成“北京市”,是因为当你不传umap参数的时候,会默认传一个笔者推荐的字典,其内容如下(在cpca.py中):
  1. myumap = {'南关区': '长春市',
  2. '南山区': '深圳市',
  3. '宝山区': '上海市',
  4. '市辖区': '东莞市',
  5. '普陀区': '上海市',
  6. '朝阳区': '北京市',
  7. '河东区': '天津市',
  8. '白云区': '广州市',
  9. '西湖区': '杭州市',
  10. '铁西区': '沈阳市'}

你会发现,其中指定了将”朝阳区“映射到北京市,因为笔者在测试数据中发现,数据中的”朝阳区“基本上都是指北京市那个”朝阳区“(原因可能是北京市的”朝阳区“的经济以及知名度要远比长春市的那个”朝阳区“发达)。当然,默认的这个umap并没有囊括中国所有的重名区,因为有的时候,两个重名区在数据中都经常被提及,无法强制指定将某个区映射成固定的市,比如福州市的“鼓楼区”与南京市的“鼓楼区”,都是经常被提及的地名。
看看下面一个例子:
  1. location_str = ["福建省鼓楼区软件大道89号"]
  2. from cpca import *
  3. df = transform(location_str)
  4. df

输出结果为:
  1. 区市省地址
  2. 0鼓楼区福建省软件大道89号

可以看到,市没有被成功提取出来,并且还会产生一个警告信息:
WARNING:root:建议添加到umap中的区有:{'鼓楼区'},有多个市含有相同名称的区

当程序发现重名区并且不知道将其映射到哪一个市时,会将其加入警告信息,提示用户最好根据数据给它指定一个市进行映射。
当使用以下代码时就能成功地将“鼓楼区”映射到“福州市”:
  1. location_str = ["福建省鼓楼区软件大道89号"]
  2. from cpca import *
  3. df = transform(location_str, umap={"鼓楼区":"福州市"})
  4. df

输出结果:
  1. 区市省地址
  2. 0鼓楼区福州市福建省软件大道89号

好在中国只有在三级行政区存在重名问题,二级与一级行政区的名称都是唯一的。
有的时候为了方便concat,想要自定义输出表的index,可以选择使用transform函数的index参数(这个参数只要保证长度和data相同即可,可以是list或者pandas中相关的类型),示例如下:
  1. location_str = ["徐汇区虹漕路461号58号楼5楼", "泉州市洛江区万安塘西工业区", "朝阳区北苑华贸城"]
  2. from cpca import *
  3. df = transform(location_str, index=["2018年","2017年","2016年"])
  4. df

输出结果:
  1. 区市省地址
  2. 2018年徐汇区上海市上海市虹漕路461号58号楼5楼
  3. 2017年洛江区泉州市福建省万安塘西工业区
  4. 2016年朝阳区北京市北京市北苑华贸城

全文模式 jieba分词并不能百分之百保证分词的正确性,在分词错误的情况下会造成奇怪的结果,比如下面:
  1. location_str = ["浙江省杭州市下城区青云街40号3楼","广东省东莞市莞城区东莞大道海雅百货"]
  2. from cpca import *
  3. df = transform(location_str)
  4. df

输出的结果为:
  1. 区市省地址
  2. 0 城区东莞市广东省莞大道海雅百货自然堂专柜
  3. 1 城区杭州市浙江省下青云街40号3楼

这种诡异的结果是因为jieba本身就将词给分错了,所以我们引入了全文模式,不进行分词,直接全文匹配,使用方法如下:
  1. location_str = ["浙江省杭州市下城区青云街40号3楼","广东省东莞市莞城区东莞大道海雅百货"]
  2. from cpca import *
  3. df = transform(location_str, cut=False)
  4. df

结果如下:
  1. 区市省地址
  2. 0下城区杭州市浙江省青云街40号3楼
  3. 1莞城区东莞市广东省大道海雅百货

这下就完全正确了,不过全文匹配模式会造成匹配效率低下,我默认会向前看8个字符(对应transform中的lookahead参数默认值为8),这个是比较保守的,因为有的地名会比较长(比如“新疆维吾尔自治区”),如果你的地址库中都是些短小的省市区名的话,可以选择将lookahead设置得小一点,比如:
  1. location_str = ["浙江省杭州市下城区青云街40号3楼","广东省东莞市莞城区东莞大道海雅百货"]
  2. from cpca import *
  3. df = transform(location_str, cut=False, lookahead=3)
  4. df

输出结果和之前是一样的。
地图绘制 模块中还自带一些简单绘图工具,可以在地图上将上面输出的数据以热力图的形式画出来.
这个工具依赖folium,为了减小本模块的体积,所以并不会预装这个依赖,在使用之前请使用pip install folium .
代码如下:
  1. from cpca_drawers import *
  2. #df为上一段代码输出的df
  3. draw_locations(df, "df.html")

这一段代码运行结束后会在运行代码的当前目录下生成一个df.html文件,用浏览器打开即可看到
绘制好的地图(如果某条数据'省','市'或'区'字段有缺,则会忽略该条数据不进行绘制),速度会比较慢,需要耐心等待,绘制的图像如下:
使用python提取中文地址描述中的省市区信息
文章图片
地图绘制 还有更多的绘图工具请参考Github上的README中大标题为“示例与测试用例”的部分。

    推荐阅读