简介:这份2004年中国行政区划Shapefile数据集面向历史地理研究、社会经济分析及地图制图人员,提供省、地级市、县三级行政边界的矢量记录,可用于GIS空间分析、历史区划复原与专题图制作。压缩包共21个文件,约6.92MB,以shp、dbf、prj、shx、sbn、sbx及xml为主:shp承载行政边界几何,dbf存储名称、代码、人口、面积等属性,prj定义空间参考系,shx与sbn/sbx为空间索引以提升读取效率,xml记录元数据。已有438人学习下载。需注意该数据为2004年版本,与现行区划存在差异,部分地级市名称已变更,海南省个别地级市当时尚未纳入,使用时宜结合更新数据校正。资源可与ArcGIS、QGIS等软件兼容,便于叠加人口、经济指标开展历史空间分布与变化趋势分析,适合作为历史区划研究的基础底图与教学演示素材。
1. 2004 版行政区划 shp 到底能干什么:先看清它的边界
手里有一份 2004 年的中国行政区划 shp 文件,很多人第一反应是“太老了,还能用吗”。这个问题得拆开看。行政区划数据不是地图底图,它的价值在于“某一时刻的行政边界快照”——省、市、县三级界线、行政代码、名称,全部固化在 2004 年那个时间点上。你要做的是历史对比、教学演示、老数据回溯、或者给一批 2004 年前后的统计年鉴配空间底图,这份数据就是对的;你要做的是当前行政区划查询、最新邮编匹配、实时区县变更追踪,它一定翻车。所以第一件事不是打开 ArcGIS 看效果,而是想清楚你的分析时间锚点在哪一年。这份资源适合做空间分析入门、历史行政区划研究、老统计资料可视化的人,也适合需要一份“干净、结构简单、字段少”的 shp 来练手 GIS 流程的从业者。它不适合拿来做现势性要求高的业务系统底图,这一点先立住,后面所有操作才有意义。
2. 把 shp 读进工作流:字段、坐标系与编码三件事
2.1 先验字段结构,别急着画图
拿到一个 shp 压缩包,我一般不会直接双击打开。先解压,看目录里是不是完整的.shp、.shx、.dbf、.prj四件套。2004 年前后的行政区划数据,常见字段就那么几个:省级名称、地市名称、县级名称、行政区划代码,有的版本还会带一个面积字段。字段名可能是英文缩写,也可能是拼音,甚至直接是中文,这取决于当年制作者的导出习惯。用 Python 的geopandas先读一遍,把字段名、数据类型、记录数打出来,比在软件里点属性表快得多。
import geopandas as gpd # 读取 shp,注意指定编码,2004 年前后的 dbf 常见 GBK gdf = gpd.read_file("china_admin_2004.shp", encoding="gbk") print("记录数:", len(gdf)) print("字段列表:", list(gdf.columns)) print("几何类型:", gdf.geom_type.unique()) print("坐标系:", gdf.crs) print(gdf.head(3))这段代码的重点不在读,而在“验”。记录数能告诉你这份数据是省级、市级还是县级粒度;geom_type如果混着Polygon和MultiPolygon,说明有些行政区被拆成了多部件,后面做面积统计或空间连接时要先统一;crs如果是None,说明.prj缺失或没被识别,那就得手动补坐标系,否则量出来的面积全是错的。字段名如果是乱码,八成是编码问题,gbk不行就换gb18030再试,别硬改字段。
2.2 坐标系这件事,2004 年的数据大概率没有 .prj
这是血泪经验里最常见的一条。早年流出的行政区划 shp,很多只给了几何,没给投影文件。你打开一看图形是正常的,因为经纬度坐标本身就能画出来,但一旦做缓冲区、算面积、做距离分析,单位就变成了“度”,结果毫无意义。判断方法很简单:看坐标数值范围。经度在 73 到 135 之间、纬度在 3 到 54 之间,基本可以确定是 WGS84 地理坐标系。确认之后,第一件事是补上 CRS,再做投影转换。
# 若 crs 为空,先按经纬度补 WGS84 if gdf.crs is None: gdf = gdf.set_crs("EPSG:4326") # 转成适合全国尺度面积统计的等积投影(Albers) gdf_albers = gdf.to_crs("EPSG:3857") # 仅作快速预览 gdf_area = gdf.to_crs("+proj=aea +lat_1=25 +lat_2=47 +lat_0=0 +lon_0=105 +datum=WGS84 +units=m") gdf_area["area_km2"] = gdf_area.geometry.area / 1e6这里EPSG:3857只适合看图形,不适合算面积,因为它在高纬度会严重变形。真正做全国面积统计,常见做法是 Albers 等积投影,中央经线取 105 度,标准纬线取 25 和 47,这套参数在国内区域分析里用得很多。参数不是死的,你做省级以下分析时可以把中央经线调到所在省的中部,变形会更小。补完 CRS 再算面积,和直接拿经纬度算,结果能差出百分之几十,这不是玄学,是投影的锅。
2.3 编码与名称字段的清洗顺序
2004 版数据里,行政区划代码通常是 6 位或 12 位。6 位是县及县以上常用的编码结构,前两位省、中间两位市、后两位县。但老数据经常出现代码位数不齐、名称带空格、名称里混着“市辖区”“省直辖县级行政区划”这类占位名的情况。清洗顺序我一般固定为:先去空格,再统一代码为字符串并补零,最后处理占位名称。
# 代码统一为 6 位字符串,避免前导零丢失 gdf["code"] = gdf["code"].astype(str).str.strip().str.zfill(6) # 名称去空格,占位名单独标记 gdf["name"] = gdf["name"].astype(str).str.strip() placeholder = gdf["name"].str.contains("市辖区|省直辖|自治区直辖", na=False) print("占位名称记录数:", placeholder.sum())补零这一步特别容易翻车。如果代码列被读成整数,110101会变成110101没问题,但010101这种前导零直接消失,后面按代码关联统计年鉴就对不上。统一转字符串再zfill(6)是最稳的。占位名称不要急着删,先标记出来,因为它们在省级汇总时往往需要合并回上级,删了反而丢面积。
3. 从 shp 到可用底图:分级汇总与空间连接
3.1 省、市、县三级怎么拆
一份县级粒度的 shp,本身就能往上汇总出市级和省级。做法不是重新找数据,而是按代码前缀分组做几何融合。6 位代码里前两位是省,前四位是市,用dissolve按前缀合并,比手工选要素靠谱得多。这里要注意,融合会丢掉原始字段,所以融合前先把需要保留的名称字段整理好。
# 省级:按代码前两位融合 gdf["prov_code"] = gdf["code"].str[:2] prov = gdf.dissolve(by="prov_code", aggfunc={"name": "first"}).reset_index() # 市级:按代码前四位融合 gdf["city_code"] = gdf["code"].str[:4] city = gdf.dissolve(by="city_code", aggfunc={"name": "first"}).reset_index() print("省级要素数:", len(prov), "市级要素数:", len(city))dissolve的aggfunc决定融合后保留哪个名称,用first只是取组内第一条,严格说应该按行政级别取上级名称,但 2004 版数据里县级名称字段未必带上级全称,所以更稳的做法是融合后单独维护一张代码到名称的对照表。省级要素数可以用来做一次 sanity check:2004 年前后省级单元数量是固定的,如果融合出来多出几个,多半是代码前缀有异常值,比如代码为空或位数不对,回头查那几条记录就行。
3.2 和统计表格做空间连接时的两个参数
行政区划 shp 最常见的用途,是把一批带行政区代码或名称的统计数据挂到地图上。如果统计表里有标准代码,直接按代码merge,不要用空间连接,因为空间连接在边界调整过的年份容易把点落到隔壁县。只有统计表里只有点位坐标、没有行政代码时,才用sjoin。用sjoin时两个参数必须想清楚:predicate选within还是intersects,how选left还是inner。
# 统计表带代码:直接属性连接 stats = gpd.read_file("stats_2004.csv") # 假设含 code 列 merged = gdf.merge(stats, on="code", how="left") # 只有点位:空间连接,点必须落在面内 points = gpd.read_file("points.shp").to_crs(gdf.crs) joined = gpd.sjoin(points, gdf[["code", "name", "geometry"]], how="left", predicate="within")predicate="within"要求点严格落在面内部,边界上的点会被判为不匹配;intersects则把边界点也算进去。做行政区归属时我一般用within,因为边界点归属本身就有歧义,宁可留空也不要错挂。how="left"保证没匹配上的点也保留,方便你回头查是坐标偏了还是行政区缺失。连接完先看index_right的空值比例,空太多说明坐标系没对齐,这是比字段错误更隐蔽的坑。
3.3 导出前的几何有效性检查
老 shp 的几何问题比新数据多,自相交、重复点、零面积多边形都可能出现。导出成 GeoJSON 或入库之前,跑一遍is_valid,把无效几何单独拎出来修。buffer(0)是常用的修复手段,但它会改变几何形状,只适合做展示底图,不适合做精确面积统计。
invalid = gdf[~gdf.geometry.is_valid] print("无效几何数:", len(invalid)) # 展示用途可尝试 buffer(0) 修复 gdf_fixed = gdf.copy() gdf_fixed["geometry"] = gdf_fixed.geometry.buffer(0) print("修复后无效数:", (~gdf_fixed.geometry.is_valid).sum())修复前后都要记录数量,修复后如果还有无效的,说明问题不是简单自相交,可能是环方向错误或坐标精度问题,这时候别硬修,单独导出那几条人工看。导出格式上,shp 有字段名长度限制,中文名容易截断,做 Web 底图时转 GeoJSON 或 GeoPackage 更省心,字段名提前改成英文短名。
4. 避坑清单:这份 2004 数据最容易翻车的五个地方
4.1 现象:面积算出来比实际大好几倍
原因几乎都是没做投影转换,直接拿经纬度坐标算面积,单位是“平方度”。解决方法是先确认 CRS,再转 Albers 等积投影后计算,参数按分析范围调整,全国尺度用中央经线 105 度那套,省级以下可以换本地中央经线。
4.2 现象:按代码关联统计表,匹配率不到一半
原因通常是代码列被读成整数导致前导零丢失,或者统计表代码是 12 位而 shp 是 6 位。解决方法是两边都统一转字符串、去空格、按较短位数截取后再关联,关联前先各打印前十条对比格式,别等 merge 完才发现对不上。
4.3 现象:地图上某些县缺一块或者多一块
原因是原始数据里存在多部件几何,或者相邻行政区边界不共享、有缝隙重叠。解决方法是先explode拆多部件看分布,再用unary_union检查重叠,展示用途可以接受微小缝隙,做面积汇总时必须先做拓扑修复,否则汇总面积对不上统计口径。
4.4 现象:中文属性在 QGIS 里显示乱码
原因是 dbf 编码和软件默认编码不一致,2004 年前后的数据多为 GBK。解决方法是在读取时显式指定encoding="gbk",QGIS 里在图层属性中改数据源编码,导出时统一转 UTF-8,别在乱码状态下直接改字段值,改完再转码会二次损坏。
4.5 现象:空间连接后大量点匹配不到行政区
原因多半是点位坐标系和 shp 坐标系不一致,或者 shp 本身 CRS 缺失导致to_crs没生效。解决方法是连接前分别打印两者的crs和坐标范围,确认都在同一经纬度区间后再做sjoin,匹配不上的点单独导出看落点,别直接丢。
5. 进阶用法:把 2004 版当成时间切片做对比分析
这份数据真正有意思的用法,不是单独看,而是当成一个时间切片,和另一年份的行政区划数据做对比。做法上,先把两个年份的数据都统一到同一投影、同一代码位数,然后按代码做外连接,用几何差异判断边界是否变化。代码能对上的,比较几何是否完全一致;代码对不上的,说明期间发生了撤并或新增,这部分单独列出来人工核对。对比结果不要只看数量,要看空间分布——哪些区域调整密集,往往和当年的区划调整节奏有关。
# 假设 gdf_2004 与 gdf_other 均已统一 CRS 和 6 位代码 cmp = gdf_2004[["code", "name", "geometry"]].merge( gdf_other[["code", "name", "geometry"]], on="code", how="outer", suffixes=("_04", "_xx"), indicator=True ) print(cmp["_merge"].value_counts()) # 两边都有的,比较几何是否一致 both = cmp[cmp["_merge"] == "both"].copy() both["same_geom"] = both.apply( lambda r: r["geometry_04"].equals(r["geometry_xx"]), axis=1 ) print("几何未变数量:", both["same_geom"].sum())indicator=True会生成_merge列,left_only和right_only就是两个年份之间新增或消失的单元,这部分是区划调整的核心线索。equals比较的是几何是否完全一致,精度差异也会被判为不同,所以实际用的时候可以先做一次坐标精度截断,或者用面积差比例做阈值判断,别被浮点误差带偏。对比结果导出成表,配上变化前后的名称,就是一份能直接看的区划变更清单。
我自己的习惯是,每次拿到年份较早的行政区划数据,先跑一遍 CRS 检查、代码补零、几何有效性这三步,再谈任何分析。这三步不过,后面画出来的图再漂亮也是错的。这份 2004 版 shp 的价值不在“新”,而在“准地定格了一个时间点”,用对场景、把住坐标系和编码两道关,它能撑起不少历史空间分析的需求。希望帮到你。
本文还有配套的精品资源,点击获取