☰
全国228189个矿产地CSV数据清洗与PostGIS空间入库实战
2026/9/26 6:08:53 网站建设 项目流程

1. 全国矿产地数据集的整体设计与数据价值拆解

1.1 这份数据到底装了什么

第一次拿到“全国33个省228189个矿产地位置分布数据”这个标题的时候,我脑子里第一反应是:这个体量的数据,如果字段设计合理,基本可以支撑起一个省级到全国尺度的矿产资源空间分析项目。228189条记录,覆盖33个省级行政区,核心字段是经纬度坐标,格式是CSV。这几个关键词组合在一起,说明它不是一个简单的统计表格,而是一个带有空间属性的点位数据集。

从数据结构的角度来推,这类矿产地数据集通常包含以下几类字段:矿区名称、所属省份、行政区划代码、矿种类型(煤、铁、铜、金、铅锌等)、矿床规模(大型、中型、小型)、经纬度坐标(经度Lon、纬度Lat)、海拔高程(部分数据集会有)、数据来源或备注。228189这个数字意味着它大概率是全国矿产资源潜力评价、矿业权实地核查或者地质调查项目积累下来的汇总成果。33个省而不是34个,说明统计口径上可能没有包含港澳台,或者某些省级单位的数据被合并处理了。

CSV格式的选择非常务实。相比Shapefile或者GeoJSON,CSV在跨平台交换上几乎没有障碍——Excel能打开,Python的pandas能读,PostgreSQL能导入,甚至连一些低代码平台都能直接解析。经纬度坐标以十进制小数形式存储,通常是WGS84或者CGCS2000坐标系,这为后续的空间分析和可视化提供了最基础的条件。

1.2 谁需要这份数据,用来做什么

我接触过不少用这类数据的人,大致可以分成几类。第一类是做地质科研的高校师生,他们需要基于矿产地分布做成矿规律分析、空间聚类、核密度估计;第二类是做国土空间规划或矿业权管理的技术人员,需要把矿产地落到地图上,和生态红线、基本农田、城镇开发边界做叠加分析;第三类是做数据可视化的开发者,想拿这份数据做一个全国矿产资源分布的地图应用;第四类是做投资研究或行业分析的人,想从矿种分布和规模结构里看出区域资源禀赋的差异。

不同的人对这份数据的使用方式完全不同。科研人员关心的是坐标精度和矿种分类的准确性,规划人员关心的是行政区划字段是否完整、能否和现有GIS图层做关联,开发者关心的是CSV的编码格式、字段分隔符、有没有表头、经纬度的顺序是“经度在前”还是“纬度在前”。这些细节看起来琐碎,但实际用起来,任何一个不对都会导致整个流程卡住。

1.3 为什么是CSV而不是其他格式

这里我想多说一句格式选型的问题。很多人拿到CSV会觉得“太原始了”,想要Shapefile或者GeoJSON。但实际工作中,CSV反而是最稳妥的中间格式。原因有三:一是CSV的通用性最强,任何数据处理工具都能读写;二是CSV便于版本管理和差异对比,Git能直接diff;三是CSV在导入数据库时最灵活,你可以自己控制字段类型、索引和约束。

当然,CSV也有它的短板。它不存储坐标系信息,不存储几何类型,不存储字段的数据类型。这意味着你拿到一份CSV坐标数据,必须自己确认坐标系是什么,经纬度字段的顺序是什么,有没有缺失值,有没有重复记录。这些确认工作不做,后面所有的分析都是空中楼阁。

提示:拿到任何CSV坐标数据,第一步永远是抽样检查。用文本编辑器打开前50行,确认分隔符是逗号还是制表符,确认表头字段名,确认经纬度的数值范围是否合理(国内经度大约在73到135之间,纬度大约在3到53之间)。

2. 数据获取后的核心细节解析与实操要点

2.1 字段识别与坐标系确认

假设你已经拿到了这份CSV文件,第一步不是急着导入,而是先做字段识别。用Python的pandas读前几行看看结构:

import pandas as pd df = pd.read_csv('mineral_sites.csv', nrows=5, encoding='utf-8') print(df.columns.tolist()) print(df.head()) print(df.dtypes)

