目录
- 一、四个口径,四个数
- 二、先看恒等式:产生量 = 弃置量 + 回收量
- 三、分母放谁:18.1 个百分点,和一个 108.3%
- 四、人均弃置率反推人口:口径的另一个入口
- 五、URL 里嵌着年份,明年这份链接就没了
- 六、可直接抄的做法
- 参考链接
今天是中秋正日,节后照例有一轮「月饼盒、包装、利是封到底回收了多少」的讨论。这类问题看着简单,落到数据上全是坑。我把中国香港环境保护署的废物统计五份 CSV 全抓了下来(零鉴权,任何人都能复现),只做一件事:算回收率。三个数字先摆出来:
- 2024 年的回收率,34.4% 和 52.5% 都算得出,差18.1 个百分点,区别在于分母放「产生量」还是「弃置量」;
- 用错分母的那条线,2010 年算出过108.3%——回收率超过 100%,这个数本身就是报错;
- 五份文件里「废物量」有四个口径:总弃置5,723,100、都市固体废物弃置3,846,800、产生5,864,700、回收2,017,900(公吨/年),总弃置比都市固体废物弃置高出 48.8%。
一、四个口径,四个数
五份文件的表头几乎一样(year, waste_cat_en, 数量),文件名却各不相同,量的是四件事:
| 口径 | 2024 年数值 | 说明 |
|---|---|---|
| 总弃置量 | 5,723,100 | 都市固体废物 + 建筑废物 + 特殊废物 |
| 都市固体废物弃置量 | 3,846,800 | 只占上一行的 67% |
| 都市固体废物产生量 | 5,864,700 | 还没减掉回收掉的部分 |
| 都市固体废物回收量 | 2,017,900 |
踩过一次就知道:「香港一年产生多少废物」这句话,四个数都能答,而且都对。总弃置量那 5,723,100 吨拆开是:都市固体废物 3,846,800、建筑废物 1,718,200、特殊废物 158,200——工地拆下来的混凝土占掉三成,跟生活垃圾完全不是一回事。拿总数去算人均生活垃圾,会比真实值高 48.8%。
二、先看恒等式:产生量 = 弃置量 + 回收量
在动手算比率之前,我习惯先找一条能自证的等式。这套数据里有一条:
# 产生量 与 弃置量+回收量 的残差,逐年核对importcsv,io,pathlib RAW=pathlib.Path("原始返回/epd")defrows(name):text=(RAW/f"{name}_en_r0.csv").read_bytes().decode("utf-8-sig")return[rforrincsv.reader(io.StringIO(text))ifrandr[0].strip()]gen={r[0]:int(r[2])forrinrows("generation")[1:]}rec={r[0]:int(r[2])forrinrows("recovery")[1:]}msw={r[0]:int(r[2])forrinrows("bycat")[1:]ifr[1]=="Municipal solid waste"}resid={y:gen[y]-msw[y]-rec[y]foryinsorted(gen)}zero=sum(1forvinresid.values()ifv==0)print(len(resid),zero,{y:vfory,vinresid.items()ifv!=0})跑出来是16 14 {'2013': -100, '2016': 100}:16 个年份里14 年残差正好为 0,只有 2013 和 2016 年差了 ±100 公吨——100 吨是这份数据的舍入粒度(所有数字都取整到百吨),所以这不是数据错,是四舍五入留下的指纹。
这条等式的价值在于:它说明产生量、弃置量、回收量三个数来自同一套统计口径,可以互相校验。拿到一批新数据时,先找这种恒等式跑一遍,比读完文档再下手靠谱得多——文档不会告诉你哪两个数该对得上。
三、分母放谁:18.1 个百分点,和一个 108.3%
回收率的分子没争议(回收量 2,017,900),分母有两个候选:
# 同一个分子,两个分母foryinsorted(gen):over_gen=round(rec[y]/gen[y]*100,1)over_disp=round(rec[y]/msw[y]*100,1)flag=" ← 超过 100%,分母错了"ifover_disp>100else""print(y,over_gen,over_disp,round(over_disp-over_gen,1),flag)# 2024 34.4 52.5 18.1# 2010 52.0 108.3 56.3 ← 超过 100%,分母错了回收量 ÷ 产生量 = 34.4%(废物流进处理链条之前就被分走了多少),回收量 ÷ 弃置量 = 52.5%(回收的和扔掉的之比)。两个数都在说「回收率」,差18.1 个百分点。
第二个分母有个致命的破绽:2010 年它算出 108.3%。回收率不可能超过 100%,所以只要你算出来的比率越界,就一定是分母选错了(或者分子分母不同源)。这是个不用读文档就能发现的信号——我建议把assert 0 <= rate <= 100直接写进脚本。
为什么早期年份会越界?看数据就明白:2010 年的产生量是 6,930,100 吨,回收量 3,603,400 吨,而弃置量只有 3,326,700 吨——那几年回收的量大到接近弃置量,说明「回收」的统计口径(含出口转运)与后面年份并不完全一致。跨年份比比率之前,先确认口径有没有换过。
四、人均弃置率反推人口:口径的另一个入口
第五份文件给的是人均弃置率(公斤/人/日),2024 年都市固体废物是1.4、家居废物是0.86。把总量和人均率放在一起,可以反推出它用的是多少人口:
rate={}forrinrows("rate")[1:]:rate.setdefault(r[0],{})[r[1]]=float(r[2])foryinsorted(msw):pop=msw[y]*1000/365/rate[y]["Municipal solid waste"]/1e6print(y,round(pop,3))# 2009 6.948 ... 2020 7.527 ... 2024 7.528反推出来的序列从 2009 年的 694.8 万一路走到 2024 年的 752.8 万,2021 年有一个回落(742.3 万)——与这几年的人口走势吻合。所以这份数据用的是年中人口口径,而不是年末人口。
这个方法反过来也很好用:当你手上有两个聚合指标,又不确定它们是否同源时,反推出隐含的第三个量,看它是否与已知事实对得上。要留意精度——人均率只保留两位小数(1.4),末位抖动 ±0.005 就是±0.4%,换算到人口是±3 万,做年度对比时这点误差无所谓,做月度对比就完全不够用。
五、URL 里嵌着年份,明年这份链接就没了
最后一个坑不在数据里,在下载地址上。这五份文件的 URL 长这样:
.../solid-waste-generation-quantity-en-2024.csv年份直接写在文件名里。我把 2018 到 2026 都试了一遍:9 个年份里只有 5 个还活着(2020–2024 返回 200,2018/2019 已被清理,2025/2026 还没生成)。
更隐蔽的是,同一个模式下的旧年份文件不是同一个数据:2020 版只有 2009–2020 共 12 行(465 字节),2024 版有 16 行(611 字节)——文件每年长高一点,旧文件是当年的快照,不是全集的子集。所以硬编码 URL 有两个后果:明年文件名从 2024 变 2025,你的脚本直接 404;就算某个旧链接还活着,拿到的也不是最新全集,而且你不会收到任何警告——它照样返回 200。
正确做法是从数据集描述页取资源地址(data.gov.hk 的package_show能拿到当前资源的真实 URL),或者按年份构造时先探测再回退,别把年份写死。
六、可直接抄的做法
- 先找恒等式再算比率。找到「A = B + C」这类能自证的关系,跑一遍残差,舍入粒度内的差异可以放过,超出就别往下算。
- 比率必须写边界断言。
0 <= rate <= 100一行代码,能挡住 108.3% 这种错。 - 分母写进变量名。别叫
rate,叫recovery_over_generation,半年后回来看代码你不会搞混。 - 人均类指标反推隐含量,验证口径;同时记下它的有效位数,别用它做超出精度的对比。
- 下载地址不要硬编码带年份的文件名,从资源清单取,或者探测+回退。
今天 21 次请求(五份主数据各两轮 + 三语对照 + 九个年份探测)全部真实抓取,原始文件已落盘,脚本可以整篇复跑。
参考链接
- https://www.epd.gov.hk/epd/sites/default/files/epd/english/environmentinhk/waste/data/files/solid-waste-generation-quantity-en-2024.csv
- https://data.gov.hk/en-data/api/3/action/package_show?id=hk-epd-statteam-solid-waste-recovery-quantity
- https://www.epd.gov.hk/epd/english/environmentinhk/waste/waste_maincontent.html
原创声明:本文所有数据于 2026 年 9 月 25 日实测抓取自中国香港环境保护署公开统计文件与 data.gov.hk,抓取与校验脚本随文附上,欢迎复现。
如果这篇帮你挡住了一次「回收率算成 108%」的事故,点个收藏,下一篇继续拆比率类指标的坑。