
搞地震数据分析的人都知道拿到一份干净、完整、时间对得上的地震目录比拿到十个模型都管用。最近我一直在用CnOpenData平台上的中国历史地震表而且是“当前时间1年内”的滚动版本做区域地震活动性分析和可视化总体体验很顺中间也踩了几个坑。这篇文章就把这份数据从字段结构、获取思路、清洗处理到常见问题完整拆一遍希望能给做同类工作的朋友省点时间。先说结论这份数据本质上是一份经过整理的近一年中国地震目录覆盖了大陆及周边区域的主要地震事件包含发震时刻、震级、经纬度、深度、震中参考位置等核心字段。适合做短期活动性统计、震级频次分析、空间分布可视化也适合作为应急演练、科普内容、毕业论文数据底表。无论你是做GIS、搞科研还是单纯想分析一下“最近哪里震得多”这份表都能直接上手。1. 先弄明白这份数据是什么1.1 CnOpenData 与地震目录的定位CnOpenData是国内一个面向学术研究的数据平台定位是把各种零散的公开数据整理成结构化、可直接分析的数据集。中国历史地震表就是其中一类它把原本分散在各级地震台网的地震事件信息汇聚成一张张表免去了你从多个站点爬取、合并、对齐的麻烦。说句实在话自己做地震目录最大的痛苦不是数据量而是数据源太碎。国家台网有正式目录省级台网有快报目录科研机构又有自己的震源机制目录同一个地震在不同来源里震级可能差0.3以上。CnOpenData这类平台的价值就在于做了汇聚和清洗至少我拿到的版本字段是一致的时间范围是明确的事件类型也列清楚了。它不是原始观测数据而是整理后的“目录型数据”对于大多数分析需求来说这个粒度完全够用。1.2 为什么“当前时间1年内”这个窗口很实用很多人习惯一上来就下载全量历史数据动辄几十万条分析还没开始就被数据清洗耗掉大半天。我个人的建议是如果你只关心近期地震活动趋势那就用1年窗口的数据。“当前时间1年内”这个设定本质上是一个按日滚动的数据切片。这个窗口有几点好处。第一体量小处理快不需要分布式工具一台笔记本用pandas就能跑完所有分析。第二数据新鲜度高能反映最近一年的真实活动水平不会因为时间跨度过大而把近期异常淹没在长周期背景里。第三数据结构简单特别适合用来做教学案例、快速原型和可视化演示。当然它也有局限比如只看一年很难讨论十年尺度的活动周期也没法做b值这种需要大量样本的统计推断。所以我的使用习惯是快速分析用1年版正式研究再从平台拉全量历史数据。两者互相补充不冲突。1.3 适合谁、能做什么我粗粗列了一下这份数据的典型用户可以分成几类地球物理、地理信息相关专业的学生用做课程设计、毕业论文的数据来源省去自己爬数据的环节。做灾害风险评估、应急管理的从业者需要快速掌握近一年区域地震发生情况用于简报、报告和数据底图。GIS和可视化开发者利用经纬度和震级字段做交互地图、热力图、时间轴动画。科普内容创作者想做一个“今年哪些地方地震了”的图或者视频这份数据是最直接的素材库。我自己做过的两个实际场景一是生成“近一年华北地区震级频次分布”图表二是在地图上把震中位置按深度着色展示整个流程从数据下载到出图不到半小时。这个效率手工爬数据的时候根本不敢想。2. 数据结构和字段逐个拆解2.1 典型的字段清单不同批次的数据字段名可能略有出入但核心结构基本一致。我拿到的版本大致包含这些字段字段名类型示例说明发震时刻datetime2025-08-15 03:26:55发震时间通常精确到秒注意时区问题纬度float34.53震中纬度北纬为正单位度经度float112.78震中经度东经为正单位度震级float4.9地震大小数值注意与震级标度搭配使用震级标度stringML、Ms、Mw震级的量测方式直接影响数值对比深度float10.0震源深度单位千米震中位置string河南洛阳市新安县参考地名常用于快速定位事件类型string天然地震/非天然地震/塌陷区分天然与非天然事件很重要参考地点string河南洛阳市新安县具体行政位置描述便于地理落位数据版本stringV1.0数据批次版本更新日期date2025-06-01目录生成时间判断数据的新鲜度2.2 字段不是单纯列里面藏了很多前提逐个字段讲一下实际使用时的注意点。发震时刻是第一个容易出问题的地方。很多目录原始存储用UTC时间展示出来是北京时间。平台整理过的数据通常会统一成北京时间但你不能想当然最好拿到数据后先随机抽几行和中国地震台网发布的正式结果对一下差8小时就是UTC没转换。纬度和经度看似简单实际上也存在精度假象。有的目录经纬度显示到小数点后两位看着精确到公里级但可能来自自动定位震中偏差几公里是常事。如果你做的是乡镇级别的空间叠加别对单个点的经纬度过度信任。震级是争议最集中的字段。震级本身不是物理量纲的直接测量而是基于振幅、周期、持续时间等观测的推算值所以会存在不同标度。ML地方震级适合近震和中小地震范围通常在几公里到几百公里内。Ms面波震级常用来描述中强地震中国地震台网正式目录里用得很普遍。Mw矩震级是基于地震矩的物理标度大震级时最稳定不会饱和。不同标度的数值不能直接混在一起取平均或者直接比较。比如同一个地震Mw 5.0和Ms 5.2可能描述的是同一事件但你直接代入统计模型就会产生偏差。处理办法是分析前先按标度分组或把少数Mw事件单独标注。深度字段也很有意思。浅源地震0到20公里最常见中源20到70公里和深源70到300公里以上则需要特别关注因为它们的成因机制不太一样。还有一类特殊情况目录里深度为0并不一定代表地面破裂可能是定位算法给了一个默认浅源值也可能是爆破事件被记录成0深度。分析的时候最好结合参考地点和事件类型来综合判断。2.3 版本差异与字段命名不统一说了这么多字段核心提醒是下载之前先读样表先读样表先读样表。重要的话说三遍。CnOpenData不同批次的数据字段名可能从英文改成中文或者从“time”变成“发震时刻”甚至有些版本会额外带一个“事件ID”字段方便去重。我的习惯是拿到数据后先执行几个简单命令打印所有列名逐个确认含义查看每列dtype时间字段确保是datetime类型而不是object用describe()看经纬度和震级的值域范围排除明显异常值。这一步看起来琐碎但它决定了后面所有分析是否可靠。我曾经见过有人没确认字段就批量处理结果把“事件类型”当成“震级标度”用统计出来的图完全没法解释最后只能重新来一遍。3. 从下载到可视化完整实操流程3.1 数据下载与格式确认平台的交互方式通常是在网页上勾选数据表选择时间范围这里选近1年然后提交下载。下载下来一般是CSV或者Excel格式。如果压缩包里有数据说明文档务必读一下尤其是字段定义、时间时区、事件类型分类这些内容。拿到文件后我建议第一时间用Python打开一个数据切片确认内容长什么样。下面是我常用的初始探查代码import pandas as pd # 如果文件是CSV df pd.read_csv(earthquake_1y.csv, encodingutf-8) # 打印基本信息 print(df.shape) print(df.columns.tolist()) print(df.head(10).to_string()) print(df.dtypes)这一步能看到列名、前几行内容和字段类型。如果发现时间列读出来是字符串后面就需要显式转换。3.2 清洗与预处理让目录真正可用目录数据看起来规整但直接用来分析还是会出问题。我的标准流程分四步第一步时间统一。把发震时刻列统一转成datetime64并强制使用北京时间。如果发现原数据是UTC就做8小时转换。这一步决定了后面按天、按月聚合是否准确。df[time] pd.to_datetime(df[time]) # 如果确认是UTC需要加8小时 if df[time].dt.tz is None: df[time] df[time].dt.tz_localize(UTC).dt.tz_convert(Asia/Shanghai)第二步筛选近一年。虽然标题已经限定是1年数据但从平台下载时可能是某个固定时间点在真正分析之前仍建议用当前时间重新过滤一次保证数据边界清楚。from datetime import datetime, timedelta ref_time datetime(2025, 6, 1) start_time ref_time - timedelta(days365) df_1y df[df[time] start_time]第三步经纬度合理性检查。地学数据最基本的逻辑是经纬度落在预期范围内。大陆地区经度大致在73°E到135°E之间纬度在18°N到54°N之间。超出这个范围的点要单独看可能是境外事件也可能是定位异常。mask ( (df[lat].between(18, 54)) (df[lon].between(73, 135)) ) df_valid df[mask]第四步深度与震级处理。深度缺失或为0的先看数量占比震级列如果有空值直接删除这些行最省事因为没有震级的事件无法参与统计分析。df_clean df_valid.dropna(subset[mag, lat, lon]) df_clean df_clean[df_clean[depth].fillna(0) 0]做完这四步数据基本处于可用状态。要注意整个过程不要脱离业务背景盲目清洗比如深度等于0不一定是错误要结合事件类型判断。3.3 统计与可视化从目录里看出趋势清洗完成后下一步是用图表把数据“讲出来”。我最常用的三个图分别是震级频次直方图、时间序列累积图、空间分布地图。这三个图能回答“震级怎么分布”、“活动怎么变化”、“震中在哪里”三个核心问题。震级频次直方图直接反映震级分布。import matplotlib.pyplot as plt plt.figure(figsize(10, 6)) plt.hist(df_clean[mag], bins30, edgecolorblack, alpha0.7) plt.xlabel(Magnitude) plt.ylabel(Count) plt.title(Magnitude Distribution in Recent 1 Year) plt.grid(axisy, linestyle--, alpha0.5) plt.show()时间序列累积图非常直观如果斜率在某一段突然变陡说明这段时间地震明显增多值得深挖。import matplotlib.dates as mdates df_1y df_clean.sort_values(time) df_1y[cum_count] range(1, len(df_1y) 1) plt.figure(figsize(12, 6)) plt.plot(df_1y[time], df_1y[cum_count], linewidth1.5) plt.xlabel(Time) plt.ylabel(Cumulative Earthquake Count) plt.title(Cumulative Earthquake Count Over Past Year) plt.grid(alpha0.4) plt.show()空间分布地图我用交互式地图库绘制把每个地震画成圆圈圆的大小代表震级颜色代表深度一下子就能看出活动带分布。import plotly.express as px fig px.scatter_mapbox( df_clean, latlat, lonlon, sizemag, colordepth, hover_nameplace, zoom3, center{lat: 36, lon: 104}, mapbox_styleopen-street-map, color_continuous_scaleYlOrRd, ) fig.show()需要说明的是mapbox_styleopen-street-map在有些环境下需要网络连通如果加载不出来可以退回到普通的scatter图用经纬度作为坐标轴也能看出空间聚集特征。3.4 延伸结合其他数据源交叉验证使用这份数据时我一般不会只看单一目录来源。尤其是震级较大的事件比如M≥5.5建议用中国地震台网速报目录或USGS目录做一个交叉验证。原因很简单不同目录的震级测量方式、定位算法、数据处理流程不同单靠一个目录做结论容易踩到系统偏差。交叉验证时最需要注意的是震级标度对齐。USGS通常给出Mw平台目录可能给的是Ms两者差异0.2到0.4都属于正常范围。如果你写的报告需要精确震级建议直接在结果里注明标度来源和目录名称这是学术严谨性的基本要求。4. 常见问题与排坑实录4.1 高频问题速查表实际使用中我从自己和身边朋友的经历里整理了一份高频问题表格按出现概率排了序问题现象可能原因解决方法时间和官方结果差8小时时区未转换目录存储的是UTC统一加8小时得到北京时间震级统计偏大或偏小不同震级标度混用先按震级标度字段分组再分别统计深度大量为0定位算法默认浅源或记录缺失结合事件类型判断非天然地震可能较多同一条地震出现两次不同来源目录合并时未去重按“时间经纬度震级”联合去重经纬度点落在境外数据范围不仅限国内按业务需要做经纬度范围过滤地震事件中出现爆破、塌陷记录目录混入非天然地震使用事件类型字段过滤数据更新滞后于实际发震目录整理需要时间理解平台更新机制重要事件用速报目录对齐4.2 两次实际踩坑的完整排查过程第一个坑是时间偏移。我做过一次震级随时间分布分析发现某一天的峰值和官方通报完全对应不上差8小时。排查过程很简单先看原始数据里时间字段的时区信息发现是UTC未转换再做加8小时处理重画图后马上和官方结果对齐了。这个坑的教训是拿到数据后第一件事先抽查一条人工核实时间不要盲目信任“平台已经处理好了”。第二个坑是震级标度混用。有次做震级频次统计画出来的直方图在震级4.5到5.0之间出现了一个奇怪的凹陷怎么解释都不通。后来我按震级标度字段拆分发现这个区间分别有ML、Ms两种标度的样本它们本身就不在一个度量体系里直接合在一起统计自然会出现人为缺口。排查方法就是拆开看df.groupby(mag_type)[mag].describe()一眼就能发现分布差异。统计分析前花两分钟做一个分组描述统计能省掉后面大量返工时间。4.3 实用心得一二三条最后分享几条实操心得都是在一次次返工里攒出来的第一下载数据后立刻记录获取日期。像“近1年”这种滚动窗口它随下载时间变化不同日期的数据子集不同。我把文件名改成earthquake_1y_20250601.csv后面做分析、写说明的时候一眼就能看出这份数据的时间锚点。第二做任何结论前都把“目录完整性”挂嘴上。小震级事件通常比大震级事件更容易被漏录因为台网密度在空间上不均匀。近一年数据里某区域地震数少不代表真实发生少可能只是台网稀疏。这个道理在写研究报告时尤其重要否则容易被审稿人或者同行抓住。第三把数据切片和全量数据分开存放。近1年数据适合快速探索全量数据适合严肃统计。每次做探索性和验证性分析用不同数据集避免混淆。我本地目录通常分explore/和research/两个文件夹前者放滚动窗口样本后者放固定版本的全量快照。另外补充一个小技巧用df.groupby(pd.Grouper(keytime, freqM))可以快速做月度聚合看每个月地震次数变化非常直观。比如近一年里某个月次数突然抬升再结合空间分布图基本能锁定是哪片区域“贡献”的增量。这份数据的后续还可以做很多扩展比如把它和断层分布图层叠加分析震中与断裂带的空间关系或者把近一年目录按省份聚合做一个“省域地震活跃度排行”。但不管做哪种分析都要记住目录数据只是起点最终的解释需要结合区域地质背景和地球物理知识。数据能告诉你哪里震了、多大、什么时候但它不会直接告诉你为什么——那个部分需要你在掌握方法论之后自己去挖。