如果编码报错,换成gbk或者gb18030再试。国内很多地质调查项目导出的CSV默认是GBK编码,直接用UTF-8读会乱码。这个问题我踩过不止一次,尤其是从老系统导出的数据。

字段识别完之后,最关键的是确认坐标系。国内常见的坐标系统有几种:WGS84(GPS原始坐标)、CGCS2000(国家大地坐标系)、北京54、西安80。如果数据来源是近十年的地质调查项目,大概率是CGCS2000或者WGS84,两者在国内尺度下差异很小,普通可视化可以忽略。但如果要做高精度叠加分析,就必须确认清楚。

怎么判断坐标系?一个实用的方法是找几个已知矿产地,比如鞍山铁矿、白云鄂博稀土矿,把CSV里的坐标和已知的真实坐标做对比。如果偏差在几十米以内,基本就是WGS84或CGCS2000;如果偏差几百米,可能是北京54或西安80。

2.2 经纬度顺序与数值范围校验

经纬度顺序是另一个高频坑。国内很多数据集习惯用“纬度,经度”的顺序,而国际惯例是“经度,纬度”。如果你不确认就导入GIS,会发现所有点都跑到非洲或者南极去了。

校验方法很简单:

# 假设字段名是 lat 和 lon print(df['lon'].describe()) print(df['lat'].describe())

如果lon的范围在73到135之间,lat在3到53之间,说明顺序正确。如果反过来,lon的范围在3到53,lat在73到135,那就需要交换字段。

数值范围校验还能发现异常值。比如经度出现0或者负数,纬度出现90以上,这些大概率是缺失值填充或者录入错误。我一般会把这些记录单独导出,人工核查后再决定是否保留。

2.3 缺失值与重复记录处理

228189条记录里,难免有缺失和重复。缺失值可能出现在矿种类型、规模、坐标等字段。坐标缺失的记录基本没法用于空间分析,建议直接剔除或者单独存放。矿种和规模缺失的记录可以保留,但在做分类统计时要标记为“未知”。

重复记录的判断标准要看业务需求。如果两条记录的矿区名称、坐标、矿种完全一致,基本可以判定为重复。但如果只是名称相同、坐标略有差异,可能是同一矿区的不同矿段,不能简单去重。

# 基于名称和坐标的重复检测 dup_mask = df.duplicated(subset=['矿区名称', '经度', '纬度'], keep=False) dups = df[dup_mask] print(f"疑似重复记录数: {len(dups)}")

处理重复记录时,我通常的做法是保留第一条,把重复的导出到一个单独文件,人工确认后再决定是否合并或删除。

2.4 数据加密与访问控制的实际考量

热搜词里出现了“写完怎么加密”,说明有人关心数据的安全性问题。对于这类矿产地数据,如果涉及敏感信息,确实需要做访问控制。但加密本身不是目的,目的是控制谁能看、谁能改、谁能导出。

实际工作中,我一般建议分层处理:原始CSV文件放在受控的服务器目录,通过数据库导入后,用视图和权限控制不同角色的访问范围。如果确实需要对CSV文件本身加密,可以用7-Zip打包加密或者GPG加密,但要注意密钥管理,否则时间一长自己都打不开。

注意:加密后的CSV文件无法被pandas直接读取,需要先解密到临时目录。如果是在自动化流程中使用,建议把解密步骤做成独立的脚本,密钥通过环境变量传入,不要硬编码在代码里。

3. 从CSV到空间数据库的完整实操流程

3.1 用pandas做数据清洗与预处理

在导入数据库之前,我习惯先用pandas做一轮清洗。这一步的目标是把数据整理成“干净、一致、可直接入库”的状态。

