簡介
一個用於提取簡體中文字符串中省,市和區並能夠進行映射,檢驗和簡單繪圖的python模塊。
舉個例子:
["徐彙區虹漕路461號58號樓5樓", "泉州市洛江區萬安塘西工業區"]
↓ 轉換
|省 |市 |區 |
|上海市|上海市|徐彙區|
|福建省|泉州市|洛江區|
如果你只是想快速實現以上類型的數據處理的話,那麼只需要複製以下代碼,不需要過多閱讀本文檔的內容(複製代碼之前,先閱讀安裝說明將本模塊裝上):
location_str = ["徐彙區虹漕路461號58號樓5樓", "泉州市洛江區萬安塘西工業區", "朝陽區北苑華貿城"] #任意的可迭代類型,比如Series也可以
from chinese_province_city_area_mapper.transformer import CPCATransformer
from chinese_province_city_area_mapper import myumap
cpca = CPCATransformer(myumap.umap)
df = cpca.transform(location_str)
df
安裝說明
代碼目前僅僅支持python3
pip install chinese_province_city_area_mapper
特點
基於jieba分詞進行匹配,同時用比較複雜的匹配邏輯保證了準確率,筆者根據手頭的海量地址描述數據進行了測試自帶完整的省,市,區三級地名及其經緯度的數據支持自定義省,市,區映射輸出的是基於pandas的DataFrame類型的表結構,易於理解和使用封裝了簡單的繪圖功能,可以很方便地進行簡單的數據可視化MIT 授權協議Get Started
本模塊中最主要的類是chinese_province_city_area_mapper.transformer.CPCATransformer(注:CPCA是Chinese Province City Area的縮寫),該類的transform方法可以輸入任意的可迭代類型(如list,Series等),然後將其轉換為一個DataFrame,示例代碼如下:
location_str = ["徐彙區虹漕路461號58號樓5樓", "泉州市洛江區萬安塘西工業區", "朝陽區北苑華貿城"]
from chinese_province_city_area_mapper.transformer import CPCATransformer
cpca = CPCATransformer()
df = cpca.transform(location_str)
df
輸出的結果為:
區 市 省
0 徐彙區 上海市 上海市
1 洛江區 泉州市 福建省
2 朝陽區
從上面的程序輸出中你會發現朝陽區並沒有被映射到北京市,這是因為在中國有多個同名的叫做朝陽區的區,並且他們位於不同的市,所以程序就不知道該映射到哪一個市了(舉個例子,南京市有一個鼓樓區,開封市有一個鼓樓區,福州市也有一個鼓樓區,這樣程序就不知道應該把鼓樓區映射到哪一個市了),因此就不對其進行映射,如果你確定你的數據中的朝陽區都是指北京市的那個朝陽區的話,可以在CPCATransformer的構造函數中傳一個字典(叫做umap參數,是user map的簡稱),指定朝陽區都要映射到北京市,注意只有區到市的這一級映射存在重名問題,中國的市的名稱都是唯一的,省的名稱也都是唯一的,示例代碼如下:
location_str = ["徐彙區虹漕路461號58號樓5樓", "泉州市洛江區萬安塘西工業區", "朝陽區北苑華貿城"]
from chinese_province_city_area_mapper.transformer import CPCATransformer
cpca = CPCATransformer({"朝陽區":"北京市"})
df = cpca.transform(location_str)
df
輸出結果為:
區 市 省
0 徐彙區 上海市 上海市
1 洛江區 泉州市 福建省
2 朝陽區 北京市 北京市
模塊中還內置了一個我推薦大家使用的umap,這個umap中我根據處理地址數據的經驗將那些重名的區映射到了它最常見的一個市,這個umap位於chinese_province_city_area_mapper.myumap.umap,使用如下:
location_str = ["徐彙區虹漕路461號58號樓5樓", "泉州市洛江區萬安塘西工業區", "朝陽區北苑華貿城"]
from chinese_province_city_area_mapper.transformer import CPCATransformer
from chinese_province_city_area_mapper import myumap
print(myumap.umap) #查看這個umap的內容
cpca = CPCATransformer(myumap.umap)
df = cpca.transform(location_str)
df
輸出和上一個程序一樣
模塊中還自帶一個簡單繪圖工具,可以在地圖上將上面輸出的數據以熱力圖的形式畫出來,代碼如下:
from chinese_province_city_area_mapper import drawers
#df為上一段代碼輸出的df
drawers.draw_locations(df, "df.html")
這一段代碼運行結束後會在運行代碼的當前目錄下生成一個df.html文件,用瀏覽器打開即可看到 繪製好的地圖(如果某條數據'省','市'或'區'字段有缺,則會忽略該條數據不進行繪製),速度會比較慢,需要耐心等待,繪製的圖像如下:
draw_locations函數還可以通過指定path參數來改變輸出路徑,示例代碼如下::
from chinese_province_city_area_mapper import drawers
#在當前目錄的父目錄生成df.html
drawers.draw_locations(df, "df.html", path="../")
到這裡就你就已經知道了本模塊的基本使用了,接下來我會闡明更多細節。
數據接口
本模塊自帶全國省市區的映射關係及其經緯度,如果你只是想使用這個數據的話可以使用如下代碼:
from chinese_province_city_area_mapper.infrastructure import SuperMap
#地區到市的映射數據庫,是一個字典類型(key為區名,value為其所屬的市名),注意其中包含重複的區名
SuperMap.area_city_mapper
#重複的區名列表,列表類型,如果區名在這個列表中,說明存在多個同名區,則area_city_mapper的映射是不準確的
SuperMap.rep_areas
#市到省的映射數據庫,字典類型(key為市的名稱,value為省的名稱)
SuperMap.city_province_mapper
#全國省市區的經緯度數據庫,字典類型(key為"省,市,區",value為(維度,經度))
SuperMap.lat_lon_mapper
#獲取北京市朝陽區的經緯度
SuperMap.lat_lon_mapper.get("北京市,北京市,朝陽區")
#獲得一個地名的級別(即省,市或者區)
SuperMap.getType("江蘇省") #返回"province",即常量SuperMap.PROVINCE
SuperMap.getType("南京市") #返回"city",即常量SuperMap.CITY
SuperMap.getType("海淀區") #返回"area",即常量SuperMap.AREA
#省略"省"字也能夠識別出來
SuperMap.getType("江蘇")
關於匹配與映射的細節
為了保證匹配與映射的正確性,我做了很多細節上的處理,如果在使用本模塊的過程中遇到困惑可以參考這裡。
能夠匹配到省或者市的縮寫,比如將"北京市"縮寫為"北京","江蘇省"縮寫為"江蘇",依舊能夠匹配到並且能夠自動補全為全稱,示例代碼如下:#測試數據
location_strs = ["江蘇省南京市鼓樓區256號", "江蘇南京鼓樓區256號"]
from chinese_province_city_area_mapper.transformer import CPCATransformer
cpca = CPCATransformer()
df = cpca.transform(location_strs)
df
輸出的結果為:
區 市 省
0 鼓樓區 南京市 江蘇省
1 鼓樓區 南京市 江蘇省
能夠自動檢測字符串中匹配到的省,市和區是否是所屬關係,如果不是所屬關係的話,則會刪去優先級較低的(注:如果匹配到的是縮寫的話,即將"南京市"縮寫為"南京",則認為優先級較低),如果優先級一樣的話,則刪除地域範圍較小的,示例代碼如下:#測試數據,一些故意錯亂的地址描述
location_strs = ["靜安區南京西路30號", "南京市靜安區", "江蘇省上海市", "上海市靜安區南京西路"]
from chinese_province_city_area_mapper.transformer import CPCATransformer
cpca = CPCATransformer()
df = cpca.transform(location_strs)
df
輸出結果如下:
區 市 省
0 靜安區 上海市 上海市
1 南京市 江蘇省
2 江蘇省
3 靜安區 上海市 上海市
分析:第一個測試數據"靜安區南京西路"會同時匹配到"靜安區"和"南京"兩個地域名稱,但是靜安區是屬於上海的,和"南京"想矛盾,而且因為"南京"是"南京市"的縮寫,因此優先級比較低,故放棄"南京"這個地域名稱。
第二個測試數據匹配到"南京市"和"靜安區"兩個矛盾的地域名稱,而且這兩個名稱都是全稱,優先級相同,所以保留地域範圍比較大的,即保留"南京市"而放棄"靜安區"。第三個測試數據也是一樣的道理。
第四個測試數據中有兩個市的名稱會被匹配到,一個是"上海市",還有一個是"南京",但是因為"上海市"在前面被匹配到了,所以"南京"就會被忽略。
測試數據
本倉庫放了一份大約一萬多條地址描述信息addr.csv,這是我當時測試與開發用的數據,目前的版本可以保證比較高的準確率,大家可以用這個數據繼續進行測試,測試代碼如下:
#讀取數據
import pandas as pd
origin = pd.read_csv("addr.csv")
#轉換
from chinese_province_city_area_mapper.transformer import CPCATransformer
from chinese_province_city_area_mapper import myumap
cpca = CPCATransformer(myumap.umap)
addr_df = cpca.transform(origin["原始地址"])
#輸出
processed = pd.concat([origin, addr_df], axis=1)
processed.to_csv("processed.csv", index=False, encoding="utf-8")
注意以上代碼會產生產生大量的warnning,這些warnning是因為程序無法確定某個區縣屬於哪個市(因為這些區縣存在重名問題而且在umap中又沒有指定它屬於哪一個市).
繪圖代碼:
from chinese_province_city_area_mapper import drawers
#processed為上一段代碼的processed
drawers.draw_locations(processed, "processed.html")
繪製的局部圖像如下:
(注意:本模塊在繪圖時,只繪製那些可以精確地匹配到省市區的地址,對於省市區有一個或多個字段缺失的則會直接忽略)
-----------------------------------以下為2.0版本新增的接口----------------------------------------------
更新模塊
通過pip list查看模塊版本,如果版本低於2.0,則應該使用如下的命令更新模塊:
pip install -U chinese_province_city_area_mapper
新的繪圖接口
之前版本的繪圖接口是基於folium編寫的,但是在國內folium的地圖顯示速度太慢了,所以2.0版本在保留原本的folium繪圖接口的基礎上添加了echarts的繪圖接口.
第一個接口是echarts熱力圖繪製接口,代碼如下,仍然使用之前的測試數據生成的processed變量:
from chinese_province_city_area_mapper import drawers
drawers.echarts_draw(processed, "test.html")
該接口的更多參數及其含義如下:
def echarts_draw(locations, fileName, path="./", title="地域分佈圖"
, subtitle="location distribute"):
"""
生成地域分佈的echarts熱力圖的html文件.
:param locations: 樣本的省市區, pandas的dataframe類型.
:param fileName: 生成的html文件的文件名.
:param path: 生成的html文件的路徑.
:param title: 圖表的標題
:param subtitle: 圖表的子標題
"""
然後會在當前目錄下生成一個test.html文件,用瀏覽器打開後即可看到圖像:
第二個接口是樣本分類繪製接口,通過額外傳入一個樣本的分類信息,能夠在地圖上以不同的顏色畫出屬於不同分類的樣本散點圖,以下代碼以“省”作為類別信息繪製分類散點圖(可以看到,屬於不同省的樣本被以不同的顏色標記了出來,這裡以“省”作為分類標準只是舉個例子,實際應用中可以選取更加有實際意義的分類指標):
from chinese_province_city_area_mapper import drawers
drawers.echarts_cate_draw(processed, processed["省"], "test2.html")
然後會在當前目錄下生成一個test2.html文件,用瀏覽器打開後即可看到圖像:
該接口更多的參數及其含義如下:
def echarts_cate_draw(locations, labels, fileName, path="./"
, title="地域分佈圖", subtitle="location distribute",
point_size=7):
"""
依據分類生成地域分佈的echarts散點圖的html文件.
:param locations: 樣本的省市區, pandas的dataframe類型.
:param labels: 長度必須和locations相等, 代表每個樣本所屬的分類.
:param fileName: 生成的html文件的文件名.
:param path: 生成的html文件的路徑.
:param title: 圖表的標題
:param subtitle: 圖表的子標題
:param point_size: 每個散點的大小,如果樣本數較少可以考慮設置的大一些
"""
給出的數據集考慮到了模塊給出的echarts繪圖接口都是基於本模塊自帶的經緯度數據集的,而不是pyecharts的數據集。如果想更加精細地控制pyecharts繪圖參數的話可以直接把本倉庫的drawers模塊的源碼複製過去修改。
項目地址:https://github.com/DQinYuan/chinese_province_city_area_mapper.git
喜歡的可以自己下載使用。