做过人口空间化的人都懂那种别扭:手里有一份统计年鉴,每个区县一个总数,可你要回答的问题偏偏是“这条街道三公里范围内住着多少人”“洪水淹到哪一层楼会影响到多少户”。行政口径的数字落到空间上就散架了。1km 精度人口分布栅格数据,说到底就是把“每平方公里住多少人”这件事,从表格里搬到地图上,让每一个约一平方公里的像元都带上一个可计算的人口值。它解决的不是统计问题,是空间问题。
这份 2000 到 2023 年、覆盖全球到分市多个尺度的人口栅格数据,价值不在于“有数据”,而在于它给了你一条时间轴。单一年份的人口栅格只能做横截面分析,二十多年的序列才能做增长速率、重心迁移、城市扩张强度、灾害暴露度演变这类纵向研究。做城市规划的、搞公共卫生资源配给的、算碳排放和能耗基线的、做商业选址和门店覆盖评估的,只要你的问题和“人在哪儿、有多少、怎么变”沾边,这套东西都能直接上手。
我把话说在前面:这类数据看着是“下载即用”,实际上从打开文件到跑出能写进报告的结论,中间有一堆坑。单位是密度还是总量、重采样该用哪种算法、边界像元算不算、跨年份产品版本不一致怎么办,随便踩一个,结果就能差出百分之几十。下面这些内容是我自己反复折腾出来的流程和判断标准,从数据体检到分区统计到误差校验,尽量写到你能直接照着做的程度。
1. 这份数据到底解决了什么问题
1.1 行政口径与栅格口径的根本差别
统计口径的人口数据,本质是“面”的属性,而且这个面是人为划定的管理单元。它有两个绕不开的局限:一是空间分辨率完全取决于行政区大小,一个面积三千平方公里的县和一个面积三十平方公里的城区街道,在数据表里都是一行;二是边界内部的分布被完全抹平了,你把全县人口平均撒到每一寸土地上,山区和县城中心得到的是同一个密度值,这显然不符合现实。
栅格口径换了一套逻辑:把地球表面切成规则的网格,每个网格给它一个人口估计值。网格大小固定,不随行政边界变化,这就让跨区域、跨年份的横向比较成为可能。更关键的是,栅格可以任意叠加——洪水淹没范围、噪声影响圈、三公里生活圈、某个产业园的辐射半径,这些图层在行政单元上根本对不齐,在栅格上却是天然匹配的。
从业者最常犯的一个错误,是拿栅格汇总出来的数字去和统计公报硬碰硬,发现对不上就认为数据有质量问题。实际上两者本就不是一个东西:栅格产品通常是用建成区、土地利用、夜间灯光、路网密度这些协变量,把行政总量“分摊”到像元上的结果,分摊模型本身就带假设。它保证的是分布形态的相对合理,不保证每个单元都精确复现统计值。理解这一点,后面所有的误差分析才有意义。
1.2 1km 分辨率在不同场景下的实际含义
1km 这个尺度,说大不大说小不小,具体够不够用完全看你的研究对象。在赤道附近,一个 30 弧秒的像元边长约 0.927 公里,面积约 0.86 平方公里;到了北纬 40 度,东西向边长缩短到约 0.71 公里,像元面积只剩约 0.66 平方公里。这个纬度效应必须记住,因为它直接影响你从“密度”换算“总量”的计算。
放到实际场景里比一比。做全国或大区域的人口重心迁移分析,1km 绰绰有余,甚至 5km 都够用,因为你要的是宏观趋势。做流域尺度的人口暴露评估,1km 是主流选择,一条河谷里的村落分布能大致反映出来。但如果你的研究对象是城市核心区,1km 就明显吃力了——一个高密度城区的像元里可能塞着三五万人,整个小区、整条街道的内部差异全被抹平,任何精细到街区尺度的分析都会失真。
我一般的判断标准是:分析单元的特征尺度如果小于三倍像元尺寸,这个数据就不适合。也就是说,研究街区问题,1km 数据基本只能用来做背景参照,真要动手得换 100m 产品。但如果研究的是县域、市域、城市群、流域,1km 是性价比最高的档位——精度够用,计算量可控,二十多年序列跑下来也不至于让机器趴窝。
1.3 时间序列带来的额外价值与额外负担
2000 到 2023 年这个跨度,覆盖了快速城镇化的完整周期。单看某一年的栅格,你能知道人口分布在哪儿;把二十多年摞起来看,你才能算出哪些地方在快速填充、哪些地方在收缩、城镇边界以什么速度外扩、人口重心往哪个方向漂移。这类纵向指标在区域规划评估、基础设施投资时序安排、灾害风险动态评估里都是硬通货。
但序列数据也带来了单年份数据没有的麻烦。人口栅格产品的底层算法和输入协变量会随版本更新变化,同一套产品在不同年份之间可能存在系统性偏移。如果你直接把 2005 年和 2018 年的数据相减算增长率,得到的差值里可能混着一部分算法差异,而不是真实的人口变动。这个问题在后面第 2.3 节还会展开讲,这里先记住一个原则:跨年份比较前,必须先做一致性检验,不能默认序列是同质的。
2. 数据产品谱系与选型逻辑
2.1 三类技术路线的差异与适用边界
业内能拿到的高分辨率人口栅格产品,技术路线大致分三类,我把它们简称为产品甲、产品乙、产品丙,具体名字不重要,重要的是理解各自的建模逻辑,因为这直接决定了它们在什么场景下更可信。
产品甲的思路是“建成区反演加密度分配”,先用遥感影像识别出人类居住的建成区范围,再根据区域统计总量反推建成区内的平均密度,最后按像元分摊。它的优点是在城乡边界清晰的地方表现好,能较好地区分“住人的地方”和“不住人的地方”;缺点是在城乡结合部、城中村这类混合区域容易出问题,建成区识别一旦漏判,人口就直接归零。
产品乙走的是统计建模路线,用大量协变量(土地利用、灯光、路网、地形、气候)训练回归或机器学习模型,把行政单元的总量拆解到像元。它的优点是在数据稀疏地区也能给出连续估计,全球覆盖完整;缺点是模型外推的区域误差不可控,尤其是在训练样本稀少的地区,结果的可信度需要单独验证。
产品丙偏向人口普查微数据加抽样调查的空间化,精度在采样充分的地区表现最好,但覆盖完整性和时间连续性往往不如前两类。实际工作中,我通常的做法是:做趋势分析选一套产品跑通全程,保证内部一致性;做关键节点的精度校验时,再引入第二套产品做交叉比对,两套结果差异超过百分之三十的区域,就得逐个排查原因。
| 技术路线 | 核心输入 | 优势场景 | 典型短板 |
|---|---|---|---|
| 建成区反演加密度分配 | 遥感影像、区域统计总量 | 城乡边界清晰、建设用地集中的区域 | 混合用地、城中村易漏判 |
| 协变量统计建模 | 土地利用、灯光、路网、地形 | 大范围连续覆盖、数据稀疏区 | 外推区域误差不可控 |
| 普查微数据空间化 | 抽样调查、普查汇总 | 采样充分、精度要求高的区域 | 覆盖不全、年份不连续 |
2.2 全球、全国、分省、分市四级尺度该怎么选
这套数据提供了四个尺度的切片,很多人第一反应是“直接下最细的”,其实不对。选哪个尺度,取决于你的分析单元和最外边界。
做跨国比较、全球人口重心、洲际尺度的暴露度评估,当然是全球数据集,它的优势是投影和网格全球统一,不会出现跨国拼接错位。做全国层面的总量核算、区域差异分析、国土空间规划评估,用全国切片最省事,省掉了自己按国界裁剪的步骤,也避免了裁剪时边界像元归属的争议。分省和分市切片的真正价值不在于“更细”,而在于“免裁剪”——当你的研究范围刚好是一个省或一个市,直接用切片能省掉大量预处理时间,尤其是矢量边界不好找、坐标系不统一的时候。
但切片也有代价。一是边界版本问题,行政边界是会调整的,切片用的边界年份如果不明,你拿它和另一份边界数据叠加就会出现缝隙或重叠。二是边缘像元问题,按边界裁切时,跨越边界的像元要么被整块保留(外溢),要么被整块丢弃(缺失),两种处理都会在边界上产生系统偏差。三是拼接问题,如果你要研究跨省的城市群,把几个省的切片拼起来,接缝处的像元可能重复计算也可能漏算。我的经验是:只要研究范围跨了两个以上行政单元,就别用切片,老老实实下全国或全球数据自己裁,边界处理逻辑掌握在自己手里才踏实。
2.3 二十三年序列的连续性陷阱
前面提过,跨年份直接相减是有风险的。这里说具体点。人口栅格产品的版本迭代通常伴随三件事:输入影像源更新、协变量数据集换版、建模方法改进。任何一项变化都可能在时间序列上造成“台阶”——某一年前后同一地点的人口值突然整体抬高或压低,而实际人口并没有那么大变化。
识别这种断点,我常用两个办法。第一个是找几个已知稳定的区域做参照,比如人口长期变化很小的老城区或偏远农业县,把它们的年度总值画成折线,如果出现明显的跳跃点,基本可以判定是产品版本切换。第二个是看增长率的分布,真实的人口增长在空间上是渐变的,如果某一年的增长率图层出现大面积同号异常(比如整片区域同比暴涨),那多半是数据问题而不是现实。
确认存在断点后的处理方式有三种:一是分段建模,把序列按断点切成几段,段内做趋势分析,段间不做直接比较;二是做相对指标而非绝对指标,比如用某年占全国比重、占基年倍数这类归一化指标,能在一定程度上抵消系统性偏移;三是引入外部锚点做校正,用统计年鉴的总量对每年的栅格做整体缩放,把总量拉回一致口径。第三种方法工作量最大,但如果要做严谨的长时序研究,值得投入。
3. 拿到文件后的第一轮体检
3.1 元数据与投影核查必做的四件事
文件到手别急着算,先花十分钟做体检,能省掉后面几小时的返工。第一件事看坐标系。这类产品常见的有两种:地理坐标(经纬度,单位是度)和等积投影(单位是米)。前者好处是网格规则、便于全球拼接,坏处是像元面积随纬度变化;后者好处是每个像元面积相同、直接求和就是总量,坏处是不能跨区域直接拼。
第二件事看像元尺寸。地理坐标下常见 30 弧秒(约 0.008333 度),投影坐标下常见 1000 米。要确认它是不是名义上的“1km”——在高纬度地区,30 弧秒的东西向实际距离远小于 1 公里,如果你的研究区在北纬 50 度以上,必须按实际面积换算,否则人口总量会系统性高估。
第三件事看无效值标记。这类数据通常用 -99999 或 -3.4e38 标记无数据区(海洋、冰川、无人区),如果你不处理,求和时会得到一个巨大的负数。第四件事看数值类型,是浮点还是整型,是密度还是总量,这个下一节单独说。
import rioxarray as rxr pop = rxr.open_rasterio("pop_2020_1km.tif", masked=True).squeeze() print("坐标系:", pop.rio.crs) print("像元尺寸:", pop.rio.resolution()) print("无效值:", pop.rio.nodata) print("数值范围:", float(pop.min()), float(pop.max())) print("数据类型:", pop.dtype)跑完这几行,心里就有底了。如果resolution()返回的是 0.008333 这种小数,说明是地理坐标;如果是 1000 左右,说明是投影坐标。数值范围也要留意,最大值的量级能帮你判断单位——如果最大值是几十万,那基本是“人每平方公里”的密度;如果是几千,那可能是“每像元人数”。
3.2 数值语义核对:密度还是总量,这是生死问题
这是最容易出错、后果也最严重的一环。密度和总量在后续处理中的算法完全相反:密度做重采样要用双线性或立方卷积,总量必须用面积加权或求和;密度做区域汇总要先乘面积再求和,总量直接求和就行。搞错了,结果能差出几个数量级。
判断方法很直接:找一个你熟悉的城市核心区像元,看看数值。如果这个像元数值在两三万这个量级,那是密度(人/平方公里);如果在几百这个量级,那是每像元人数(因为 1 平方公里左右的像元,密度两万对应人数就是两万左右,但如果产品网格更细或更粗,数值会不同)。更稳妥的办法是取一个县的范围做汇总,把结果和统计公报对比,数量级对得上就是总量口径,差了几个数量级就是密度口径。
换算关系要记牢。从密度到总量:人数 = 密度 × 像元面积,像元面积按纬度算。从总量到密度:密度 = 人数 / 像元面积。像元面积的计算公式是:
import math def pixel_area_km2(lat_deg, dlon_deg=0.0083333, dlat_deg=0.0083333): lat_rad = math.radians(lat_deg) dx = dlon_deg * 111.320 * math.cos(lat_rad) # 东西向边长 km dy = dlat_deg * 110.574 # 南北向边长 km return dx * dy # 北纬 30 度处,30 弧秒像元的面积 print(round(pixel_area_km2(30), 4)) # 约 0.926 print(round(pixel_area_km2(50), 4)) # 约 0.617看出差别了吧,北纬 50 度的像元面积只有北纬 30 度的三分之二。如果你在全国尺度直接用固定面积换算,东北地区的总量会被高估三成左右。这个坑我在早期项目里踩过,改了两天才找到原因。
3.3 快速出图与异常识别
体检的最后一步是画图。别小看图,很多问题肉眼一看就露馅。我一般会出一张三联图:原始栅格全图、局部放大图、数值直方图。
全图看整体形态,正常的人口栅格应该呈现明显的“点轴集聚”——城市群是亮点,河流沿岸和海岸带是亮线,山区和荒漠是大片暗区。如果出现整片均匀的中等亮度,说明产品在该区域可能退化成了平均值填充,可信度要打问号。局部放大图用来检查城市边缘的过渡是否自然,正常应该是由高到低的渐变,如果出现生硬的方块状突变,可能是不同数据源拼接的痕迹。直方图看数值分布,健康的人口栅格通常高度右偏——绝大多数像元是低值,极少数像元是极高值,如果分布接近正态,反而不正常。
再补一个技巧:算一下研究区的总人口,和已知统计数对比。误差在正负百分之二十以内算正常,超过百分之五十就要查原因,常见的是无效值没处理、单位搞错、或者边界裁剪时把大片区域误删了。
4. 核心实操:裁剪、重采样与分区统计
4.1 按研究区裁剪的三种方式与取舍
裁剪看着简单,其实是误差引入的高发环节。方式一按矩形框裁(clip_box),最快,但会把框内的非研究区也带进来,后续统计必须再用掩膜剔除。方式二按矢量边界裁(clip),精确,但涉及边界像元归属问题。方式三是先用矩形粗裁再精裁,适合超大文件,能显著降低内存占用。
# 方式一:按经纬度范围粗裁,速度快,适合超大文件的第一轮筛选 clipped = pop.rio.clip_box(minx=116.0, miny=39.0, maxx=117.0, maxy=40.0) # 方式二:按矢量边界精裁,注意 all_touched 参数 import geopandas as gpd boundary = gpd.read_file("study_area.shp").to_crs(pop.rio.crs) clipped = pop.rio.clip( boundary.geometry, boundary.crs, drop=True, all_touched=False, # 只保留中心点落在边界内的像元 )all_touched这个参数值得单独说。设为False时,只有像元中心落在边界内才保留,结果是边界处偏保守,可能漏掉边缘人口;设为True时,只要像元和边界有接触就保留,结果是边界外溢,总量偏高。对于形状规整的研究区,两者差别不大;对于边界曲折、面积小的研究区(比如一个城区街道),差别可能超过百分之十。我的做法是:如果研究区面积小于一百个像元,用True并注明可能高估;面积大的时候用False,误差可以忽略。
还有个更精细的处理,适合对边界精度要求高的场景:不要简单裁切,而是用面积加权。具体做法是把研究区边界栅格化到高分辨率(比如 100 米),算出每个 1km 像元被研究区覆盖的比例,然后按比例分配人口。这样边界像元不会整块保留也不会整块丢弃,总量更准确。代价是要多做一步重采样和乘积运算,但值得。
4.2 重采样的方法选择与参数计算
把 1km 数据降到 100m 或者升到 5km,是常见需求。这里的选择逻辑非常明确,只有一条:看你处理的是密度还是总量。
处理密度时,重采样可以用双线性(bilinear)或三次卷积(cubic),它们会做插值平滑,保留空间梯度的连续性,适合做可视化或做梯度分析。处理总量时,绝对不能用插值,必须用面积加权分配或者聚合求和:降尺度时把像元值按面积比例拆到子像元,升尺度时把覆盖的像元值加起来。
from rasterio.enums import Resampling # 情形一:密度栅格降尺度做可视化,用双线性 density_500m = pop.rio.reproject( pop.rio.crs, resolution=0.0041667, # 15 弧秒,约 500 米 resampling=Resampling.bilinear, ) # 情形二:总量栅格降尺度,必须面积加权,不能插值 # 思路:把总量转成密度 -> 重采样 -> 再转回总量 area_src = 0.926 # 源像元面积 km2(按研究区纬度取平均) area_dst = 0.2315 # 目标像元面积 km2 density = pop / area_src density_fine = density.rio.reproject( pop.rio.crs, resolution=0.0041667, resampling=Resampling.bilinear ) total_fine = density_fine * area_dst这段代码里最关键的一句是“先转密度再转回总量”。很多人图省事直接对总量栅格做双线性,结果某个高值像元被平滑成四个中等值,虽然总和看起来差不多,但空间形态被改得面目全非,人口热点变得模糊,后续做热点识别就不准了。
升尺度的情况相反,从 1km 聚合到 10km,用Resampling.sum或者按块求和都行,但要注意无效值的处理——如果一块里有一个无效像元,求和操作可能返回无效,需要用sum的跳过无效值选项,或者先把无效值转成 0 再求和(前提是无效区确实无人居住,海洋和冰川符合这个条件)。
4.3 分区统计的标准流程与三个易错点
分区统计是把栅格人口落到行政单元、格网、缓冲区上的核心操作,也是最容易出错的地方。标准流程是四步:确认坐标系一致、确认单位语义、选择统计方式、处理边界像元。
from rasterstats import zonal_stats stats = zonal_stats( boundary, "pop_2020_1km.tif", stats=["sum", "mean", "count"], all_touched=True, nodata=-99999, affine=pop.rio.transform(), ) boundary["pop_total"] = [s["sum"] for s in stats]三个易错点,我逐个说。第一,坐标系必须完全一致。如果边界是投影坐标、栅格是地理坐标,rasterstats会静默给出错误结果,不报错但数值离谱。跑之前一定先to_crs。第二,单位语义要匹配。如果栅格是密度,sum得到的是“密度之和”,毫无意义,必须先乘像元面积转成总量再统计。第三,边界像元的选择要和你的研究目的匹配。做资源配给、做总量核算,倾向于用all_touched=True保证不漏人;做严格的面积比例分析,用面积加权更严谨。
还有一个细节:zonal_stats返回的count是有效像元数,不是像元总数。如果你要算区域平均密度,别用sum/count,应该用人口总量 / 区域实际面积,因为研究区面积和像元总面积往往不等。
5. 融合应用:把人口栅格变成可解释的指标
5.1 与土地利用、灯光、路网叠加的典型组合
单独的人口栅格只能回答“有多少人”,一旦叠加其他图层,能回答的问题就完全不一样了。我常用的组合有这么几组。
人口加土地利用,能算出各类用地上承载的人口,比如“工业用地内居住人口”“耕地上的常住人口”,这类指标在空间规划里用来识别用地混杂问题非常有效。人口加夜间灯光,能做人均灯光强度,间接反映经济活动强度和生活水平差异,虽然粗糙但空间连续性好,适合做区域对比。人口加路网,能算单位道路长度服务人口,用来评估交通压力和服务覆盖。
人口加灾害范围,这是我做得最多的一类。洪水淹没范围、地质灾害易发区、极端天气影响圈,叠加人口栅格就能算出受影响人口。这里有个关键细节:受影响程度不是简单的人数相加,要按影响强度分级。比如洪水按淹没深度分三档,每档用一个暴露系数(浅水 0.3、中水 0.6、深水 1.0),把人口乘以系数再求和,得到的“等效暴露人口”比原始总人数更有决策价值。
人口加服务设施,做可达性分析。以医院、学校、消防站为起点做缓冲区或成本距离,落到人口栅格上算覆盖人口比例。这类分析里,1km 数据的精度足够支撑市域尺度的设施布局评估,但如果要精细到社区尺度,就得换更细的数据配合路网做网络分析。
5.2 精度校验的方法与误差来源拆解
任何用这套数据得出的结论,在写进报告之前都该做一轮校验。校验的核心思路是:找一组独立的、可信的参照数据,对比栅格汇总值和参照值。
最容易拿到的参照就是统计年鉴里的人口数。做法是按行政单元做分区统计,然后把栅格汇总值和统计值做散点,看 R² 和平均绝对百分比误差。我实测下来的经验是:地级市尺度上,主流产品的 R² 通常在 0.9 以上,平均相对误差在百分之十到二十;到区县尺度,R² 会掉到 0.8 左右,误差涨到百分之二十到三十;到乡镇尺度,误差可能超过百分之四十,这时候数据只能做趋势参考,不能做绝对量核算。
误差不是随机分布的,它有明显的空间规律,这个必须搞清楚:
| 区域类型 | 典型相对误差 | 主要误差来源 |
|---|---|---|
| 城市核心高密度区 | 正负 10% 至 20% | 像元内垂直分布差异大,高层住宅被低估 |
| 城中村、老旧街区 | 正负 30% 至 50% | 建筑密度高但识别困难,容易漏判 |
| 一般农村居民点 | 正负 15% 至 25% | 宅基地分散,小村落容易被平滑掉 |
| 城乡结合部 | 正负 25% 至 40% | 用地类型混合,建成区边界模糊 |
| 荒漠、高山无人区 | 绝对误差极小 | 基数太小,相对误差反而失真 |
看这张表能得出一个反直觉的结论:误差最大的地方不是偏远地区,恰恰是人口最密集、最受关注的城市核心区和城中村。原因很简单,1km 像元在这些地方内部的异质性太强,一栋三十层住宅楼和旁边一片空地的平均值毫无物理意义。所以在城市研究中,如果条件允许,城市核心区部分应该替换成 100m 产品,或者用建筑体量数据做垂直分配修正。
还有一个常被忽略的误差来源:时间错配。统计年鉴的年份、栅格产品的年份、你研究的时间点,三者可能不完全一致。用 2020 年的栅格去校验 2019 年的统计数,本身就有误差,别把这个算到数据质量头上。
6. 常见问题与排查实录
表格里的问题基本都是我自己或身边同行真实遇到过的,按出现频率排序。
| 现象 | 可能原因 | 排查与解决 |
|---|---|---|
| 汇总人口为负数或极大值 | 无效值未处理 | 检查 nodata 标记,用 masked 读取或显式设 0 |
| 总量比统计数高一个数量级 | 把密度当总量求和 | 核对单位,密度需乘像元面积后求和 |
| 高纬度区域人口明显偏高 | 用了固定像元面积 | 按纬度计算实际面积,或改用等积投影 |
| 相邻年份数据出现整片跳变 | 产品版本切换 | 找出断点年份,分段处理或做归一化 |
| 边界处出现明显锯齿或断线 | 边界像元归属处理不当 | 统一 all_touched 策略,或改用面积加权 |
| 裁剪后文件仍然很大 | 只做了空间裁剪未做波段压缩 | 用 COG 格式加 DEFLATE 压缩重写 |
| 大城市中心区人口被严重低估 | 1km 像元抹平垂直差异 | 换 100m 产品,或用建筑数据做垂直分配 |
| 跨省拼接后接缝处有空白或重影 | 切片边界版本不一致 | 改用全国或全球数据自行裁剪 |
| 分区统计结果为 None | 坐标系不一致或几何无效 | 统一 CRS,用make_valid修复几何 |
| 相同代码换个区域结果全错 | 硬编码了像元面积常数 | 改为按纬度动态计算 |
挑两个展开说。第一个是“汇总人口为负数”。这个错误看着离谱,但新手极容易犯,因为很多软件在读取带 -99999 标记的栅格时,如果不用掩膜,会把它当真实值参与运算。一个县里只要有几百个海洋或冰川像元,求和结果就是负几十亿。解决办法就一句话:读取时永远带masked=True,或者手动把 nodata 设为 NaN。
第二个是“大城市中心区低估”。这个问题的根源不在数据,在尺度。一个 1km 像元里如果有一栋住三千人的高层和一片住两百人的老房子,产品的分配模型通常按建成区面积或建筑密度分摊,很容易给出一个“平均”的密度值,把高层的垂直人口压平了。业内的处理办法是用建筑轮廓数据做垂直分配,计算每栋建筑的楼层面积,按楼层面积比例重新分配像元总人口。这套流程工作量不小,但如果研究结论对城市核心区敏感,值得做。我在一个城市体检项目里做过对比,修正前后核心区人口相差近四成,直接影响了对公共服务缺口的判断。
再补一个存储上的经验。全球 1km 数据单一年份约 9.3 亿个像元,浮点存储约 3.7GB,二十三年摞起来接近 85GB。这个体量在本地硬盘上不算夸张,但读取效率会成问题。建议全部转成 COG 格式加 DEFLATE 压缩,压缩后通常能降到一半以下,而且支持按窗口读取,做局部裁剪时不用把整个文件载入内存。实测下来,一次只读一个省的窗口,内存占用能从几 GB 降到几十 MB,跑批量脚本的体验完全不一样。
7. 几个踩过坑之后才明白的道理
数据精度不是越高越好,是越匹配越好。我见过太多人执着于找最高分辨率的产品,结果拿到 100m 数据后计算量爆炸,跑一次分区统计要几小时,最后发现结论和 1km 数据得出的几乎一样,因为分析单元本来就是县级。先想清楚你的分析单元和目标精度,再倒推该用哪个尺度的数据,这个顺序不能反。
跨产品比较要格外小心。两套不同产品在同一地点的数值差异,可能来自算法、输入数据、基准年份任何一项,你不能简单地说“A 产品比 B 产品高估了”。如果非要做交叉验证,正确姿势是看空间格局的一致性而不是绝对值的差异——两套产品都识别出的高密度区在哪里,不一致的区域有什么共同特征,这比对比一个总数有意义得多。
最后说一个实用技巧。做长时序分析时,与其纠结逐年数据的绝对精度,不如把每年的人口栅格除以当年的全国总人口,得到一个人口占比栅格,再用这个占比序列做趋势分析。这个归一化操作能抵消掉大部分产品版本带来的系统性偏移,让趋势判断稳定得多。代价是你只能回答“某地在全国的重要性怎么变”,回答不了“某地到底住了多少人”。如果你的研究问题恰好是前者,这个方法能省掉大量校正工作。
人口栅格这类数据,本质上是模型输出,不是观测事实。它能告诉你分布的大致形态和相对差异,但不能替代实地调查和统计核算。把它当成一把好用的尺子,而不是一把绝对准确的秤,用起来心里就有数了。