import pandas as pd import numpy as np # 读取数据 df = pd.read_csv('mineral_sites.csv', encoding='gb18030') # 重命名列(根据实际字段名调整) df = df.rename(columns={ '矿区名称': 'mine_name', '省份': 'province', '矿种': 'mineral_type', '规模': 'scale', '经度': 'longitude', '纬度': 'latitude' }) # 坐标数值转换 df['longitude'] = pd.to_numeric(df['longitude'], errors='coerce') df['latitude'] = pd.to_numeric(df['latitude'], errors='coerce') # 剔除坐标缺失的记录 df = df.dropna(subset=['longitude', 'latitude']) # 范围过滤(国内合理范围) df = df[(df['longitude'] >= 73) & (df['longitude'] <= 136)] df = df[(df['latitude'] >= 3) & (df['latitude'] <= 54)] # 去除首尾空格 df['mine_name'] = df['mine_name'].str.strip() df['province'] = df['province'].str.strip() # 导出清洗后的数据 df.to_csv('mineral_sites_clean.csv', index=False, encoding='utf-8') print(f"清洗后记录数: {len(df)}")

这段代码看起来简单,但每一步都有讲究。errors='coerce'能把无法转换的值变成NaN,避免程序崩溃。范围过滤能剔除明显错误的坐标。去空格能避免后续关联时的匹配失败。

3.2 PostgreSQL建表与导入

PostgreSQL是我最推荐的空间数据存储方案,配合PostGIS扩展,能直接做空间查询和分析。建表的时候,字段类型要设计好:

CREATE TABLE mineral_sites ( id SERIAL PRIMARY KEY, mine_name VARCHAR(200), province VARCHAR(50), mineral_type VARCHAR(100), scale VARCHAR(20), longitude NUMERIC(10, 6), latitude NUMERIC(10, 6), geom GEOMETRY(Point, 4326) ); CREATE INDEX idx_mineral_sites_geom ON mineral_sites USING GIST(geom); CREATE INDEX idx_mineral_sites_province ON mineral_sites(province); CREATE INDEX idx_mineral_sites_type ON mineral_sites(mineral_type);

导入的时候,先用\copy命令把CSV灌进去:

psql -U postgres -d mineral_db -c "\copy mineral_sites(mine_name, province, mineral_type, scale, longitude, latitude) FROM 'mineral_sites_clean.csv' WITH CSV HEADER ENCODING 'UTF8'"

然后更新geom字段:

UPDATE mineral_sites SET geom = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326) WHERE longitude IS NOT NULL AND latitude IS NOT NULL;

这里有个细节:ST_MakePoint的参数顺序是“经度, 纬度”,不是“纬度, 经度”。我见过不少人在这里搞反,结果所有点都跑到海里去了。

3.3 空间索引与查询性能优化

228189条记录不算大,但如果没有空间索引,做范围查询或者最近邻查询时会明显变慢。GIST索引建好之后,下面这类查询基本是毫秒级:

-- 查询某个矩形范围内的矿产地 SELECT mine_name, province, mineral_type FROM mineral_sites WHERE geom && ST_MakeEnvelope(116.0, 39.0, 117.0, 40.0, 4326); -- 查询距离某点50公里内的矿产地 SELECT mine_name, province, ST_Distance(geom::geography, ST_MakePoint(116.4, 39.9)::geography) / 1000 AS distance_km FROM mineral_sites WHERE ST_DWithin(geom::geography, ST_MakePoint(116.4, 39.9)::geography, 50000) ORDER BY distance_km;

ST_DWithin配合geography类型,能直接按米计算距离,不用自己换算坐标系。这个技巧在做“某城市周边矿产资源”分析时特别实用。

3.4 按省份和矿种的聚合统计

数据入库之后,最常见的分析就是按省份和矿种做聚合。比如统计各省的矿产地数量和主要矿种:

-- 各省矿产地数量排名 SELECT province, COUNT(*) AS site_count FROM mineral_sites GROUP BY province ORDER BY site_count DESC; -- 各省主要矿种(取数量最多的前三种) SELECT province, mineral_type, COUNT(*) AS type_count FROM mineral_sites GROUP BY province, mineral_type ORDER BY province, type_count DESC;

如果要在Python里做更灵活的分析,可以直接用pandas的groupby:

province_stats = df.groupby('province').agg( site_count=('mine_name', 'count'), mineral_types=('mineral_type', 'nunique') ).sort_values('site_count', ascending=False) print(province_stats.head(10))

这种统计能快速看出哪些省份矿产地密集,哪些省份矿种丰富。比如内蒙古、新疆、云南这些地方,矿产地数量和矿种多样性通常都排在前列。

