一个用于提取简体中文字符串中省,市和区并能够进行映射,检验和简单绘图的python模块...
簡介
一個用于提取簡體中文字符串中省,市和區(qū)并能夠進行映射,檢驗和簡單繪圖的python模塊。
舉個例子:
["徐匯區(qū)虹漕路461號58號樓5樓", "泉州市洛江區(qū)萬安塘西工業(yè)區(qū)"]↓ 轉(zhuǎn)換 |省 |市 |區(qū) |地址 | |上海市|上海市|徐匯區(qū)|虹漕路461號58號樓5樓 | |福建省|泉州市|洛江區(qū)|萬安塘西工業(yè)區(qū) |注:“地址”列代表去除了省市區(qū)之后的具體地址
安裝說明
代碼目前僅僅支持python3
pip install cpca
注:cpca是chinese province city area的縮寫
常見安裝錯誤:
? 有的朋友在我的博客中反映他們在使用的時候會報如下錯誤:
ModuleNotFoundError: No module named 'jieba'? 可能是因為某種原因,依賴未能成功的安裝上去,這個時候則需要手動使用pip install jieba命令進行安裝。
如果覺得本模塊對你有用的話,施舍個star,謝謝。
中國三級行政區(qū)劃分(參考自百度百科)
| 一級行政區(qū)(省級行政區(qū)) | 34個(23個省、5個自治區(qū)、4個直轄市、2個特別行政區(qū)) |
| 二級行政區(qū)(地級行政區(qū)) | 334個(294個地級市、7個地區(qū)、30個自治州、3個盟) |
| 三級行政區(qū)(縣級行政區(qū)) | 2876個(987個市轄區(qū)、363個縣級市、1355個縣、117自治縣、49個旗、3個自治旗、1個特區(qū)、1個林區(qū)) |
特點
- 基于jieba分詞進行匹配,同時加入了一些額外的校驗匹配邏輯
- 因為jieba分詞本身有時候會分錯,所以引入了全文匹配的模式,這種模式下能夠提高準(zhǔn)確率,但會導(dǎo)致性能降低,關(guān)于如何開啟這個模式見下面的使用文檔或者?issue #11
- 如果地址數(shù)據(jù)比較臟的,不能指望依靠這個模塊達(dá)到100%的準(zhǔn)確,本模塊只能保證盡可能地提取信息,如果想要達(dá)到100%準(zhǔn)確率的話,最好在匹配完后再人工核驗一下
- 自帶完整的省,市,區(qū)三級地名及其經(jīng)緯度的數(shù)據(jù)
- 支持自定義省,市,區(qū)映射
- 輸出的是基于pandas的DataFrame類型的表結(jié)構(gòu),易于理解和使用
- 封裝了簡單的繪圖功能,可以很方便地進行簡單的數(shù)據(jù)可視化
- MIT 授權(quán)協(xié)議
Get Started
分詞模式:
本模塊中最主要的方法是cpca.transform,該方法可以輸入任意的可迭代類型(如list,pandas的Series類型等),然后將其轉(zhuǎn)換為一個DataFrame,下面演示一個最為簡單的使用方法:
location_str = ["徐匯區(qū)虹漕路461號58號樓5樓", "泉州市洛江區(qū)萬安塘西工業(yè)區(qū)", "朝陽區(qū)北苑華貿(mào)城"] from cpca import * df = transform(location_str) df輸出的結(jié)果為:
區(qū) 市 省 地址 0 徐匯區(qū) 上海市 上海市 虹漕路461號58號樓5樓 1 洛江區(qū) 泉州市 福建省 萬安塘西工業(yè)區(qū) 2 朝陽區(qū) 北京市 北京市 北苑華貿(mào)城注:程序輸出的df是一個Pandas的DataFrame類型變量,DataFrame可以非常輕易地轉(zhuǎn)化為csv或者excel文件,如果你對DataFrame不熟悉的話,可以參考Pandas的官方文檔:http://pandas.pydata.org/pandas-docs/version/0.20/dsintro.html#dataframe
,或者往下翻到"示例與測試用例"大標(biāo)題,那里我也展示了DataFrame的拼接與轉(zhuǎn)換成csv文件的操作。
默認(rèn)情況下transform方法的cut參數(shù)為True,即采用分詞匹配的方式,這種方式速度比較快,但是準(zhǔn)確率可能會比較低,如果追求準(zhǔn)確率而不追求速度的話,建議將cut設(shè)為False(全文模式),具體見下一小節(jié)。
嘗試著對代碼稍加修改(其實就是將transform方法的umap參數(shù)置為空字典):
location_str = ["徐匯區(qū)虹漕路461號58號樓5樓", "泉州市洛江區(qū)萬安塘西工業(yè)區(qū)", "朝陽區(qū)北苑華貿(mào)城"] from cpca import * df = transform(location_str, umap={}) df會發(fā)現(xiàn)輸出變?yōu)?#xff1a;
區(qū) 市 省 地址 0 徐匯區(qū) 上海市 上海市 虹漕路461號58號樓5樓 1 洛江區(qū) 泉州市 福建省 萬安塘西工業(yè)區(qū) 2 朝陽區(qū) 北苑華貿(mào)城發(fā)現(xiàn)這種情況的原因是中國其實不止一個“朝陽區(qū)”,除了北京市有一個“朝陽區(qū)”外,長春市也有一個“朝陽區(qū)”,這樣的話,程序就不知道該把“朝陽區(qū)”映射到哪個市。之所以前一段程序能夠成功地將“朝陽區(qū)”映射成“北京市”,是因為當(dāng)你不傳umap參數(shù)的時候,會默認(rèn)傳一個筆者推薦的字典,其內(nèi)容如下(在cpca.py中):
myumap = {'南關(guān)區(qū)': '長春市', '南山區(qū)': '深圳市', '寶山區(qū)': '上海市', '市轄區(qū)': '東莞市', '普陀區(qū)': '上海市', '朝陽區(qū)': '北京市', '河?xùn)|區(qū)': '天津市', '白云區(qū)': '廣州市', '西湖區(qū)': '杭州市', '鐵西區(qū)': '沈陽市'}你會發(fā)現(xiàn),其中指定了將”朝陽區(qū)“映射到北京市,因為筆者在測試數(shù)據(jù)中發(fā)現(xiàn),數(shù)據(jù)中的”朝陽區(qū)“基本上都是指北京市那個”朝陽區(qū)“(原因可能是北京市的”朝陽區(qū)“的經(jīng)濟以及知名度要遠(yuǎn)比長春市的那個”朝陽區(qū)“發(fā)達(dá))。當(dāng)然,默認(rèn)的這個umap并沒有囊括中國所有的重名區(qū),因為有的時候,兩個重名區(qū)在數(shù)據(jù)中都經(jīng)常被提及,無法強制指定將某個區(qū)映射成固定的市,比如福州市的“鼓樓區(qū)”與南京市的“鼓樓區(qū)”,都是經(jīng)常被提及的地名。
看看下面一個例子:
location_str = ["福建省鼓樓區(qū)軟件大道89號"] from cpca import * df = transform(location_str) df輸出結(jié)果為:
區(qū) 市 省 地址 0 鼓樓區(qū) 福建省 軟件大道89號可以看到,市沒有被成功提取出來,并且還會產(chǎn)生一個警告信息:
WARNING:root:建議添加到umap中的區(qū)有:{'鼓樓區(qū)'},有多個市含有相同名稱的區(qū)當(dāng)程序發(fā)現(xiàn)重名區(qū)并且不知道將其映射到哪一個市時,會將其加入警告信息,提示用戶最好根據(jù)數(shù)據(jù)給它指定一個市進行映射。
當(dāng)使用以下代碼時就能成功地將“鼓樓區(qū)”映射到“福州市”:
location_str = ["福建省鼓樓區(qū)軟件大道89號"] from cpca import * df = transform(location_str, umap={"鼓樓區(qū)":"福州市"}) df輸出結(jié)果:
區(qū) 市 省 地址 0 鼓樓區(qū) 福州市 福建省 軟件大道89號好在中國只有在三級行政區(qū)存在重名問題,二級與一級行政區(qū)的名稱都是唯一的。
有的時候為了方便concat,想要自定義輸出表的index,可以選擇使用transform函數(shù)的index參數(shù)(這個參數(shù)只要保證長度和data相同即可,可以是list或者pandas中相關(guān)的類型),示例如下:
location_str = ["徐匯區(qū)虹漕路461號58號樓5樓", "泉州市洛江區(qū)萬安塘西工業(yè)區(qū)", "朝陽區(qū)北苑華貿(mào)城"] from cpca import * df = transform(location_str, index=["2018年","2017年","2016年"]) df輸出結(jié)果:
區(qū) 市 省 地址 2018年 徐匯區(qū) 上海市 上海市 虹漕路461號58號樓5樓 2017年 洛江區(qū) 泉州市 福建省 萬安塘西工業(yè)區(qū) 2016年 朝陽區(qū) 北京市 北京市 北苑華貿(mào)城全文模式:
這個模式的出現(xiàn)是為解決issue #11?所提到的問題。
jieba分詞并不能百分之百保證分詞的正確性,在分詞錯誤的情況下會造成奇怪的結(jié)果,比如下面:
location_str = ["浙江省杭州市下城區(qū)青云街40號3樓","廣東省東莞市莞城區(qū)東莞大道海雅百貨"] from cpca import * df = transform(location_str) df輸出的結(jié)果為:
區(qū) 市 省 地址 0 城區(qū) 東莞市 廣東省 莞大道海雅百貨自然堂專柜 1 城區(qū) 杭州市 浙江省 下青云街40號3樓這種詭異的結(jié)果是因為jieba本身就將詞給分錯了,所以我們引入了全文模式,不進行分詞,直接全文匹配,使用方法如下:
location_str = ["浙江省杭州市下城區(qū)青云街40號3樓","廣東省東莞市莞城區(qū)東莞大道海雅百貨"] from cpca import * df = transform(location_str, cut=False) df結(jié)果如下:
區(qū) 市 省 地址 0 下城區(qū) 杭州市 浙江省 青云街40號3樓 1 莞城區(qū) 東莞市 廣東省 大道海雅百貨這下就完全正確了,不過全文匹配模式會造成匹配效率低下,我默認(rèn)會向前看8個字符(對應(yīng)transform中的lookahead參數(shù)默認(rèn)值為8),這個是比較保守的,因為有的地名會比較長(比如“新疆維吾爾族自治區(qū)”),如果你的地址庫中都是些短小的省市區(qū)名的話,可以選擇將lookahead設(shè)置得小一點,比如:
location_str = ["浙江省杭州市下城區(qū)青云街40號3樓","廣東省東莞市莞城區(qū)東莞大道海雅百貨"] from cpca import * df = transform(location_str, cut=False, lookahead=3) df輸出結(jié)果和上面是一樣的。
繪圖:
模塊中還自帶一些簡單繪圖工具,可以在地圖上將上面輸出的數(shù)據(jù)以熱力圖的形式畫出來.
這個工具依賴folium,為了減小本模塊的體積,所以并不會預(yù)裝這個依賴,在使用之前請使用pip install folium?.
代碼如下:
from cpca_drawers import * #df為上一段代碼輸出的df draw_locations(df, "df.html")這一段代碼運行結(jié)束后會在運行代碼的當(dāng)前目錄下生成一個df.html文件,用瀏覽器打開即可看到 繪制好的地圖(如果某條數(shù)據(jù)'省','市'或'區(qū)'字段有缺,則會忽略該條數(shù)據(jù)不進行繪制),速度會比較慢,需要耐心等待,繪制的圖像如下:
draw_locations函數(shù)還可以通過指定path參數(shù)來改變輸出路徑,示例代碼如下:
from cpca_drawers import * #在當(dāng)前目錄的父目錄生成df.html draw_locations(df, "df.html", path="../")還有更多的繪圖工具請參考文檔的大標(biāo)題為“示例與測試用例”的部分。
到這里就你就已經(jīng)知道了本模塊的基本使用了,接下來我會闡明更多細(xì)節(jié)。
數(shù)據(jù)接口
本模塊自帶全國省市區(qū)的映射關(guān)系及其經(jīng)緯度,如果你只是想使用這個數(shù)據(jù)的話可以使用如下代碼:
from chinese_province_city_area_mapper.infrastructure import SuperMap #地區(qū)到市的映射數(shù)據(jù)庫,是一個字典類型(key為區(qū)名,value為其所屬的市名),注意其中包含重復(fù)的區(qū)名 SuperMap.area_city_mapper #重復(fù)的區(qū)名列表,列表類型,如果區(qū)名在這個列表中,說明存在多個同名區(qū),則area_city_mapper的映射是不準(zhǔn)確的 SuperMap.rep_areas #市到省的映射數(shù)據(jù)庫,字典類型(key為市的名稱,value為省的名稱) SuperMap.city_province_mapper #全國省市區(qū)的經(jīng)緯度數(shù)據(jù)庫,字典類型(key為"省,市,區(qū)",value為(維度,經(jīng)度)) SuperMap.lat_lon_mapper #獲取北京市朝陽區(qū)的經(jīng)緯度 SuperMap.lat_lon_mapper.get("北京市,北京市,朝陽區(qū)") #獲得一個地名的級別(即省,市或者區(qū)) SuperMap.getType("江蘇省") #返回"province",即常量SuperMap.PROVINCE SuperMap.getType("南京市") #返回"city",即常量SuperMap.CITY SuperMap.getType("海淀區(qū)") #返回"area",即常量SuperMap.AREA #省略"省"字也能夠識別出來 SuperMap.getType("江蘇")關(guān)于匹配與映射的細(xì)節(jié)
為了保證匹配與映射的正確性,我做了很多細(xì)節(jié)上的處理,如果在使用本模塊的過程中遇到困惑可以參考這里。
- 能夠匹配到省或者市的縮寫,比如將"北京市"縮寫為"北京","江蘇省"縮寫為"江蘇",依舊能夠匹配到并且能夠自動補全為全稱,示例代碼如下:
輸出的結(jié)果為:
區(qū) 市 省 地址 0 鼓樓區(qū) 南京市 江蘇省 256號 1 鼓樓區(qū) 南京市 江蘇省 256號- 能夠自動檢測字符串中匹配到的省,市和區(qū)是否是所屬關(guān)系,如果不是所屬關(guān)系的話,則會刪去優(yōu)先級較低的(注:如果匹配到的是縮寫的話,即將"南京市"縮寫為"南京",則認(rèn)為優(yōu)先級較低),如果優(yōu)先級一樣的話,則刪除地域范圍較小的,示例代碼如下:
輸出結(jié)果如下:
區(qū) 市 省 地址 0 靜安區(qū) 上海市 上海市 西路30號 1 南京市 江蘇省 2 江蘇省 3 靜安區(qū) 上海市 上海市 西路分析:第一個測試數(shù)據(jù)"靜安區(qū)南京西路"會同時匹配到"靜安區(qū)"和"南京"兩個地域名稱,但是靜安區(qū)是屬于上海的,和"南京"相矛盾,而且因為"南京"是"南京市"的縮寫,因此優(yōu)先級比較低,故放棄"南京"這個地域名稱。
第二個測試數(shù)據(jù)匹配到"南京市"和"靜安區(qū)"兩個矛盾的地域名稱,而且這兩個名稱都是全稱,優(yōu)先級相同,所以保留地域范圍比較大的,即保留"南京市"而放棄"靜安區(qū)"。第三個測試數(shù)據(jù)也是一樣的道理。
第四個測試數(shù)據(jù)中有兩個市的名稱會被匹配到,一個是"上海市",還有一個是"南京",但是因為"上海市"在前面被匹配到了,所以"南京"就會被忽略。
注意:從上面的例子你會看到,對于這種地址字段在句子中間出現(xiàn)的情況,模塊提取出的"地址"列會有些bug,這個目前暫時解決起來比較麻煩,如果地址數(shù)據(jù)中有大量這種數(shù)據(jù)的話,建議不要使用模塊提取出的"地址"列
示例與測試用例
本倉庫放了一份大約一萬多條地址描述信息addr.csv,用于測試模塊,測試代碼如下:
測試基本功能:
#讀取數(shù)據(jù) import pandas as pd origin = pd.read_csv("addr.csv") #轉(zhuǎn)換 from cpca import * addr_df = transform(origin["原始地址"], myumap) #輸出 processed = pd.concat([origin, addr_df], axis=1) processed.to_csv("processed.csv", index=False, encoding="utf-8")注意以上代碼運行結(jié)束后會打印一句warnning,這些warnning是因為程序無法確定某個區(qū)縣屬于哪個市(因為這些區(qū)縣存在重名問題而且在umap中又沒有指定它屬于哪一個市).
測試?yán)L圖函數(shù)1(繪制熱力圖):
模塊中繪制熱力圖的函數(shù)是基于folium編寫的,為了減小模塊體積,在安裝模塊時沒有安裝這些繪圖庫的依賴,如果需要使用這個函數(shù)的話,需要先使用pip install folium?安裝folium
from cpca_drawers import * #processed為上一段代碼的processed draw_locations(processed, "processed.html")用瀏覽器打開"processed.html"文件,發(fā)現(xiàn)繪制的局部圖像如下(在國內(nèi)folium的地圖顯示速度比較慢,所以需要耐心等待地圖顯示):
(注意:本模塊在繪圖時,只繪制那些可以精確地匹配到省市區(qū)的地址,對于省市區(qū)有一個或多個字段缺失的則會直接忽略)
測試?yán)L圖函數(shù)2(繪制echarts熱力圖):
因為在國內(nèi)folium的地圖顯示速度太慢了,所以添加了echarts的熱力圖繪圖函數(shù).
在使用本函數(shù)之前需要先用如下命令安裝它的依賴(為了減少本模塊的體積,所以這些依賴不會被自動安裝):
pip install pyecharts pip install echarts-countries-pypkg pip install pyecharts-snapshot示例代碼如下,仍然使用之前的測試數(shù)據(jù)生成的processed變量:
from cpca_drawers import * echarts_draw(processed, "test.html")該接口的更多參數(shù)及其含義如下:
def echarts_draw(locations, fileName, path="./", title="地域分布圖" , subtitle="location distribute"): """ 生成地域分布的echarts熱力圖的html文件. :param locations: 樣本的省市區(qū), pandas的dataframe類型. :param fileName: 生成的html文件的文件名. :param path: 生成的html文件的路徑. :param title: 圖表的標(biāo)題 :param subtitle: 圖表的子標(biāo)題 """然后會在當(dāng)前目錄下生成一個test.html文件,用瀏覽器打開后即可看到圖像:
測試?yán)L圖函數(shù)3(繪制分類信息圖):
在使用本函數(shù)之前需要安裝的依賴同上一個繪圖函數(shù),如果你是跳過了前面的直接讀到這里的話,務(wù)必向上翻看一下。
樣本分類繪制函數(shù),通過額外傳入一個樣本的分類信息,能夠在地圖上以不同的顏色畫出屬于不同分類的樣本散點圖,以下代碼以“省”作為類別信息繪制分類散點圖(可以看到,屬于不同省的樣本被以不同的顏色標(biāo)記了出來,這里以“省”作為分類標(biāo)準(zhǔn)只是舉個例子,實際應(yīng)用中可以選取更加有實際意義的分類指標(biāo)):
from cpca_drawers import * echarts_cate_draw(processed, processed["省"], "test2.html")然后會在當(dāng)前目錄下生成一個test2.html文件,用瀏覽器打開后即可看到圖像:
該接口更多的參數(shù)及其含義如下:
def echarts_cate_draw(locations, labels, fileName, path="./" , title="地域分布圖", subtitle="location distribute", point_size=7): """ 依據(jù)分類生成地域分布的echarts散點圖的html文件. :param locations: 樣本的省市區(qū), pandas的dataframe類型. :param labels: 長度必須和locations相等, 代表每個樣本所屬的分類. :param fileName: 生成的html文件的文件名. :param path: 生成的html文件的路徑. :param title: 圖表的標(biāo)題 :param subtitle: 圖表的子標(biāo)題 :param point_size: 每個散點的大小,如果樣本數(shù)較少可以考慮設(shè)置的大一些 """END
如果大家在使用過程中發(fā)現(xiàn)一些匹配錯誤的地址,歡迎提issue來幫助我收集這些錯誤用例和改善算法,畢竟筆者手頭數(shù)據(jù)有限,難以考慮到所有邊界情況
轉(zhuǎn)載于:https://www.cnblogs.com/wu-chao/p/10081988.html
總結(jié)
以上是生活随笔為你收集整理的一个用于提取简体中文字符串中省,市和区并能够进行映射,检验和简单绘图的python模块...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sprint2第三天任务完成情况
- 下一篇: web 前端基本框架