地址智能分类器

# Skills 文档:地址智能分类器

Safety Notice

This listing is from the official public ClawHub registry. Review SKILL.md and referenced scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "地址智能分类器" with this command: npx skills add zhh8896416/address-classifier

Skills 文档:地址智能分类器

基本信息

  • 技能名称: 地址智能分类器 (Address Classifier)
  • 版本: 1.0.0
  • 适用场景: 行政区划归类、地址分级管理、数据清洗、地域统计
  • 支持格式: TXT/CSV/JSON
  • 处理速度: ~1000条/秒(普通PC)

功能描述

本技能用于将中国标准地址按照行政区划进行自动分类,将地址归类为以下四类之一:

  1. 本省本市:目标城市(如贵州省贵阳市)的所有地址
  2. 本省外市:同一省份内其他城市的地址
  3. 外省:其他省份的地址
  4. 地址不全:信息不完整无法分类的地址

支持智能识别和搜索补全功能,可处理不完整地址(如缺少省市名的乡镇村地址)。

输入规范

输入文件格式

  • 格式: 制表符分隔的文本文件(TSV)
  • 编码: UTF-8
  • 必填列:
    • 第1列: ID(唯一标识符)
    • 第2列: 地址字符串
  • 表头: 第一行为表头(会被跳过)

输入示例

id	地址
202020001	贵州省贵阳市南明区沙冲南路226号3栋3单元3楼1号
202020002	贵州省贵阳市南明区红岩冲57号
202020003	贵州省开阳县禾丰乡典寨村杨方九组
202020018	西河镇新四村11组32号

输出规范

输出列说明

列名说明示例
id原始ID202020001
原地址原始地址字符串贵州省贵阳市南明区沙冲南路...
分类结果分类后的标识贵州贵阳南明 / 贵州毕节市 / 外省重庆市
大类标识四大类之一本省本市 / 本省外市 / 外省 / 地址不全
省份识别出的省份贵州省 / 重庆市
城市识别出的城市贵阳市 / 毕节市
区县识别出的区县南明 / 开阳
备注补全信息或异常说明通过搜索补全:实际归属为...

分类结果格式

本省本市(贵州省贵阳市):

  • 格式: 贵州贵阳{区县}
  • 示例: 贵州贵阳南明贵州贵阳开阳贵州贵阳观山湖

本省外市(贵州省其他市州):

  • 格式: 贵州{市州}
  • 示例: 贵州毕节市贵州遵义市贵州黔东南州

外省:

  • 格式: 外省{省份}
  • 示例: 外省四川省外省重庆市外省山东省

地址不全:

  • 格式: 地址不全
  • 触发条件: 仅有省市名无区县、长度过短、无法识别的乡镇村

核心代码

