搞气象数据处理的人,十有八九都绕不开“中国国家级地面气象站基本气象要素日值数据集(V3.0)”这个老伙计。我最早接触它还是在学校做毕业论文那会儿,当时为了下载一套全国站的降水资料,在数据服务平台上实名注册、填申请理由、等审核,折腾了快一周才拿到权限。后来工作里做气候评估、农业气象服务、水文模型验证,又反复跟这个数据集打交道,可以说它是我见过的最“皮实”也最考验耐心的公开气象数据产品之一。
这套数据集简单来说,就是把全国两千多个国家级地面气象站每天观测到的气压、气温、降水、风、湿度、日照、蒸发、地温等基本要素,统一整理成规范化的日值记录,并附带一套质量控制信息。它解决的问题非常直接:你想做全国尺度的气候变化分析,或者某个区域的农业积温统计,不需要自己去档案馆翻纸质报表,也不用自己拼凑零散的月报数据,直接下载这套日值文件就能开工。适合的人群也很明确——气象、水文、生态、农业、环境领域的科研人员和工程师,以及正在做相关课程设计或毕业论文的高年级本科生和研究生。
不过说实话,这套数据虽然公开透明,但“会用”和“能拿到”是两回事。尤其是V3.0版本,文件结构、缺省值标记、质量控制码都有一套自己的规矩,不摸清楚就硬读,很容易在第一步就把数据读歪了。这篇我就把自己实际使用中的经验整理出来,从数据解构、文件解析、缺测处理,到实战计算和避坑清单,一步步说清楚。
1. 先看懂数据集:它到底装了什么
1.1 从一套“国字号”观测资产说起
很多人第一次接触“国家级地面气象站”这个概念时,容易把它理解成“所有气象站”,其实这是不对的。我们每天在天气App上看到的几万个自动站,大部分属于区域自动站,站间距小、密度高,但历史资料参差不齐,质量控制水平也不统一。而这套V3.0数据集里的“国家级站”,指的是纳入国家气象观测网业务运行、执行统一观测规范和传输标准的台站,包括国家基准气候站、国家基本气象站和国家一般气象站,总数大概在两千多个量级。
这套站网的历史价值非常大。基准站有的从上世纪五六十年代就开始持续观测,中间经历仪器换型、台站搬迁、观测时次调整,站址和仪器变迁信息在随附的台站元数据文件里都有登记。我经常把它类比成一支“老兵队伍”:虽然每个人(每个站)都有一点自己的小毛病,但整体纪律严明,业务化运行几十年,数据连续性和可比性是区域自动站完全比不了的。做长序列气候趋势分析,优先用这套数据,而不是随便抓一堆加密站来拼凑,这是最起码的严谨性问题。
V3.0这个版本号,含义也不只是“第三次修订”。它意味着时间序列覆盖做了系统性延长,许多站的数据更新到近年份;质量控制流程重新梳理过,可疑、错误、缺测的标记规则更清晰;台站基本信息表(经纬度、海拔、区站号)也做了核对修正。相比更早的版本,V3.0能明显减少“拿到的数据和台站位置对不上”这类尴尬问题。
1.2 八大基本要素与字段结构
V3.0日值数据集的核心是八个基本气象要素。我整理了一个速查表,方便你对照理解:
| 要素名称 | 数据文件名常见标识 | 主要内容 | 常用单位 |
|---|---|---|---|
| 气压 | PRS | 平均本站气压、日最高/最低气压 | 0.1 hPa |
| 气温 | TEM | 平均气温、日最高/最低气温 | 0.1 ℃ |
| 降水 | PRE | 20-20时或08-08时降水量 | 0.1 mm |
| 蒸发 | EVP | 小型蒸发皿蒸发量 | 0.1 mm |
| 相对湿度 | RHU | 平均相对湿度、最小相对湿度 | 1 % |
| 风向风速 | WIN | 平均风速、最大风速及风向、极大风速及风向 | 0.1 m/s |
| 日照时数 | SSD | 逐日日照时数 | 0.1 h |
| 地面温度 | GST | 0cm平均地温、日最高/最低地温 | 0.1 ℃ |
注意,上面的单位我写的是“0.1 hPa”“0.1 ℃”这类形式。这是气象数据文件里非常常见的“缩放存储”做法——为了压缩存储空间、保留一位小数精度,文件里存的是整数,比如气温字段存的是“235”,实际值就是23.5℃。我见过不少新手直接把235当成235℃拿去画图,画出来的东西自己都觉得离谱,半天找不到原因。所以解析数据时,务必要看随附的《数据说明》文档,搞清楚每个字段有没有缩放系数,这是读这套数据的第一个硬门槛。
每条日值记录通常包含区站号、年、月、日、要素值、质量控制码这几个字段。不同要素的文件结构略有差异,比如气温文件除了平均值,还会有最高值、最低值并各自带质控码;风要素会有平均风速、最大风速、极大风速等多个字段。建议先把说明文档里的“数据文件格式”一节复制出来,对着格式说明逐列检查再写解析代码。
1.3 V3.0相比老版本的关键变化
如果你以前用过V2.0或者更早的手工整理版本,会明显感觉V3.0有三个变化。
第一是元数据信息更完整。每个站点的经纬度、海拔、站名、建站年份、资料起止时间,都有统一的说明文件。这个看起来不起眼,实际作用很大——以前经常出现“资料里有个站号,但不知道这个站在哪儿”的困境,做空间插值时无从下手。
第二是质量控制码体系更规范。老版本里质控标记存在缺失和前后不一致的情况,V3.0对绝大多数记录都标了质控码,便于用户按需过滤。
第三是文件组织方式更适合程序化处理。按要素拆分为独立文件,每行一条记录,这种“长表”结构在pandas、R里处理起来非常顺手,不用再手工复制粘贴Excel了。
不过也要提醒一句:V3.0并不是把所有历史数据全部重算重审了一遍,早期年份(比如上世纪五六十年代)的数据质量仍然受当时观测条件限制,有些记录即使质控码标为“正确”,和现代仪器观测值之间也可能存在系统性差异。这是历史资料的通病,不是你下载的数据有毛病。
2. 拿到数据以后怎么读:解析、缺测与质控
2.1 原始文件的“脾气”:分隔符与固定宽度
从数据服务平台下载下来,通常是一个压缩包,解压后每个要素一个文本文件,或者所有要素合在一个目录里。文件内部最常见的格式是每行一条观测记录,字段之间用空格分隔,少数文件用固定宽度排列。我强烈建议第一次打开某个文件时,不要急着写代码,先用文本编辑器直接看前二三十行,把字段排列方式肉眼确认一遍。
这里有个容易踩的坑:字段之间的空格数量可能不固定。有的文件是用单个空格分隔,有的为了对齐用了多个空格,直接按空格split在某些编程语言里会产生空字符串。Python里用split()方法默认会处理连续空白符,问题不大,但如果用固定宽度截取方式读取,就必须严格按说明文档里的“起始列-结束列”来切。
另外一个需要特别留意的点是“微量降水”和“缺测”的编码。V3.0数据里,降水量字段通常用特定的大数表示特殊状态,比如32700系列。32766通常表示缺测,32744一般表示降水微量(比如雾、露、霜、雾凇等产生的湿迹,量小到无法用雨量筒准确量取)。如果不看说明,直接把这些数当成真实降水量去累加,年降水量能给你算出上万毫米来,明显不合常理。我一般会在读取后立即把特殊值替换为NaN,单独建一列标记“是否为微量”,这样后续统计既不会把微量当成真实降雨,也不会丢弃掉“有降水现象但量级极小”的信息。
2.2 用Python快速读取一整套日值文件
读取这类文件,pandas是首选工具。以气温要素为例,我常用的读取代码大概长这样:
import pandas as pd import numpy as np # 假设文件为空格分隔,无表头,字段顺序为: # 区站号 年 月 日 平均气温 平均气温质控码 最高气温 最高气温质控码 最低气温 最低气温质控码 col_names = [ "station_id", "year", "month", "day", "tavg_raw", "tavg_qc", "tmax_raw", "tmax_qc", "tmin_raw", "tmin_qc" ] df = pd.read_csv( "SURF_CLI_CHN_MUL_DAY_TEM_2020.txt", sep=r"\s+", header=None, names=col_names, dtype={"station_id": str} ) # 缺省值处理:气温字段常见的缺省标记为32766 q_missing = 32766 for col in ["tavg_raw", "tmax_raw", "tmin_raw"]: df[col] = pd.to_numeric(df[col], errors="coerce") df.loc[df[col] == q_missing, col] = np.nan # 单位缩放:原始值单位为0.1℃,转成标准℃ for col in ["tavg_raw", "tmax_raw", "tmin_raw"]: df[col] = df[col] / 10.0 # 构造日期列 df["date"] = pd.to_datetime(df[["year", "month", "day"]]) # 过滤质量控制码为正确的记录 # 不同版本的质控码定义略有差异,以说明文档为准,0通常表示数据正确 df_valid = df[df["tavg_qc"] == 0].copy()这段代码里有几个关键动作值得解释一下。
先把station_id读成字符串,是因为区站号是五位数,像01001这类站号如果按数字读,前导零会被丢掉,后面做站点匹配时就会对不上。再把原始数值列转成数值类型,并把缺省值替换为NaN,这样后续mean()、sum()等统计函数才会自动跳过缺失值,不会把32766这种“假数字”算进去。最后做单位缩放,把整数存储还原成有物理意义的值。质量控制过滤我单独做了一步,因为“质控码为0”和“缺失值”是两个不同的概念,前者代表数据被判定为正确,后者代表压根没有观测,两者不能混为一谈。
2.3 质量控制码到底该怎么理解
V3.0数据集里几乎每个要素值旁边都带一个质量控制码,常见取值和含义如下(具体以你下载的版本说明为准):
| 质控码 | 含义 | 处理建议 |
|---|---|---|
| 0 | 数据正确 | 可直接使用 |
| 1 | 数据可疑 | 建议复核或剔除 |
| 2 | 数据错误 | 必须剔除或修正 |
| 3 | 数据缺测 | 当作缺失值处理 |
| 4 | 未做质量控制 | 谨慎使用,需自行检查 |
| 9 | 数据缺失(无观测任务) | 当作缺失值处理 |
实际处理时,我见过三种典型做法。保守派只保留质控码为0的记录,这样最干净,但对于历史早期资料可能会丢掉大量记录;实用派会把0和1都保留,毕竟“可疑”不代表“错误”,有时候是气候极值事件,比如某站日降水量突破历史极值,机器初判可疑,人工复核后其实是真实记录;还有一种做法是把质控码当作权重信息保留,建模时对质控较差的记录降权。
我个人的建议是:做气候统计时,至少要把质控码为2和3的记录剔除掉,质控码为1的记录看具体场景决定去留。如果你是做极端事件分析,恰恰要仔细查看“可疑”记录,因为这些记录里往往藏着真正的极值——当年某地日降水创新高的时候,程序的第一反应就是“这数看着可疑啊”。
3. 实操案例:从原始文件到一份可用时间序列
3.1 挑选合适合法站点的硬规则
很多人拿到数据后第一件事就是把所有站点的数据读进来,然后直接算全国平均。这个操作其实有风险,因为不同站的建站时间、迁站历史、缺测比例差别很大,不加筛选就平均,结果可能被某些“早退晚到”的站点带偏。
我一般会先做三件事。
第一,检查站点观测年限。做气候趋势分析时,通常要求站点有足够长的连续观测记录,比如至少30年,或者至少覆盖你研究的起止时段。如果一个站在2005年才建站,你却拿它去算1980—2020年的气候平均,那肯定不对。
第二,检查站点是否有严重缺测。有些站某个时段维护不善,一年里缺了三分之一的天数。这种站直接参与年平均温度计算,会让该年区域平均值出现虚假波动。一个可行的处理标准是:某个年份缺测天数超过15%,该年就不参与站点年平均计算;缺测比例更高的站甚至整站剔除。
第三,留意台站迁移记录。国家级气象站并非永远建在同一个地点,城市扩张、机场建设、观测环境恶化都可能导致台站搬迁。新站址和旧站址海拔、地形不同,观测值会出现系统偏差,比如从城区迁到郊区,年均温可能一下子掉下去0.5℃甚至更多。如果做长序列变化趋势,不处理这种“断点”,算出来的趋势可能完全是迁站造成的假象。正规做法是用RHtests等均一化工具检测和修正断点,至少也要在论文里说明哪些站发生过迁移,并做敏感性分析。
3.2 计算区域平均气温趋势的完整流程
说一个我最近实际做过的例子:计算某区域过去40年的年平均气温距平序列。
第一步,读取所有站点逐年平均气温。气温日值数据已经按上面说的方法解析成DataFrame后,按站点和年份分组求平均:
# df_valid 为过滤后的日值数据 df_valid["year"] = df_valid["date"].dt.year # 先计算各站各年的年平均气温 annual_mean = ( df_valid.groupby(["station_id", "year"])["tavg_raw"] .mean() .reset_index() ) # 计算各站气候基准期(比如1981—2010)的平均值 base_period = annual_mean[ annual_mean["year"].between(1981, 2010) ] clim = ( base_period.groupby("station_id")["tavg_raw"] .mean() .to_dict() ) # 计算各站逐年气温距平 annual_mean["anomaly"] = annual_mean.apply( lambda row: row["tavg_raw"] - clim.get(row["station_id"], np.nan), axis=1 ) # 区域平均:对年份求所有站点的平均距平 regional_series = ( annual_mean.groupby("year")["anomaly"] .mean() .dropna() )第二步,对区域平均距平序列做线性趋势估计。用scipy的linregress就可以:
from scipy import stats years = regional_series.index.values values = regional_series.values slope, intercept, r_value, p_value, std_err = stats.linregress(years, values) # 趋势单位:℃/10年 trend_per_decade = slope * 10.0 print(f"趋势: {trend_per_decade:.2f} ℃/10年, p值: {p_value:.4f}")这里有几个容易出错的地方。
一是“距平”和“平均温度”的区别。区域平均温度受站点海拔、纬度影响很大,直接对多个站点的绝对温度做平均,得到的值其实没有太多空间代表性。而先算每个站相对自身气候态的距平,再对距平做区域平均,能把海拔和纬度的系统差异去掉,更能反映真正的气候变化信号。这是气候诊断里的基本操作。
二是年平均值缺失的控制。如果某站某年数据缺了七八个月,直接求年均值会严重偏低或偏高(取决于缺的是夏季还是冬季)。我在算年均值之前,会先检查每个站每年的有效天数,有效天数低于330天的年份直接设为NaN。
三是基准期的选择。WMO推荐用最近三个完整的十年作为气候基准期,目前常用1981—2010年或1991—2020年。用什么基准期会在结果上造成差异,写论文时必须注明。
3.3 极端指数与积温的快速计算
除了平均温度,日值数据最常用的还有两类衍生计算:极端温度指数和农业积温。
极端温度指数里,TXx(年最高气温最大值)、TNn(年最低气温最小值)是最基础的。直接从日值数据里按年分组取最大最小即可:
# TXx:每年每个站点的日最高气温最大值 txx = ( df_valid.groupby(["station_id", "year"])["tmax_raw"] .max() .reset_index() .rename(columns={"tmax_raw": "TXx"}) ) # TNn:每年每个站点的日最低气温最小值 tnn = ( df_valid.groupby(["station_id", "year"])["tmin_raw"] .min() .reset_index() .rename(columns={"tmin_raw": "TNn"}) )这类指数在气候变化研究里属于“极端气候事件”的核心指标,可以用来分析霜冻风险变化、高温热浪趋势等等。要注意的是,如果某年数据缺测较多,计算出的年极值会偏低(因为真正极值那天可能恰好缺测),所以极端指数计算前对缺测的筛查比平均值更严格,一般要求全年有效天数在360天以上。
积温是农业气象里的老面孔了。简单地说,把一年中所有日平均气温大于等于某个生物学下限温度(比如0℃或10℃)的日期,每天超过下限的那部分温度累加起来,就是活动积温:
base_temp = 10.0 df_valid["active_temp"] = df_valid["tavg_raw"] - base_temp df_valid.loc[df_valid["active_temp"] < 0, "active_temp"] = 0.0 # 每年每个站点的≥10℃活动积温 accumulated_temp = ( df_valid.groupby(["station_id", "year"])["active_temp"] .sum() .reset_index() .rename(columns={"active_temp": "AT10"}) )积温对作物种植区划、品种选择很有参考价值。比如华北平原冬小麦—夏玉米复种的地区,常常用≥0℃积温来评估热量资源够不够。做这类统计时,同样要处理好微量降水和缺测的问题,否则个别站点的数据会在关键生育期出现缺口。
4. 典型应用场景:科研、工程、农业与模型
4.1 气候变化特征分析
这是V3.0数据最经典的应用方向。有了长序列的日值气温和降水数据,可以做年际趋势分析、突变检验(如Mann-Kendall检验)、周期分析,也可以计算各种气候指数,比如前面提到的TXx、TNn,以及连续无降水日数、强降水日数、高温日数等等。
我印象很深的一次经历是帮某地做气候可行性论证,需要用过去50年的气温数据分析当地热岛效应是否在增强。方案是把国家级站的城区站和郊区站分开统计,用日最低气温的差值变化来表征热岛强度。这个分析完全依赖日值数据,因为月值数据把日变化信息抹掉了,热岛效应的夜间信号就看不出来了。
做这类分析时有一点特别重要:一定要把“站点代表性变化”和“真实气候波动”区分开。城市站周围盖了楼、铺了路,观测到的温度上升有一部分是局地环境变化,不是大尺度气候背景的变化。学术上管这个叫非均一性,处理不好会让你得出“某地升温特别快”的错误结论。稳妥的做法是先做均一化检验,或者至少把城市站和乡村站分开对比。
4.2 农业气象服务与灾害评估
农业是气象数据最接地气的应用领域之一。V3.0日值数据可以做的事情包括:
- 计算稳定通过某一界限温度(如0℃、5℃、10℃、15℃)的初日和终日,以及持续日数;
- 计算各时段降水量和干燥指数,判断干旱风险;
- 用日照时数和气温数据估算参考作物蒸散量(彭曼公式需要日照、温度、湿度、风速四类数据,日值数据集刚好都能提供);
- 分析霜冻、高温热害、连阴雨等农业气象灾害的发生频率和强度。
比如你要评估一个区域冬小麦的越冬条件,需要知道冬季最低气温能不能低到造成冻害。从日值气温数据里提取每年12月到次年2月的极端最低气温,再叠加地理信息做空间分布,就能回答这个问题。这类分析在农业保险定损、政策性农业补贴评估里很有实用价值。
有一点需要注意:做农业服务时,单站点的数据往往还不够用,通常要和GIS结合,做空间插值或区域统计。而空间插值的质量高度依赖站点的空间代表性,如果某区域站点稀疏,插值出来的结果不确定性会很大。实在缺资料的地方,可以把这套国家级站数据和区域自动站数据结合起来用,但前提是先做好两套数据的一致性检验。
4.3 水文模型与陆面过程模拟的驱动数据
水文模型和陆面过程模型通常需要降水、气温(最高、最低)、风速、湿度、辐射等驱动数据。V3.0日值数据可以提供其中很大一部分。
比如在某个流域建立降雨径流模型,需要把逐日降水数据插值到流域的每个网格上。国家级站的密度在某些山区可能不够,但用它们做模型率定期和验证期的基准数据是没有问题的。再比如做蒸发能力分析时,彭曼公式需要日照时数,而日照时数恰恰是这套数据集里比较有特色的要素,区域自动站很多不观测这个项目。
我自己的经验是:模型驱动数据宁可“质控严”也不要“只用最新”。有些模型对极端降水非常敏感,如果驱动数据里混入了质控码为2的错误降水记录,模型可能直接跑飞。所以在数据预处理环节把质量控制做到位,是对后面所有模拟结果负责。
4.4 教育、科普与行业报告
这套数据的另一个“隐形用途”是教学和科普。很多高校的气象学、水文学课程作业和毕业论文都用它做案例数据。
我见过学生用这套数据画全国年平均气温分布图的,用ggplot2或matplotlib叠加中国地图,直观展示气温从南到北的梯度;也见过地理信息科学专业的学生拿它做空间插值方法的对比实验。这些场景对数据时效性要求没那么高,但对数据规范性的要求很高,V3.0正好满足。
行业报告方面,气象服务公司、农业咨询机构、保险公司做区域气候背景分析时,也经常引用这套数据作为“事实基准”。比如做风力发电项目前期评估,需要多年平均风速和最大风速极值,V3.0数据里的风向风速日值就可以用来做初步的风能资源估算——当然可研阶段还要加密测风,但前期筛选项目做得快、做得省。
5. 常见问题与排查技巧实录
5.1 7个高频问题速查表
我把自己和同行在实际使用中遇到的问题整理成了下面这个表,方便你遇到同类情况时快速对照:
| 问题现象 | 可能原因 | 处理办法 |
|---|---|---|
| 某站某年数据全是32766 | 该站当年业务中断或迁站停测 | 按缺失处理,不参与该年统计 |
| 累计年降水量出现上千毫米,明显离谱 | 没处理缺省值,32766被当成真实降水参与累加 | 读取时把32700系列特殊值替换为NaN |
| 气温出现“-400”这类值 | 没做单位缩放,原始值存的是0.1℃ | 除以10再使用 |
| 站点经纬度和印象中位置对不上 | 台站发生过搬迁,元数据文件登记的是新址经纬度 | 以随附元数据文件为准,并在分析中记录迁移信息 |
| 某站数据从某年开始“风格突变” | 可能换了仪器类型或观测时次,或台站搬迁 | 做均一化检验,识别断点 |
| 质控码为1的记录特别多 | 该站处于地形复杂区域,数据波动大,程序判定“可疑” | 人工抽查部分记录,结合天气过程判断是否保留 |
| 读文件时字段对不齐 | 文件是固定宽度格式,或者空格数不固定 | 用说明文档里的列位置截取,或用正则切分连续空白符 |
5.2 我踩过的几个坑
第一个坑是微量降水的处理。有一次帮人做区域降水气候态分析,有个站点的年降水量比其他站明显偏低,一开始以为是站点问题,后来查出原因在微量降水记录上。那个站点在干旱区,一年里很多天有微量降水现象,如果简单地把所有32744微量记录当作0毫米处理,年降水量就会被低估不少,直接影响到干旱区水资源评估的结论。正确的做法是把微量降水单独标记,统计时可以分别输出“有量降水日数”和“微量降水日数”,或者按固定比例折算,但一定要让读者知道你是怎么处理的。
第二个坑是台站迁移造成的虚假趋势。某次我做某城市的长期气温趋势分析,发现最近二十年升温速率接近每十年1℃,远超周边站点。排查后发现该市气象站正好在中期从老城区搬迁到了新开发的工业区附近,新站址下垫面变化导致温度记录产生系统性偏差。后来我用周边乡村站做了对比订正,才把虚假信号修正过来。从那以后,凡是做站点长序列分析,我一定先查台站历史沿革文件。
第三个坑是“质控码过滤顺序”。曾经有个学生把质控码为2的数据直接删掉,再用dropna去重,结果发现原本应该标记为“错误”的某些极值记录被直接抹掉了,导致后续极端气候事件分析里漏掉了一次重要的历史高温过程。质控码为2的数据不代表“不存在”,而是“存在但不可信”,到底是不用、修正还是参考,取决于你的研究目的,不能一刀切删除。
5.3 处理这类数据的通用方法论
最后分享一点偏方法论层面的心得。我从处理V3.0数据集的过程里总结出一个“三分离”原则,也推荐给处理其他类似气象数据集的朋友。
第一,缺失值、特殊值、真实值要分离处理。读取原始数据后,先把特殊编码挑出来单独存放,再根据物理意义决定是丢弃、插补还是标记为事件。
第二,质量控制过程与统计计算过程要分离。不要在一个脚本里既做质控又做统计分析,否则后面换了质控标准,整个统计结果都得重跑。建议先输出一份“清洗后”的中间文件,统计分析脚本直接读取干净数据。
第三,原始文件、处理脚本、输出结果要分离存放。原始文件永远保留只读,处理脚本写清楚版本和日期,输出结果按项目、时间命名归档。这套工作流看起来笨,但等你三个月后要重跑某个结果、或者合作者问你要某个数据来源时,就知道它有多重要了。
根据我自己的经验,这套V3.0数据集最值钱的地方不在某个单独站点的精确数值,而在于它提供了一套覆盖全国、持续更新、相对规范的观测序列。与其急着跑复杂的模型,不如先把数据质量控制和可视化摸透。我处理完一套数据后,都会顺手导出一份清洗好的netCDF或CSV存档,留好对应的处理日志,后续写论文或做业务项目时直接复用,能省掉大量重复劳动。
如果你正准备跟这套数据“死磕”,我的建议很简单:先把说明文档完整读两遍,再用小范围数据试读练手,最后才上全量数据跑统计。别嫌前期准备工作枯燥,这些功夫花下去,后面出错的概率能少一大半。