
做宏观地震活动分析的人应该都被同一个问题烦过数据源明明不少但每个源的格式、字段、时区、坐标定义都不一样光整理数据就能耗掉大半天。我第一次拿到 CnOpenData 整理的美国地震信息数据时最大的感受就是省心——它把美国地质调查局USGS那份庞杂的地震目录抽成了结构清晰的表格文件时间、经纬度、深度、震级这些最常用的字段基本都给你对齐了。这篇文章不翻字段手册就按我自己实际使用这批数据的流程从下载清洗到几个说得上话的分析思路再到各种翻车现场一次性讲清楚。适合想用现成数据做科研预研、课程作业、区域风险报告或者单纯想画一张漂亮地震分布图的朋友。1. 先搞清楚这份美国地震数据是什么、从哪来、能做什么1.1 数据来源、覆盖范围与常见字段如果只让我用一句话概括CnOpenData 美国地震信息数据就是把 USGS 发布的地震目录重新整理成了一份中文环境更容易使用的结构化数据。USGS 是全球科研和工程领域最常引用的地震数据源之一原始接口返回内容特别多英文缩写也多比如magType、nst、gap、rms这些术语初学者看到就头疼。CnOpenData 做了一件好事把核心字段抽出来统一命名让使用者直接从 CSV 或者 Excel 开始不用去和 JSON、API 参数较劲。覆盖范围上这份数据记录的主要是美国本土及其周边地区的地震事件。你打开文件后会看到这些常见字段UTC 时间、纬度、经度、深度、震级、震级类型、位置描述。有些版本还会保留参与定位的台站数nst、台站方位角空隙gap、走时残差rms等质量参数。这些质量参数对简单统计不一定用得上但如果你想判断某个地震定位是否可靠它们就很有价值。位置描述字段通常长这样“12 km NW of Anchorage, Alaska”虽然看似杂乱但做关键词筛选时反而方便直接用字符串包含匹配就能把区域挑出来。1.2 哪些场景适合用它哪些场景必须绕开我实际操作下来下面这些场景用这份数据非常顺手宏观地震活动性分析比如统计某年 M5 以上地震次数看区域活跃程度区域对比比如比较加州、阿拉斯加、中部内陆的地震频次差异空间可视化散点图、核密度图或者导入 kepler.gl 做交互地图教学和入门练习字段齐全但复杂度又不高特别适合学 Pandas、SQL 和基础绘图。但也有不能勉强用的地方。工程场地地震安全性评价、建筑选址、断层活动性监测这类专业任务需要结合断层模型、强震动记录、场地效应等数据一份简单的事件目录远远不够。此外如果你准备写学术论文我还是建议回到 USGS 原始数据至少做一次交叉验证。第三方整理数据可能调整过字段、筛选过事件、更新滞后这些都会影响结论的严谨性。我的态度是这份数据适合做快速上手、预研和教学但正式引用前必须回到权威源核对。2. 从下载到读入拿到文件以后先别急着跑分析2.1 下载后的文件形态与打开方式在平台上检索“美国地震信息数据”并下载后你拿到的通常是压缩包里的一个或几个 CSV 文件有时也提供 Excel 和 Stata 格式。单文件大小从几十 MB 到几百 MB 不等取决于时间跨度。如果你只做小范围演示建议先按年份选择一个文件跑通流程不用一次性把全量数据载入内存。解压后第一件事我建议先打开随附的数据说明或 README重点确认三件事时间字段是不是 UTC深度单位是不是公里震级字段用的是哪种类型。这三件事没有确认清楚就写代码后期返工概率极高。编码问题也很常见。有些版本为了兼容平台说明字段名可能是中文但数据内容还是英文地名和数字。用 Pandas 读取时如果出现乱码可以试一下encodingutf-8-sig这个参数能同时解决 CSV 在 Excel 里的兼容问题。还有不同批次之间字段顺序可能不完全一样所以写代码时一定要用列名取数别用iloc按第几列硬取。我就见过有人按列索引写分析脚本数据一更新所有结果全乱套。2.2 用 Python 给数据做一次快速“体检”我自己最顺手的工具还是 Pandas。下面这段代码可以直接抄先读入数据再做一次最基本的检查import pandas as pd df pd.read_csv( us_earthquake.csv, parse_dates[time], low_memoryFalse ) print(df.info()) print(df.describe(includeall)) print(df.isna().sum()) print(df.head())读入后我会重点看四个东西。第一行数是不是合理范围如果读出来只有几十条大概率路径选错或者文件本身被筛选过。第二时间列有没有成功解析成 datetime 类型如果没有说明原始时间字符串格式可能不止一种。第三经纬度、深度、震级这几列的缺失值有多少用df.isna().sum()看一眼别跳过。第四看看经度取值范围是否在 -180 到 180 之间纬度是否在 -90 到 90 之间。这四个检查加起来不超过三分钟但能挡住绝大多数低级错误。如果文件特别大比如超过 1 GB可以先用usecols只读刚才提到的核心列cols [time, latitude, longitude, depth, mag, magType, place] df pd.read_csv(us_earthquake.csv, usecolscols, parse_dates[time])这样能省下不少内存读取速度也会明显提升。如果数据量大到这种程度的还不够用再考虑用 Dask 或分块处理。我不建议一开始就直接上分布式工具对大多数基于地震目录的分析场景来说Pandas 已经足够能打了。2.3 版本、字段说明与可复现记录每次拿到新数据先花五分钟建一个数据 README记录下载时间、文件名、文件大小、字段列表以及你从数据说明里读到的关键参数时间时区、深度单位、震级类型。这个 README 可以就是一个.txt文件也可以是你分析脚本开头的注释块。目的很直白就是让三个月后的自己还能想起来这批数据是哪来的下载的哪个版本字段有没有差异。我踩过一个实际教训两个不同批次的文件一个字段叫depth_km另一个叫depth合并时没注意单位说明画图的时候冒出一堆深度异常大的事件。后来翻记录才发现其中一个批次把单位从公里写成了米。第三方整理数据虽然好用但跨批次合并前一定要比对字段定义别盲目pd.concat。记录这套元信息对以后应对审稿人或者做复现实验也特别有帮助。3. 字段级的较真地震数据分析的核心都在这几列里3.1 时间与震级最容易出错的字段先说时间。USGS 目录里时间几乎都是 UTC 协调世界时原始格式像2020-01-01T12:34:56.789Z。CnOpenData 整理后可能变成2020-01-01 12:34:56.789但时区依然是 UTC。如果你在中国大陆想转成北京时间直接用df[time_beijing] df[time] pd.Timedelta(hours8)。这里千万不要想什么夏令时UTC 本身不受夏令时影响加了反而错。震级字段需要格外留个心眼。目录里最常见的写法是mag表示主震级magType标注震级类型。但震级并不只有一种Mw是矩震级物理意义稳定适合描述大地震ML是地方性震级常用于小区域、近台站记录mb是体波震级Ms是面波震级还有Md是持续时间震级专门用于小震。如果你要画震级-频度曲线或者计算 b 值理论上应该先保证所用震级属于同一套体系。正式分析时优先把magType筛成Mw或ML再做统计不要把所有类型混在一起直接求平均那样会引入系统性偏差。3.2 空间字段、深度与位置文本经纬度字段用的是十进制度WGS84 坐标系。美国本土的经度是负的西经值阿拉斯加和夏威夷同样也是负经度看到 -122 不用觉得异常。做坐标检查时如果发现经度出现正的 122很可能是符号丢失或者列错位要赶紧回头查。画图时直接用longitude和latitude作为 XY 没有问题但如果要做距离计算、面积计算或核密度分析请先把数据投影到一个适合美国范围的等积投影坐标系比如美国本土用 Albers 等积投影阿拉斯加单独处理。拿着经纬度直接算公里距离结果往往错得离谱。深度字段通常以公里为单位这是一个冷知识USGS 的 depth 大多数是正数但偶尔会出现负值。负值不代表错误它可能代表定位结果在海平面以上比如个别火山地震或人工爆破事件。清洗时不要一看到负数就删先判断数据量占比和来源。位置描述字段 place 是给人读的文本它也可以作为快速筛选工具。比如想看加州区域可以用df[df[place].str.contains(California, caseFalse, naFalse)]。注意末尾的naFalse否则缺失文本会产生异常结果。3.3 缺失值和异常值先处理再分析现实数据不会像教科书一样干净。USGS 原始目录里小地震经常缺mag、nst、rms字段。处理原则不复杂如果是做宏观统计先dropna(subset[time, latitude, longitude])这是底线三个核心字段都缺了就没法定位震级缺失则分场景画震级分布图时必须丢弃但做空间点位图时可以保留用“未测定震级”单独表示即可。异常值也不只有缺失一种还有被自动算法错误标记的事件。比如采石场爆破、矿山爆破经常被系统误判成天然地震。美国中西部有一些著名的“地震群”研究之后发现和油田注水或采矿有关。想区分天然和非天然事件可以参考 USGS 官方提供的标识如果数据里没有可以在报告里注明“未过滤非天然震源”。我的建议是建立一个固定的清洗顺序先统一时间格式再剔除无法定位的记录再检查深度、震级取值范围最后再按自己的业务规则筛选。顺序不要颠倒否则时间解析一错后面所有结果都带着隐性 bug。4. 上手就能用的几个分析思路4.1 年度频次统计用 5 级以上地震看趋势很多新手拿到数据就统计全部地震数量然后得出“某年地震特别多”的结论这其实很危险。小震级事件的记录完备性严重受台网分布和技术年代影响早期漏掉的小震非常多总数根本不可比。所以做趋势分析时要过滤出一个较完备的震级下限比如全美范围选 M5 以上区域范围选 M4 以上。代码可以这样写df df.dropna(subset[time, mag]) df[year] df[time].dt.year strong df[df[mag] 5] yearly_counts strong.groupby(year).size() yearly_counts.plot(kindline, figsize(10, 4))跑完之后你会看到美国及周边 M5 以上地震通常在每年百余次不同年份有波动但不会有特别离奇的趋势。如果某个年份突然出现数倍抬升先别兴奋先检查是不是台网升级或者目录补录造成的而不是真实的活动增强。4.2 空间分布可视化三行代码画出一张地震点位图地震数据最适合先看图。用 Matplotlib 画散点图最容易但如果不做任何分级处理美国西部频繁的小震会把图面叠加成一大团黑色。我的做法是用点的大小表示震级用颜色表示深度再调低透明度。示例代码如下import matplotlib.pyplot as plt df_plot df[df[mag].notna()].copy() df_plot df_plot[df_plot[longitude].between(-180, -50)] plt.figure(figsize(12, 8)) plt.scatter( df_plot[longitude], df_plot[latitude], sdf_plot[mag] ** 2, cdf_plot[depth], cmapviridis_r, alpha0.4 ) plt.colorbar(labeldepth (km)) plt.xlabel(longitude) plt.ylabel(latitude) plt.title(US Earthquake Distribution) plt.show()震级平方是为了让中强震与弱震的点大小区别更明显。画完以后圣安德烈亚斯断层带、阿拉斯加阿留申弧、夏威夷火山地震带基本一眼就能认出来。如果要做交互式地图可以把数据导出为 GeoDataFrame再放到 kepler.gl 或 QGIS 里做效果更好。4.3 计算 b 值理解地震大小配比的入门指标震级-频度关系是地震学里非常经典的内容公式形式是log10 N a - bM其中 b 值一般接近 1。这个值反映了小地震与大地震数量的比例。计算方式有很多最基础的是最大似然估计配合最小完备震级 Mc。下面给一个可以直接跑的版本import numpy as np def estimate_b(mags, mc): mags mags[mags mc] if len(mags) 30: return np.nan mean_mag np.mean(mags) return np.log10(np.e) / (mean_mag - (mc - 0.05)) mc 3.0 b estimate_b(df[mag].dropna().values, mc) print(b value:, round(b, 3))这里引入 0.05 的修正项是因为震级记录通常有 0.1 的分组间隔用Mc - bin/2做中心修正更稳定。Mc 的选择不能拍脑袋最简单的方法是做一幅震级-频次图找到曲线明显偏离直线的拐点拐点对应的震级就是最小完备震级。b 值不是固定的不同区域、不同深度带算出来会有差异这是研究构造应力状态的好素材也是很多论文讨论的热点。4.4 结合人口、高程等外部数据往风险评估方向走一步有了地震点位以后很多人想进一步评估影响。一个比较稳妥的做法是把地震点与人口栅格做空间连接统计某震级以上的地震周边一定半径内的人口暴露情况。用 GeoPandas 读取一份全球人口密度栅格然后对每个地震点做缓冲分析再用sjoin叠加求和。这个分析的价值不在于给出预测而在于提示“如果这个位置发生地震潜在受扰动人口大概是什么量级”。做这一步时必须清醒人口暴露不等于伤亡地震影响还取决于建筑结构、发生时间、地形条件等很多因素。把结果定性为“潜在暴露”而不是“风险评估”表达上更准确。这个方向对城市防灾、应急资源配置、学生项目展示都很有吸引力也能让报告从“画点图”升级成“有空间格局的分析”。5. 我踩过的坑希望你能直接跳过5.1 时区与日期解析上的“幽灵一小时”我曾经按小时聚合某年地震事件结果发现每天 00 点附近都有一个异常高峰。排查了半天才发现时间列在 Pandas 里已经是 UTC但我用 Excel 打开时部分字符串被 Excel 自动转换成了本地时间来回混合后就产生了 8 小时错位。从那以后我给自己定下规矩所有时间处理一律在 Python 里完成解析后统一保存为 UTC 时间戳不再导到 Excel 里手动改时间。一旦你在 Excel 里手工改过时间格式后面追 bug 会追到怀疑人生。还有一个容易漏的点同一个地震可能在不同批次文件里出现但时间的小数秒可能不同。去重时不要把time当作唯一键最好联合latitude、longitude、mag、time四列或者使用 USGS 事件 id。CnOpenData 整理版不一定保留 id所以看到“看起来一模一样”的行时先检查是不是毫秒级差异再决定去重逻辑。5.2 小震级完备性不要把漏记当增长处理历史目录时最容易犯的错就是把台网密度提升造成的“小震越来越多”解读成地震活动增强。1980 年代和 2020 年代美国本土的台站数量完全不是一个量级早期小震漏记非常严重。判断数据是否完备一个简单办法是做震级-频次图找到明显偏离直线的震级下限。我通常只对完备震级以上的数据进行趋势分析和 b 值计算这样不同年代之间的对比才是可信的。5.3 震级类型混用比较和取均值前先统一有一次给团队做汇报我直接用所有事件的mag求平均结果数值明显偏高。排查后发现目录里混了大量Md和mb它们和Mw并不在同一尺度上尤其小地震差异更明显。正确的做法是在需要量化时只保留你关心的震级类型。筛选逻辑可以像这样df_mw df[df[magType].str.upper().isin([MW, MWW, MWC])]如果不用那么严格至少也要剔除明显异常的行比如mag小于 -1 或大于 10。小于 0 的震级是真实存在的但在目录里很少你要确认自己是否真的关心它们而不是让它污染统计结果。5.4 深度单位、坐标范围和地图投影有一次画震源深度剖面图我把深度当成了米画出来的震源深到不可思议后来才发现 USGS 标准单位就是公里。这个错很蠢但也很常见。如果你要把深度和某些工程数据叠加可能需要转成米但原始解析基准一定是公里。坐标范围也要做区间检查经度应在 -180 到 180纬度应在 -90 到 90。如果出现经度 122 这种正数多半是符号丢失或列错位不要忽略。做空间展示时尽量用适合美国的投影再做区域分析。直接用经纬度画散点图没问题但做热点分析或面积统计时最好使用等积投影比如 Albers Conical Equal Area。否则高纬度地区会在图上看起来比实际“胖”很多热点区域也会被扭曲。5.5 目录版本与审核状态别把“自动”当成“定稿”数据整理方一般会定期更新但你拿到的数据可能是某个时间点的快照。USGS 目录中事件分为 automatic 和 reviewed 两种状态自动事件可能被后续修正。如果你拿到的文件里有status字段正式统计时尽量只保留 reviewed 事件或者至少在报告里说明是否包含自动事件。没有这个字段的话就记录下载日期和文件版本确保别人能复现你的结果。我自己的习惯是每下载一批数据就在项目目录写一个data_metadata.txt内容包括下载日期、原始文件名、文件哈希值、字段列表和数据说明里的关键参数。这个习惯后来帮我省了很多回看和复盘的力气。数据这种东西越是源头干净后面越顺。最后再分享一个小技巧拿到任何一批地震数据先别写复杂算法只打印时间范围、空间范围和震级范围再看一眼描述性统计。整个过程不超过五分钟但能挡住后面至少一半的返工。分析地震数据拼的往往不是模型多高级而是基础盘稳不稳。