4. 常见问题与排查技巧实录

4.1 CSV打开乱码怎么办

这是最高频的问题。国内地质调查项目导出的CSV,编码可能是GBK、GB18030、UTF-8 with BOM等多种。Excel打开乱码,不代表文件坏了,只是编码没对上。

排查步骤:先用file命令看文件编码(Linux/Mac),或者用Notepad++打开看右下角显示的编码。如果是GBK,用Excel的“数据-从文本导入”功能,手动选择GBK编码。如果是UTF-8 with BOM,用Python读取时加encoding='utf-8-sig'。

# 尝试多种编码 encodings = ['utf-8', 'gbk', 'gb18030', 'utf-8-sig'] for enc in encodings: try: df = pd.read_csv('mineral_sites.csv', encoding=enc, nrows=5) print(f"成功编码: {enc}") break except UnicodeDecodeError: continue

4.2 坐标点偏移到国外怎么排查

如果导入GIS后发现点全部偏移到国外,大概率是经纬度顺序反了,或者坐标系搞错了。排查顺序:先看数值范围,确认经度在73-136、纬度在3-54之间;再看字段名,确认哪个是经度哪个是纬度;最后看坐标系定义,确认GIS项目里的坐标系和数据的坐标系一致。

还有一种情况是坐标本身是投影坐标(比如高斯克吕格),不是经纬度。这种数据的特点是数值很大,经度可能是6位数,纬度可能是7位数。遇到这种情况,需要先做投影反算,转成经纬度再用。

4.3 导入数据库时字段类型不匹配

PostgreSQL导入CSV时,如果字段类型定义和实际数据不匹配,会报错。常见的有:经纬度字段定义成INTEGER,但实际有小数;省份字段定义成VARCHAR(10),但实际有“内蒙古自治区”这种长名称;矿种字段有特殊字符导致解析失败。

解决办法:建表时经纬度用NUMERIC(10,6),名称类字段用VARCHAR(200)留足余量,导入前先用pandas做一轮类型转换和截断。

4.4 大数据量CSV的读取性能优化

228189条记录用pandas读取,如果字段多、内存小,可能会比较慢。优化方法有几个:只读需要的列(usecols参数);指定字段类型(dtype参数)避免自动推断;分块读取(chunksize参数)处理超大文件。

# 只读需要的列,指定类型 df = pd.read_csv( 'mineral_sites.csv', usecols=['矿区名称', '省份', '矿种', '经度', '纬度'], dtype={'省份': 'category', '矿种': 'category'}, encoding='gb18030' )

把省份和矿种设成category类型,能大幅减少内存占用,做groupby时也更快。

4.5 常见问题速查表

问题现象可能原因排查方法解决方案
Excel打开乱码编码不匹配用Notepad++看编码用GBK或utf-8-sig读取
点偏移到国外经纬度顺序反了检查数值范围交换经纬度字段
点偏移几百米坐标系不一致对比已知点坐标做坐标系转换
导入报类型错误字段类型不匹配看报错字段调整建表语句
读取速度慢字段多、类型未指定看内存占用用usecols和dtype
重复记录多数据合并未去重按名称和坐标查重去重或人工确认

提示:处理这类数据,我最大的体会是“先验证,再批量”。拿10条记录做全流程测试,确认坐标对了、字段对了、导入对了,再处理全量数据。这样能避免跑完半小时才发现坐标顺序反了。

5. 数据可视化与进阶分析思路

5.1 用Python做快速可视化

清洗完的数据,用matplotlib或者folium能快速出图。matplotlib适合做静态的散点图,folium适合做交互式地图。

import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(12, 8)) ax.scatter(df['longitude'], df['latitude'], s=1, alpha=0.3, c='steelblue') ax.set_xlabel('Longitude') ax.set_ylabel('Latitude') ax.set_title('National Mineral Sites Distribution') plt.tight_layout() plt.savefig('mineral_sites_map.png', dpi=150)

这段代码能生成一张全国矿产地分布散点图。点的密度能直观反映矿产资源的空间聚集特征。如果按矿种分类着色,还能看出不同矿种的区域分布差异。