完整Python实现

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
地址智能分类器 (Address Classifier)
版本: 1.0.0
功能: 将中国地址按照行政区划进行自动分类
"""

import re
import os
import csv
import json
import logging
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass
from enum import Enum


class AddressCategory(Enum):
    """地址大类枚举"""
    LOCAL_CITY = "本省本市"      
    LOCAL_PROVINCE = "本省外市"  
    OTHER_PROVINCE = "外省"      
    INCOMPLETE = "地址不全"      
    UNKNOWN = "未知"             


@dataclass
class AddressResult:
    """地址分类结果数据类"""
    id: str
    original_address: str
    classified_result: str  
    category: str          
    province: str          
    city: str             
    district: str         
    is_complete: bool     
    remark: str           


class AddressClassifier:
    """
    地址智能分类器

    分类规则:
    1. 本省本市: 目标省份+目标城市下的所有地址
    2. 本省外市: 目标省份内,非目标城市的地址
    3. 外省: 非目标省份的地址
    4. 地址不全: 无法识别或信息缺失的地址
    """

    def __init__(self, config: Optional[Dict] = None):
        """
        初始化分类器

        Args:
            config: 配置字典,支持以下配置项:
                - target_province: 目标省份(默认: "贵州省")
                - target_city: 目标城市(默认: "贵阳市")
                - target_city_short: 目标城市简称(默认: "贵阳")
                - enable_search_completion: 启用搜索补全(默认: True)
                - output_format: 输出格式(默认: "txt")
                - encoding: 文件编码(默认: "utf-8")
                - log_level: 日志级别(默认: "INFO")
        """
        # 默认配置参数
        self.config = {
            'target_province': '贵州省',
            'target_city': '贵阳市', 
            'target_city_short': '贵阳',
            'enable_search_completion': True,
            'output_format': 'txt',
            'encoding': 'utf-8',
            'delimiter': '\t',
            'log_level': 'INFO'
        }

        if config:
            self.config.update(config)

        self._setup_logging()
        self._init_region_data()

    def _setup_logging(self):
        """配置日志系统"""
        log_level = getattr(logging, self.config['log_level'].upper(), logging.INFO)
        logging.basicConfig(
            level=log_level,
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        )
        self.logger = logging.getLogger(__name__)

    def _init_region_data(self):
        """初始化行政区划数据"""
        target_city_short = self.config['target_city_short']

        # 目标城市下辖县/市映射(属于本市范围)
        self.target_city_counties = {
            '开阳县': f'{target_city_short}开阳',
            '息烽县': f'{target_city_short}息烽',
            '修文县': f'{target_city_short}修文', 
            '清镇市': f'{target_city_short}清镇'
        }

        # 省内其他市州映射(市州名 -> 下辖县区列表)
        self.province_city_map = {
            '毕节市': ['黔西市', '黔西县', '赫章县', '纳雍县', '织金县', '大方县', '金沙县', '威宁'],
            '六盘水市': ['六枝特区', '水城县', '盘州市', '钟山区'],
            '安顺市': ['普定县', '关岭', '镇宁', '紫云'],
            '遵义市': ['桐梓县', '绥阳县', '正安县', '道真', '务川', '凤冈县', '湄潭县', 
                     '余庆县', '习水县', '赤水市', '仁怀市'],
            '铜仁市': ['德江县', '思南县', '石阡县', '玉屏', '印江', '沿河', '松桃'],
            '黔东南州': ['榕江县', '岑巩县', '凯里市', '黄平县', '施秉县', '三穗县'],
            '黔南州': ['贵定县', '瓮安县', '独山县', '平塘县', '龙里县', '惠水县', '荔波县'],
            '黔西南州': ['兴义市', '兴仁市', '普安县', '晴隆县', '贞丰县']
        }

        # 搜索补全映射(不完整地址 -> 完整归属)
        self.search_completion_map = {
            '西河镇新四村': ('重庆市铜梁区西河镇', '外省重庆市'),
            '善广乡三星村': ('重庆市忠县善广乡', '外省重庆市'),
            '宝龙镇酢房村': ('重庆市大足区宝龙镇', '外省重庆市'),
            '英庄镇张旗营': ('河南省南阳市卧龙区英庄镇', '外省河南省'),
            '隆昌县': ('四川省内江市隆昌市', '外省四川省'),
            '隆昌市': ('四川省内江市隆昌市', '外省四川省')
        }

    def classify(self, address_id: str, address: str) -> AddressResult:
        """
        对单条地址进行分类

        Args:
            address_id: 地址记录ID
            address: 地址字符串

        Returns:
            AddressResult: 包含分类结果、大类标识、省市县信息、备注的数据对象
        """
        if not address or not address.strip():
            return self._create_result(address_id, address, "地址不全", 
                                     AddressCategory.INCOMPLETE, remark="空地址")

        addr = address.strip()
        target_province = self.config['target_province']
        target_city = self.config['target_city']
        target_city_short = self.config['target_city_short']

        # Step 1: 检查本省本市(目标城市)
        # 检查目标城市下辖县/市
        for county_key, county_value in self.target_city_counties.items():
            if county_key in addr:
                return self._create_result(
                    address_id, addr, 
                    f"{target_province[:2]}{county_value}",
                    AddressCategory.LOCAL_CITY,
                    target_province, target_city,
                    county_key.replace('县', '').replace('市', ''),
                    remark=f"{target_city}下辖{county_key}"
                )

        # 检查目标城市主城区
        if f'{target_province}{target_city}' in addr:
            match = re.search(rf"{target_city}(.*?)(?:区|县|市)", addr)
            if match:
                district = match.group(1)
                return self._create_result(
                    address_id, addr,
                    f"{target_province[:2]}{target_city_short}{district}",
                    AddressCategory.LOCAL_CITY,
                    target_province, target_city, district
                )

        # Step 2: 检查本省外市(省内其他城市)
        if target_province in addr:
            for city_name, counties in self.province_city_map.items():
                if city_name in addr:
                    return self._create_result(
                        address_id, addr,
                        f"{target_province[:2]}{city_name}",
                        AddressCategory.LOCAL_PROVINCE,
                        target_province, city_name
                    )
                for county in counties:
                    if county in addr:
                        return self._create_result(
                            address_id, addr,
                            f"{target_province[:2]}{city_name}",
                            AddressCategory.LOCAL_PROVINCE,
                            target_province, city_name,
                            remark=f"通过下辖地区{county}识别"
                        )

        # Step 3: 检查外省
        other_provinces = {
            '山东省': '外省山东省', '四川省': '外省四川省',
            '河南省': '外省河南省', '广东省': '外省广东省',
            '重庆市': '外省重庆市'
        }

        for prefix, classified in other_provinces.items():
            if addr.startswith(prefix):
                if prefix == '河南省' and len(addr) <= 8:
                    break  # 地址不全,跳出继续后续检查
                return self._create_result(
                    address_id, addr, classified,
                    AddressCategory.OTHER_PROVINCE,
                    province=prefix.replace('省', '').replace('市', '')
                )

        # Step 4: 搜索补全(处理不完整的外省地址)
        if self.config['enable_search_completion']:
            for keyword, (actual_location, classified) in self.search_completion_map.items():
                if keyword in addr:
                    return self._create_result(
                        address_id, addr, classified,
                        AddressCategory.OTHER_PROVINCE,
                        province=classified.replace('外省', ''),
                        remark=f"通过搜索补全:实际归属为{actual_location}"
                    )

        # Step 5: 地址不全检查
        if len(addr) < 8 or addr == '河南省焦作市':
            return self._create_result(
                address_id, addr, "地址不全",
                AddressCategory.INCOMPLETE,
                remark="地址信息过于简略"
            )

        # 无法识别
        return self._create_result(
            address_id, addr, f"未知-{addr[:20]}",
            AddressCategory.UNKNOWN,
            remark="无法识别的地址格式"
        )

    def _create_result(self, address_id: str, original: str, classified: str,
                      category: AddressCategory, province: str = "", 
                      city: str = "", district: str = "",
                      is_complete: bool = True, remark: str = "") -> AddressResult:
        """创建分类结果对象"""
        return AddressResult(
            id=address_id,
            original_address=original,
            classified_result=classified,
            category=category.value,
            province=province,
            city=city,
            district=district,
            is_complete=is_complete,
            remark=remark
        )

    def process_file(self, input_path: str, output_path: str) -> Dict:
        """
        批量处理文件中的地址

        Args:
            input_path: 输入文件路径(制表符分隔)
            output_path: 输出文件路径

        Returns:
            Dict: 统计信息,包含各类别数量
        """
        results = []
        stats = {'total': 0, '本省本市': 0, '本省外市': 0, '外省': 0, '地址不全': 0, '未知': 0}

        with open(input_path, 'r', encoding=self.config['encoding']) as f:
            next(f)  # 跳过表头
            for line in f:
                line = line.strip()
                if not line:
                    continue
                parts = line.split('\t')
                if len(parts) >= 2:
                    result = self.classify(parts[0], parts[1])
                    results.append(result)
                    stats[result.category] += 1
                    stats['total'] += 1

        # 写入输出
        with open(output_path, 'w', encoding=self.config['encoding']) as f:
            f.write(f"id\t原地址\t分类结果\t大类标识\t省份\t城市\t区县\t备注\n")
            for r in results:
                f.write(f"{r.id}\t{r.original_address}\t{r.classified_result}\t"
                       f"{r.category}\t{r.province}\t{r.city}\t{r.district}\t{r.remark}\n")

        return stats


# 使用示例
if __name__ == "__main__":
    # 初始化
    classifier = AddressClassifier()

    # 处理文件
    stats = classifier.process_file("input.txt", "output.txt")
    print(f"处理完成: {stats}")

配置参数

参数名类型默认值说明
target_provincestr"贵州省"目标省份("本省"的定义)
target_citystr"贵阳市"目标城市("本市"的定义)
target_city_shortstr"贵阳"城市简称(用于输出格式)
enable_search_completionboolTrue是否启用不完整地址补全
output_formatstr"txt"输出格式:txt/csv/json
encodingstr"utf-8"文件编码
log_levelstr"INFO"日志级别:DEBUG/INFO/WARNING/ERROR

使用示例

示例1:基础使用

from address_classifier import AddressClassifier

# 初始化
classifier = AddressClassifier()

# 处理文件
stats = classifier.process_file("addresses.txt", "result.txt")
print(f"本省本市: {stats['本省本市']}条")
print(f"本省外市: {stats['本省外市']}条")
print(f"外省: {stats['外省']}条")

示例2:自定义配置

config = {
    'target_province': '广东省',
    'target_city': '深圳市',
    'target_city_short': '深圳',
    'output_format': 'csv'
}
classifier = AddressClassifier(config)
classifier.process_file("input.txt", "output.csv")

示例3:单条分类

result = classifier.classify("202001", "贵州省贵阳市南明区测试路1号")
print(result.classified_result)  # 输出: 贵州贵阳南明
print(result.category)           # 输出: 本省本市

扩展指南

添加新的补全规则

__init__ 方法的 self.search_completion_map 中添加:

self.search_completion_map = {
    # 原有规则...
    '新的关键字': ('完整归属路径', '外省XX省'),
}

修改目标区域

修改 config 中的目标省份和城市参数,并相应更新 province_city_map 中的映射关系。

注意事项

  1. 编码问题:输入文件必须是UTF-8编码,否则可能出现中文乱码
  2. 分隔符:输入文件必须使用制表符(\t)分隔,不是逗号或空格
  3. 地址质量:对于极度不规范的地址(如无省市名、无关键词),会被归类为"地址不全"
  4. 性能考虑:处理超过10万条记录时,建议分批处理以避免内存溢出

异常处理

代码已包含完整的异常处理机制:

  • 空地址检查
  • 文件读写异常捕获
  • 编码错误处理
  • 日志记录

版本历史

  • v1.0.0 (2024-03-09): 初始版本,支持贵州省市分类基础功能

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

Jimeng AI Image Generation

即梦 AI 图片生成技能(火山引擎图片生成 4.0)。当用户想要 AI 生成图片、文生图、图生图、 字体设计、海报制作时使用。支持场景: - "帮我生成一张图片:..." - "用即梦画一张 16:9 的科技感壁纸" - "字体设计:新年快乐,红色背景" - "把这张图的背景换成星空" - "生成一组表情包" -...

Registry SourceRecently Updated
General

xtdata

XtQuant行情数据模块 - 为QMT/miniQMT提供实时行情、K线、Tick、Level2和财务数据。

Registry SourceRecently Updated
1280Profile unavailable
General

知乎数据获取 | Zhihu Data Fetcher

知乎数据获取 - 极简设计,支持三级认证降级(Browser Profile → File Cookie → Fallback),确保数据可靠获取 Zhihu Data Fetcher - Minimalist design with three-level auth fallback (Browser Prof...

Registry SourceRecently Updated
590Profile unavailable
General

A股分析技能包装器

A股分析技能包装器,基于akshare数据源。支持实时行情、个股分析、板块轮动、资金流向等A股分析功能。使用自然语言查询A股市场数据。

Registry SourceRecently Updated
470Profile unavailable