cpca-linch 0.4.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cpca_linch-0.4.4/LICENSE +20 -0
- cpca_linch-0.4.4/MANIFEST.in +3 -0
- cpca_linch-0.4.4/PKG-INFO +76 -0
- cpca_linch-0.4.4/README.rst +43 -0
- cpca_linch-0.4.4/cpca/__init__.py +321 -0
- cpca_linch-0.4.4/cpca/drawer.py +118 -0
- cpca_linch-0.4.4/cpca/exceptions.py +22 -0
- cpca_linch-0.4.4/cpca/resources/__init__.py +6 -0
- cpca_linch-0.4.4/cpca/resources/pca.csv +3649 -0
- cpca_linch-0.4.4/cpca/structures.py +61 -0
- cpca_linch-0.4.4/cpca_linch.egg-info/PKG-INFO +76 -0
- cpca_linch-0.4.4/cpca_linch.egg-info/SOURCES.txt +19 -0
- cpca_linch-0.4.4/cpca_linch.egg-info/dependency_links.txt +1 -0
- cpca_linch-0.4.4/cpca_linch.egg-info/requires.txt +2 -0
- cpca_linch-0.4.4/cpca_linch.egg-info/top_level.txt +1 -0
- cpca_linch-0.4.4/setup.cfg +4 -0
- cpca_linch-0.4.4/setup.py +72 -0
- cpca_linch-0.4.4/tests/test_cpca.py +301 -0
- cpca_linch-0.4.4/tests/test_drawer.py +23 -0
- cpca_linch-0.4.4/tests/test_resources.py +13 -0
- cpca_linch-0.4.4/tests/test_structures.py +71 -0
cpca_linch-0.4.4/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 QinYuan Du
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cpca-linch
|
|
3
|
+
Version: 0.4.4
|
|
4
|
+
Summary: Chinese Province, City and Area Recognition Utilities (Updated 2025)
|
|
5
|
+
Home-page: https://github.com/laofahai/cpca-linch
|
|
6
|
+
Author: laofahai
|
|
7
|
+
Author-email:
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: Simplified Chinese,Chinese geographic information,Chinese province city area recognition
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Natural Language :: Chinese (Simplified)
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Text Processing
|
|
20
|
+
Classifier: Topic :: Text Processing :: Indexing
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: pandas
|
|
23
|
+
Requires-Dist: jieba
|
|
24
|
+
Dynamic: author
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: home-page
|
|
28
|
+
Dynamic: keywords
|
|
29
|
+
Dynamic: license
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
Dynamic: requires-dist
|
|
32
|
+
Dynamic: summary
|
|
33
|
+
|
|
34
|
+
cpca-linch
|
|
35
|
+
==========
|
|
36
|
+
|
|
37
|
+
A Python module for extracting Chinese province, city, and district information from address strings.
|
|
38
|
+
|
|
39
|
+
Fork from `DQinYuan/chinese_province_city_area_mapper <https://github.com/DQinYuan/chinese_province_city_area_mapper>`_ with updated 2025 administrative division data.
|
|
40
|
+
|
|
41
|
+
Installation
|
|
42
|
+
------------
|
|
43
|
+
|
|
44
|
+
.. code-block:: bash
|
|
45
|
+
|
|
46
|
+
pip install cpca-linch
|
|
47
|
+
|
|
48
|
+
Usage
|
|
49
|
+
-----
|
|
50
|
+
|
|
51
|
+
.. code-block:: python
|
|
52
|
+
|
|
53
|
+
import cpca
|
|
54
|
+
|
|
55
|
+
df = cpca.transform(["徐汇区虹漕路461号58号楼5楼", "广东省中山市沙溪镇云汉轻纺城"])
|
|
56
|
+
print(df)
|
|
57
|
+
|
|
58
|
+
Output::
|
|
59
|
+
|
|
60
|
+
省 市 区 地址
|
|
61
|
+
0 上海市 上海市 徐汇区 虹漕路461号58号楼5楼
|
|
62
|
+
1 广东省 中山市 沙溪镇 云汉轻纺城
|
|
63
|
+
|
|
64
|
+
Key Improvements
|
|
65
|
+
----------------
|
|
66
|
+
|
|
67
|
+
1. Updated administrative division data to 2025 (from `xiangyuecn/AreaCity-JsSpider-StatsGov <https://github.com/xiangyuecn/AreaCity-JsSpider-StatsGov>`_)
|
|
68
|
+
2. Support for towns in prefecture-level cities without districts (Dongguan, Zhongshan, Danzhou, Jiayuguan)
|
|
69
|
+
3. Removed latitude/longitude data for smaller package size
|
|
70
|
+
|
|
71
|
+
Full documentation: `https://github.com/laofahai/cpca-linch <https://github.com/laofahai/cpca-linch>`_
|
|
72
|
+
|
|
73
|
+
License
|
|
74
|
+
-------
|
|
75
|
+
|
|
76
|
+
MIT
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
cpca-linch
|
|
2
|
+
==========
|
|
3
|
+
|
|
4
|
+
A Python module for extracting Chinese province, city, and district information from address strings.
|
|
5
|
+
|
|
6
|
+
Fork from `DQinYuan/chinese_province_city_area_mapper <https://github.com/DQinYuan/chinese_province_city_area_mapper>`_ with updated 2025 administrative division data.
|
|
7
|
+
|
|
8
|
+
Installation
|
|
9
|
+
------------
|
|
10
|
+
|
|
11
|
+
.. code-block:: bash
|
|
12
|
+
|
|
13
|
+
pip install cpca-linch
|
|
14
|
+
|
|
15
|
+
Usage
|
|
16
|
+
-----
|
|
17
|
+
|
|
18
|
+
.. code-block:: python
|
|
19
|
+
|
|
20
|
+
import cpca
|
|
21
|
+
|
|
22
|
+
df = cpca.transform(["徐汇区虹漕路461号58号楼5楼", "广东省中山市沙溪镇云汉轻纺城"])
|
|
23
|
+
print(df)
|
|
24
|
+
|
|
25
|
+
Output::
|
|
26
|
+
|
|
27
|
+
省 市 区 地址
|
|
28
|
+
0 上海市 上海市 徐汇区 虹漕路461号58号楼5楼
|
|
29
|
+
1 广东省 中山市 沙溪镇 云汉轻纺城
|
|
30
|
+
|
|
31
|
+
Key Improvements
|
|
32
|
+
----------------
|
|
33
|
+
|
|
34
|
+
1. Updated administrative division data to 2025 (from `xiangyuecn/AreaCity-JsSpider-StatsGov <https://github.com/xiangyuecn/AreaCity-JsSpider-StatsGov>`_)
|
|
35
|
+
2. Support for towns in prefecture-level cities without districts (Dongguan, Zhongshan, Danzhou, Jiayuguan)
|
|
36
|
+
3. Removed latitude/longitude data for smaller package size
|
|
37
|
+
|
|
38
|
+
Full documentation: `https://github.com/laofahai/cpca-linch <https://github.com/laofahai/cpca-linch>`_
|
|
39
|
+
|
|
40
|
+
License
|
|
41
|
+
-------
|
|
42
|
+
|
|
43
|
+
MIT
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# __init__.py
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
from .structures import AddrMap, Pca
|
|
6
|
+
from .structures import P,C,A
|
|
7
|
+
|
|
8
|
+
VERSION = (0, 4, 4)
|
|
9
|
+
|
|
10
|
+
__version__ = ".".join([str(x) for x in VERSION])
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _data_from_csv() -> (AddrMap, AddrMap, AddrMap, dict, dict):
|
|
14
|
+
# 区名及其简写 -> 相关pca元组
|
|
15
|
+
area_map = AddrMap()
|
|
16
|
+
# 城市名及其简写 -> 相关pca元组
|
|
17
|
+
city_map = AddrMap()
|
|
18
|
+
# (省名全称, 区名全称) -> 相关pca元组
|
|
19
|
+
province_area_map = AddrMap()
|
|
20
|
+
# 省名 -> 省全名
|
|
21
|
+
province_map = {}
|
|
22
|
+
# (省名, 市名, 区名) -> (纬度,经度)
|
|
23
|
+
latlng = {}
|
|
24
|
+
# 数据约定:国家直辖市的sheng字段为直辖市名称, 省直辖县的city字段为空
|
|
25
|
+
from pkg_resources import resource_stream
|
|
26
|
+
|
|
27
|
+
with resource_stream('cpca.resources', 'pca.csv') as pca_stream:
|
|
28
|
+
from io import TextIOWrapper
|
|
29
|
+
import csv
|
|
30
|
+
text = TextIOWrapper(pca_stream, encoding='utf8')
|
|
31
|
+
pca_csv = csv.DictReader(text)
|
|
32
|
+
for record_dict in pca_csv:
|
|
33
|
+
# 经纬度为可选字段
|
|
34
|
+
lat = record_dict.get('lat', '')
|
|
35
|
+
lng = record_dict.get('lng', '')
|
|
36
|
+
if lat and lng:
|
|
37
|
+
latlng[(record_dict['sheng'], record_dict['shi'], record_dict['qu'])] = (lat, lng)
|
|
38
|
+
|
|
39
|
+
_fill_province_map(province_map, record_dict)
|
|
40
|
+
_fill_area_map(area_map, record_dict)
|
|
41
|
+
_fill_city_map(city_map, record_dict)
|
|
42
|
+
_fill_province_area_map(province_area_map, record_dict)
|
|
43
|
+
|
|
44
|
+
return area_map, city_map, province_area_map, province_map, latlng
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _fill_province_area_map(province_area_map: AddrMap, record_dict):
|
|
48
|
+
pca_tuple = (record_dict['sheng'], record_dict['shi'], record_dict['qu'])
|
|
49
|
+
key = (record_dict['sheng'], record_dict['qu'])
|
|
50
|
+
# 第三个参数在此处没有意义, 随便给的
|
|
51
|
+
province_area_map.append_relational_addr(key, pca_tuple, P)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _fill_area_map(area_map: AddrMap, record_dict):
|
|
55
|
+
area_name = record_dict['qu']
|
|
56
|
+
pca_tuple = (record_dict['sheng'], record_dict['shi'], record_dict['qu'])
|
|
57
|
+
area_map.append_relational_addr(area_name, pca_tuple, A)
|
|
58
|
+
# 处理区名简写
|
|
59
|
+
if area_name.endswith('市'):
|
|
60
|
+
area_map.append_relational_addr(area_name[:-1], pca_tuple, A)
|
|
61
|
+
elif area_name.endswith('区'):
|
|
62
|
+
area_map.append_relational_addr(area_name[:-1], pca_tuple, A)
|
|
63
|
+
elif area_name.endswith('县'):
|
|
64
|
+
area_map.append_relational_addr(area_name[:-1], pca_tuple, A)
|
|
65
|
+
elif area_name.endswith('镇'):
|
|
66
|
+
area_map.append_relational_addr(area_name[:-1], pca_tuple, A)
|
|
67
|
+
elif area_name.endswith('街道'):
|
|
68
|
+
area_map.append_relational_addr(area_name[:-2], pca_tuple, A)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _fill_city_map(city_map: AddrMap, record_dict):
|
|
72
|
+
city_name = record_dict['shi']
|
|
73
|
+
pca_tuple = (record_dict['sheng'], record_dict['shi'], record_dict['qu'])
|
|
74
|
+
city_map.append_relational_addr(city_name, pca_tuple, C)
|
|
75
|
+
if city_name.endswith('市'):
|
|
76
|
+
city_map.append_relational_addr(city_name[:-1], pca_tuple, C)
|
|
77
|
+
# 特别行政区
|
|
78
|
+
elif city_name == '香港特别行政区':
|
|
79
|
+
city_map.append_relational_addr('香港', pca_tuple, C)
|
|
80
|
+
elif city_name == '澳门特别行政区':
|
|
81
|
+
city_map.append_relational_addr('澳门', pca_tuple, C)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _fill_province_map(province_map, record_dict):
|
|
85
|
+
sheng = record_dict['sheng']
|
|
86
|
+
if sheng not in province_map:
|
|
87
|
+
province_map[sheng] = sheng
|
|
88
|
+
# 处理省的简写情况
|
|
89
|
+
# 普通省分 和 直辖市
|
|
90
|
+
if sheng.endswith('省') or sheng.endswith('市'):
|
|
91
|
+
province_map[sheng[:-1]] = sheng
|
|
92
|
+
# 自治区
|
|
93
|
+
elif sheng == '新疆维吾尔自治区':
|
|
94
|
+
province_map['新疆'] = sheng
|
|
95
|
+
elif sheng == '内蒙古自治区':
|
|
96
|
+
province_map['内蒙古'] = sheng
|
|
97
|
+
elif sheng == '广西壮族自治区':
|
|
98
|
+
province_map['广西'] = sheng
|
|
99
|
+
province_map['广西省'] = sheng
|
|
100
|
+
elif sheng == '西藏自治区':
|
|
101
|
+
province_map['西藏'] = sheng
|
|
102
|
+
elif sheng == '宁夏回族自治区':
|
|
103
|
+
province_map['宁夏'] = sheng
|
|
104
|
+
# 特别行政区
|
|
105
|
+
elif sheng == '香港特别行政区':
|
|
106
|
+
province_map['香港'] = sheng
|
|
107
|
+
elif sheng == '澳门特别行政区':
|
|
108
|
+
province_map['澳门'] = sheng
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
area_map, city_map, province_area_map, province_map, latlng = _data_from_csv()
|
|
112
|
+
|
|
113
|
+
# 直辖市
|
|
114
|
+
munis = {'北京市', '天津市', '上海市', '重庆市'}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def is_munis(city_full_name):
|
|
118
|
+
return city_full_name in munis
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
myumap = {
|
|
122
|
+
'南关区': '长春市',
|
|
123
|
+
'南山区': '深圳市',
|
|
124
|
+
'宝山区': '上海市',
|
|
125
|
+
'市辖区': '东莞市',
|
|
126
|
+
'普陀区': '上海市',
|
|
127
|
+
'朝阳区': '北京市',
|
|
128
|
+
'河东区': '天津市',
|
|
129
|
+
'白云区': '广州市',
|
|
130
|
+
'西湖区': '杭州市',
|
|
131
|
+
'铁西区': '沈阳市'
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def transform(location_strs, umap=myumap, index=[], cut=True, lookahead=8, pos_sensitive=False, open_warning=True):
|
|
136
|
+
"""将地址描述字符串转换以"省","市","区"信息为列的DataFrame表格
|
|
137
|
+
Args:
|
|
138
|
+
locations:地址描述字符集合,可以是list, Series等任意可以进行for in循环的集合
|
|
139
|
+
比如:["徐汇区虹漕路461号58号楼5楼", "泉州市洛江区万安塘西工业区"]
|
|
140
|
+
umap:自定义的区级到市级的映射,主要用于解决区重名问题,如果定义的映射在模块中已经存在,则会覆盖模块中自带的映射
|
|
141
|
+
index:可以通过这个参数指定输出的DataFrame的index,默认情况下是range(len(data))
|
|
142
|
+
cut:是否使用分词,默认使用,分词模式速度较快,但是准确率可能会有所下降
|
|
143
|
+
lookahead:只有在cut为false的时候有效,表示最多允许向前看的字符的数量
|
|
144
|
+
默认值为8是为了能够发现"新疆维吾尔族自治区"这样的长地名
|
|
145
|
+
如果你的样本中都是短地名的话,可以考虑把这个数字调小一点以提高性能
|
|
146
|
+
pos_sensitive:如果为True则会多返回三列,分别提取出的省市区在字符串中的位置,如果字符串中不存在的话则显示-1
|
|
147
|
+
open_warning: 是否打开umap警告, 默认打开
|
|
148
|
+
Returns:
|
|
149
|
+
一个Pandas的DataFrame类型的表格,如下:
|
|
150
|
+
|省 |市 |区 |地址 |
|
|
151
|
+
|上海市|上海市|徐汇区|虹漕路461号58号楼5楼 |
|
|
152
|
+
|福建省|泉州市|洛江区|万安塘西工业区 |
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
from collections.abc import Iterable
|
|
156
|
+
|
|
157
|
+
if not isinstance(location_strs, Iterable):
|
|
158
|
+
from .exceptions import InputTypeNotSuportException
|
|
159
|
+
raise InputTypeNotSuportException(
|
|
160
|
+
'location_strs参数必须为可迭代的类型(比如list, Series等实现了__iter__方法的对象)')
|
|
161
|
+
|
|
162
|
+
import pandas as pd
|
|
163
|
+
|
|
164
|
+
result = pd.DataFrame([_handle_one_record(addr, umap, cut, lookahead, pos_sensitive, open_warning) for addr in location_strs], index=index) \
|
|
165
|
+
if index else pd.DataFrame([_handle_one_record(addr, umap, cut, lookahead, pos_sensitive, open_warning) for addr in location_strs])
|
|
166
|
+
# 这句的唯一作用是让列的顺序好看一些
|
|
167
|
+
if pos_sensitive:
|
|
168
|
+
return result.loc[:, ('省', '市', '区', '地址', '省_pos', '市_pos', '区_pos')]
|
|
169
|
+
else:
|
|
170
|
+
return result.loc[:, ('省', '市', '区', '地址')]
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _handle_one_record(addr, umap, cut, lookahead, pos_sensitive, open_warning):
|
|
174
|
+
"""处理一条记录"""
|
|
175
|
+
|
|
176
|
+
# 空记录
|
|
177
|
+
if not isinstance(addr, str) or addr == '' or addr is None:
|
|
178
|
+
empty = {'省': '', '市': '', '区': ''}
|
|
179
|
+
if pos_sensitive:
|
|
180
|
+
empty['省_pos'] = -1
|
|
181
|
+
empty['市_pos'] = -1
|
|
182
|
+
empty['区_pos'] = -1
|
|
183
|
+
return empty
|
|
184
|
+
|
|
185
|
+
# 地名提取
|
|
186
|
+
pca, addr = _extract_addr(addr, cut, lookahead)
|
|
187
|
+
|
|
188
|
+
_fill_city(pca, umap, open_warning)
|
|
189
|
+
|
|
190
|
+
_fill_province(pca)
|
|
191
|
+
|
|
192
|
+
result = pca.propertys_dict(pos_sensitive)
|
|
193
|
+
result["地址"] = addr
|
|
194
|
+
|
|
195
|
+
return result
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _fill_province(pca):
|
|
199
|
+
"""填充省"""
|
|
200
|
+
if (not pca.province) and pca.city and (pca.city in city_map):
|
|
201
|
+
pca.province = city_map.get_value(pca.city, P)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _fill_city(pca, umap, open_warning):
|
|
205
|
+
"""填充市"""
|
|
206
|
+
if not pca.city:
|
|
207
|
+
# 从 区 映射
|
|
208
|
+
if pca.area:
|
|
209
|
+
# 从umap中映射
|
|
210
|
+
if umap.get(pca.area):
|
|
211
|
+
pca.city = umap.get(pca.area)
|
|
212
|
+
return
|
|
213
|
+
if pca.area in area_map and area_map.is_unique_value(pca.area):
|
|
214
|
+
pca.city = area_map.get_value(pca.area, C)
|
|
215
|
+
return
|
|
216
|
+
|
|
217
|
+
# 从 省,区 映射
|
|
218
|
+
if pca.area and pca.province:
|
|
219
|
+
newKey = (pca.province, pca.area)
|
|
220
|
+
if newKey in province_area_map and province_area_map.is_unique_value(newKey):
|
|
221
|
+
pca.city = province_area_map.get_value(newKey, C)
|
|
222
|
+
return
|
|
223
|
+
|
|
224
|
+
if open_warning:
|
|
225
|
+
import logging
|
|
226
|
+
logging.warning("%s 无法映射, 建议添加进umap中", pca.area)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _extract_addr(addr, cut, lookahead):
|
|
230
|
+
"""提取地址中的省,市,区名称
|
|
231
|
+
Args:
|
|
232
|
+
addr:原始地址字符串
|
|
233
|
+
cut: 是否分词
|
|
234
|
+
Returns:
|
|
235
|
+
[sheng, shi, qu, (sheng_pos, shi_pos, qu_pos)], addr
|
|
236
|
+
"""
|
|
237
|
+
return _jieba_extract(addr) if cut else _full_text_extract(addr, lookahead)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def _jieba_extract(addr):
|
|
241
|
+
"""基于结巴分词进行提取"""
|
|
242
|
+
import jieba
|
|
243
|
+
|
|
244
|
+
result = Pca()
|
|
245
|
+
|
|
246
|
+
pos = 0
|
|
247
|
+
truncate = 0
|
|
248
|
+
|
|
249
|
+
def _set_pca(pca_property, name, full_name):
|
|
250
|
+
"""pca_property: 'province', 'city' or 'area'"""
|
|
251
|
+
if not getattr(result, pca_property):
|
|
252
|
+
setattr(result, pca_property, full_name)
|
|
253
|
+
setattr(result, pca_property + "_pos", pos)
|
|
254
|
+
if is_munis(full_name):
|
|
255
|
+
setattr(result, "province_pos", pos)
|
|
256
|
+
nonlocal truncate
|
|
257
|
+
if pos == truncate:
|
|
258
|
+
truncate += len(name)
|
|
259
|
+
|
|
260
|
+
for word in jieba.cut(addr):
|
|
261
|
+
# 优先提取低级别行政区 (主要是为直辖市和特别行政区考虑)
|
|
262
|
+
if word in area_map:
|
|
263
|
+
_set_pca('area', word, area_map.get_full_name(word))
|
|
264
|
+
elif word in city_map:
|
|
265
|
+
_set_pca('city', word, city_map.get_full_name(word))
|
|
266
|
+
elif word in province_map:
|
|
267
|
+
_set_pca('province', word, province_map[word])
|
|
268
|
+
|
|
269
|
+
pos += len(word)
|
|
270
|
+
|
|
271
|
+
return result, addr[truncate:]
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def _full_text_extract(addr, lookahead):
|
|
275
|
+
"""全文匹配进行提取"""
|
|
276
|
+
|
|
277
|
+
result = Pca()
|
|
278
|
+
|
|
279
|
+
truncate = 0
|
|
280
|
+
|
|
281
|
+
def _set_pca(pca_property, pos, name, full_name):
|
|
282
|
+
"""pca_property: 'province', 'city' or 'area'"""
|
|
283
|
+
def _defer_set():
|
|
284
|
+
if not getattr(result, pca_property):
|
|
285
|
+
setattr(result, pca_property, full_name)
|
|
286
|
+
setattr(result, pca_property + "_pos", pos)
|
|
287
|
+
if is_munis(full_name):
|
|
288
|
+
setattr(result, "province_pos", pos)
|
|
289
|
+
nonlocal truncate
|
|
290
|
+
if pos == truncate:
|
|
291
|
+
truncate += len(name)
|
|
292
|
+
return len(name)
|
|
293
|
+
return _defer_set
|
|
294
|
+
|
|
295
|
+
# i为起始位置
|
|
296
|
+
i = 0
|
|
297
|
+
while i < len(addr):
|
|
298
|
+
# 用于设置pca属性的函数
|
|
299
|
+
defer_fun = None
|
|
300
|
+
# l为从起始位置开始的长度,从中提取出最长的地址
|
|
301
|
+
for length in range(1, lookahead + 1):
|
|
302
|
+
if i + length > len(addr):
|
|
303
|
+
break
|
|
304
|
+
word = addr[i:i + length]
|
|
305
|
+
# 优先提取低级别的行政区 (主要是为直辖市和特别行政区考虑)
|
|
306
|
+
if word in area_map:
|
|
307
|
+
defer_fun = _set_pca('area', i, word, area_map.get_full_name(word))
|
|
308
|
+
continue
|
|
309
|
+
elif word in city_map:
|
|
310
|
+
defer_fun = _set_pca('city', i, word, city_map.get_full_name(word))
|
|
311
|
+
continue
|
|
312
|
+
elif word in province_map:
|
|
313
|
+
defer_fun = _set_pca('province', i, word, province_map[word])
|
|
314
|
+
continue
|
|
315
|
+
|
|
316
|
+
if defer_fun:
|
|
317
|
+
i += defer_fun()
|
|
318
|
+
else:
|
|
319
|
+
i += 1
|
|
320
|
+
|
|
321
|
+
return result, addr[truncate:]
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from . import latlng
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def _base_input_check(locations):
|
|
6
|
+
import pandas as pd
|
|
7
|
+
from .exceptions import InputTypeNotSuportException
|
|
8
|
+
if not isinstance(locations, pd.DataFrame):
|
|
9
|
+
raise InputTypeNotSuportException(InputTypeNotSuportException.input_type)
|
|
10
|
+
if "省" not in locations.columns or "市" not in locations.columns \
|
|
11
|
+
or "区" not in locations.columns:
|
|
12
|
+
raise InputTypeNotSuportException(InputTypeNotSuportException.input_type)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
_lnglat = dict([(item[0], tuple(reversed(item[1]))) for item in latlng.items()])
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _geo_update(geo):
|
|
19
|
+
geo._coordinates = _lnglat
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def draw_locations(locations, file_path):
|
|
23
|
+
"""
|
|
24
|
+
基于folium生成地域分布的热力图的html文件.
|
|
25
|
+
:param locations: 样本的省市区, pandas的dataframe类型.
|
|
26
|
+
:param file_path: 生成的html文件的路径.
|
|
27
|
+
"""
|
|
28
|
+
_base_input_check(locations)
|
|
29
|
+
import folium
|
|
30
|
+
from folium.plugins import HeatMap
|
|
31
|
+
# 注意判断key是否存在
|
|
32
|
+
heatData = []
|
|
33
|
+
for map_key in zip(locations["省"], locations["市"], locations["区"]):
|
|
34
|
+
if latlng.get(map_key):
|
|
35
|
+
lat_lon = latlng.get(map_key)
|
|
36
|
+
heatData.append([float(lat_lon[0]), float(lat_lon[1]), 1])
|
|
37
|
+
# 绘制Map,开始缩放程度是5倍
|
|
38
|
+
map_osm = folium.Map(location=[35, 110], zoom_start=5)
|
|
39
|
+
# 将热力图添加到前面建立的map里
|
|
40
|
+
HeatMap(heatData).add_to(map_osm)
|
|
41
|
+
# 保存为html文件
|
|
42
|
+
map_osm.save(file_path)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def echarts_draw(locations, file_path, title="地域分布图"
|
|
46
|
+
, subtitle="location distribute"):
|
|
47
|
+
"""
|
|
48
|
+
生成地域分布的echarts热力图的html文件.
|
|
49
|
+
:param locations: 样本的省市区, pandas的dataframe类型.
|
|
50
|
+
:param file_path: 生成的html文件路径.
|
|
51
|
+
:param title: 图表的标题
|
|
52
|
+
:param subtitle: 图表的子标题
|
|
53
|
+
"""
|
|
54
|
+
from pyecharts import Geo
|
|
55
|
+
|
|
56
|
+
_base_input_check(locations)
|
|
57
|
+
count_map = {}
|
|
58
|
+
for map_key in zip(locations["省"], locations["市"], locations["区"]):
|
|
59
|
+
if latlng.get(map_key):
|
|
60
|
+
count_map[map_key] = count_map.get(map_key, 0) + 1
|
|
61
|
+
|
|
62
|
+
geo = Geo(title, subtitle, title_color="#fff",
|
|
63
|
+
title_pos="center", width=1200,
|
|
64
|
+
height=600, background_color='#404a59')
|
|
65
|
+
_geo_update(geo)
|
|
66
|
+
attr, value = geo.cast(count_map)
|
|
67
|
+
geo.add("", attr, value, type="heatmap", is_visualmap=True,
|
|
68
|
+
visual_text_color='#fff',
|
|
69
|
+
is_piecewise=True, visual_split_number=10)
|
|
70
|
+
geo.render(file_path)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def echarts_cate_draw(locations, labels, file_path, title="地域分布图", subtitle="location distribute",
|
|
74
|
+
point_size=7):
|
|
75
|
+
"""
|
|
76
|
+
依据分类生成地域分布的echarts散点图的html文件.
|
|
77
|
+
:param locations: 样本的省市区, pandas的dataframe类型.
|
|
78
|
+
:param labels: 长度必须和locations相等, 代表每个样本所属的分类.
|
|
79
|
+
:param file_path: 生成的html文件路径.
|
|
80
|
+
:param title: 图表的标题
|
|
81
|
+
:param subtitle: 图表的子标题
|
|
82
|
+
:param point_size: 每个散点的大小
|
|
83
|
+
"""
|
|
84
|
+
_base_input_check(locations)
|
|
85
|
+
|
|
86
|
+
if len(locations) != len(labels):
|
|
87
|
+
from .exceptions import CPCAException
|
|
88
|
+
raise CPCAException("locations的长度与labels长度必须相等")
|
|
89
|
+
|
|
90
|
+
from pyecharts import Geo
|
|
91
|
+
|
|
92
|
+
geo = Geo(title, subtitle, title_color="#000000",
|
|
93
|
+
title_pos="center", width=1200,
|
|
94
|
+
height=600, background_color='#fff')
|
|
95
|
+
_geo_update(geo)
|
|
96
|
+
|
|
97
|
+
uniques = set(list(labels))
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _data_add(_geo, _cate_keys, _category):
|
|
101
|
+
real_keys = []
|
|
102
|
+
for cate_key in _cate_keys:
|
|
103
|
+
if latlng.get(cate_key):
|
|
104
|
+
real_keys.append(cate_key)
|
|
105
|
+
|
|
106
|
+
attr = real_keys
|
|
107
|
+
value = [1] * len(real_keys)
|
|
108
|
+
geo.add(_category, attr, value, symbol_size=point_size,
|
|
109
|
+
legend_pos="left", legend_top="bottom",
|
|
110
|
+
geo_normal_color="#fff",
|
|
111
|
+
geo_emphasis_color =" #f0f0f5")
|
|
112
|
+
|
|
113
|
+
for category in uniques:
|
|
114
|
+
cate_locations = locations[labels == category]
|
|
115
|
+
_data_add(geo, zip(cate_locations["省"], cate_locations["市"],
|
|
116
|
+
cate_locations["区"]), category)
|
|
117
|
+
|
|
118
|
+
geo.render(file_path)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Wed Feb 28 18:55:58 2018
|
|
4
|
+
自定义的一些异常类
|
|
5
|
+
@author: 燃烧杯
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
class CPCAException(Exception):
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
class PlaceTypeNotExistException(CPCAException):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
class InputTypeNotSuportException(CPCAException):
|
|
15
|
+
input_type = \
|
|
16
|
+
"""
|
|
17
|
+
输入应该为
|
|
18
|
+
|省 |市 |区 |
|
|
19
|
+
|江苏省 |扬州市 |邗江区 |
|
|
20
|
+
格式的pandas.core.frame.DateFrame
|
|
21
|
+
"""
|
|
22
|
+
pass
|