5.2 核密度分析与热点识别

如果想进一步识别矿产资源的热点区域,可以用核密度估计(KDE)。Python的scipy或者sklearn都有现成的实现:

from sklearn.neighbors import KernelDensity import numpy as np # 准备坐标数组 coords = df[['longitude', 'latitude']].values # 核密度估计 kde = KernelDensity(bandwidth=0.5, metric='haversine') kde.fit(np.radians(coords)) # 在网格上评估密度 lon_grid = np.linspace(73, 136, 200) lat_grid = np.linspace(3, 54, 150) lon_mesh, lat_mesh = np.meshgrid(lon_grid, lat_grid) grid_coords = np.radians(np.vstack([lon_mesh.ravel(), lat_mesh.ravel()]).T) density = np.exp(kde.score_samples(grid_coords)).reshape(lon_mesh.shape)

bandwidth参数控制平滑程度,值越大越平滑。metric='haversine'确保在经纬度上计算的是球面距离,而不是平面距离。这个分析能帮你找出矿产地最密集的区域,对成矿规律研究很有价值。

5.3 按省份和矿种的交叉分析

除了空间分布,按省份和矿种的交叉分析也能挖出不少信息。比如:

# 透视表:省份 x 矿种 pivot = pd.pivot_table( df, values='mine_name', index='province', columns='mineral_type', aggfunc='count', fill_value=0 ) # 找出每个省份数量最多的矿种 top_mineral = pivot.idxmax(axis=1) print(top_mineral)

这个分析能快速回答“哪个省以什么矿为主”这类问题。比如山西以煤为主,辽宁以铁为主,云南以有色金属为主,这些结论从数据里直接就能看出来。

5.4 导出为其他格式的注意事项

有时候需要把数据导出成Shapefile或者GeoJSON给GIS同事用。导出时要注意坐标系和字段名长度。Shapefile的字段名不能超过10个字符,中文字段名容易出问题,建议导出前先改成英文。

import geopandas as gpd from shapely.geometry import Point # 转成GeoDataFrame geometry = [Point(xy) for xy in zip(df['longitude'], df['latitude'])] gdf = gpd.GeoDataFrame(df, geometry=geometry, crs='EPSG:4326') # 导出GeoJSON gdf.to_file('mineral_sites.geojson', driver='GeoJSON') # 导出Shapefile(注意字段名长度) gdf_export = gdf.rename(columns={ 'mine_name': 'name', 'province': 'prov', 'mineral_type': 'mtype', 'scale': 'scale' }) gdf_export.to_file('mineral_sites.shp', encoding='utf-8')

导出Shapefile时,encoding='utf-8'能避免中文乱码,但有些老版本ArcGIS对UTF-8支持不好,可能需要用GBK。

6. 个人实操经验与后续扩展方向

这份数据我前前后后处理过几次,最大的感受是:数据质量比数据量重要得多。228189条记录听起来很多,但如果坐标缺失、矿种分类混乱、省份字段不统一,实际能用的可能只有一半。所以在清洗阶段多花时间,后面分析阶段就能少踩坑。

另一个体会是,CSV虽然简单,但“简单”不等于“随便”。字段命名、编码格式、坐标顺序、缺失值表示方式,这些细节如果一开始不统一,后面每换一个工具就要重新处理一遍。我的做法是,拿到原始CSV后,先做一轮标准化,输出一个“干净版”CSV,后续所有分析都基于这个干净版,不再直接碰原始文件。

后续如果想扩展,有几个方向可以考虑。一是把矿产地数据和地质构造图、成矿带图做叠加,分析成矿规律;二是把数据按时间维度展开,看不同时期的勘探重点变化;三是把数据接入Web地图,做一个可交互的全国矿产资源分布查询系统。这些方向都需要在现有数据基础上补充其他数据源,但核心的坐标和分类字段已经具备,扩展起来不会太吃力。

最后分享一个小技巧:处理这类数据时,我习惯在CSV旁边放一个README.md,记录数据来源、坐标系、字段说明、清洗步骤和已知问题。过几个月再回头看,这个README能省下大量回忆时间。数据本身会说话,但前提是你得记得它说的是什么。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询