news 2026/9/28 20:19:52

香港资助房屋成交数据实测:文件叫 2024,里面的成交发生在 2026

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
香港资助房屋成交数据实测:文件叫 2024,里面的成交发生在 2026

目录

    • 一、七份文件,最大的比最小的大 25 倍
    • 二、文件名里的年份,不是数据里的年份
    • 三、字段会改名:Court → Court/Estate,还多了个 Wing
    • 四、楼层是字符串,单位号里还有字母
    • 五、把七份合在一起算均价,会算出一个不存在的数
    • 六、可以直接抄的做法
    • 参考链接

中国香港房委会把资助出售房屋的成交记录按「每期计划」发成一份文件,零鉴权,JSON 格式,中英文各一版。我把能抓到的七份全下载下来(共约 9.7MB、18,822 条成交),只想回答一个问题:这批数据的年份怎么对。结果是:

  • 没有一份文件的「文件名年份」等于它里面的成交年份——七份里有5 份完全不重合;代号 g24 的那份文件名写着 2024,里面的成交全部发生在 2025 和 2026;
  • 字段在改名:2018 年那份用Court,之后六份全改成Court/Estate,还多出一个Wing字段。11 个字段里只有 8 个是七份共有的;
  • 同一条记录里楼层是字符串、面积是浮点、价格是整数——楼层排序会得到1, 10, 11, 12, 13这种顺序,而单位号里还混着04A。

一、七份文件,最大的比最小的大 25 倍

先看清这批文件的规模:

代号计划成交条数
018居屋 20184,431
g20绿置居 20203,294
g22绿置居 20224,586
g23绿置居 20233,002
g24绿置居 20243,069
e222022(另一批)256
e232023(另一批)184

最后两份只有 184 和 256 条,跟前面的几千条不在一个量级,最大与最小相差 24.9 倍。这两份对应的是规模小得多的批次,把它们和主期计划当成同一个均匀的时间序列做年度趋势,等于让 184 条和 4,586 条拥有同样的话语权——趋势线的形状主要由样本量决定,而不是由市场决定。所以按「期」分析时,要么显式加权,要么把小批次单独标注出来,不要和主期混在一条线上。

二、文件名里的年份,不是数据里的年份

这是今天最值得记住的一条。每份文件里都有一个签约日期字段,我按它统计了实际年份:

# 文件名年份 vs 实际签约年份importjson,pathlib,collections RAW=pathlib.Path("原始返回/ssfs")SERIES={"018":2018,"g20":2020,"g22":2022,"g23":2023,"g24":2024,"e22":2022,"e23":2023}DATE="Date of Agreement for Sale and Purchase (ASP)"forcode,file_yearinSERIES.items():recs=json.loads((RAW/f"{code}_en_r0.json").read_bytes().decode("utf-8-sig"))["records"]years=collections.Counter(r[DATE].split("/")[-1]forrinrecs)hit=str(file_year)inyearsprint(code,file_year,dict(years.most_common()),"重合:",hit)# 018 2018 {'2019': 4431} 重合: False# g24 2024 {'2025': 2783, '2026': 286} 重合: False# e22 2022 {'2022': 151, '2023': 105} 重合: True

七份里五份完全不重合:2018 年那份的成交全部发生在2019(4,431 条),2024 年那份全部发生在2025(2,783)和 2026(286),2023 年那份全部发生在 2024。只有 e22、e23 两份有部分重合。

原因不复杂:文件名里的年份是「第几期计划」,成交签约发生在计划之后——先抽签选楼、再签买卖协议,跨年是常态。但如果你按文件名给数据打年份标签(这是最顺手的做法),整条时间轴会平移一到两年,跟任何其他年度数据(楼价指数、人口、利率)对不上,而且不会有任何报错:数字照样算得出来,图表照样画得出来,只是整体错了一格。

正确做法是只用日期字段派生年份,文件名只当版本号。

三、字段会改名:Court → Court/Estate,还多了个 Wing

把七份文件的字段取并集和交集,会看到漂移:

keysets={}forcodeinSERIES:recs=json.loads((RAW/f"{code}_en_r0.json").read_bytes().decode("utf-8-sig"))["records"]keysets[code]=set().union(*[set(r)forrinrecs])union=set().union(*keysets.values())inter=set.intersection(*keysets.values())print(len(union),len(inter),sorted(union-inter))forkinsorted(union-inter):print(k,"有于",[cforcinSERIESifkinkeysets[c]],"缺于",[cforcinSERIESifknotinkeysets[c]])# 11 8 ['Court', 'Court/Estate', 'Wing']# Court 有于 ['018'] 缺于 ['g20', 'g22', 'g23', 'g24', 'e22', 'e23']# Court/Estate 有于 ['g20', ...] 缺于 ['018']# Wing 有于 ['g20', ...] 缺于 ['018']

2018 年那份里,屋苑字段叫Court;从 2020 年起改叫Court/Estate,同时新增了Wing(翼)字段。所以:

  • 按Court/Estate取数,2018 年那份会取到 4,431 个空值——不报错,只是那一整年的屋苑全是空;
  • 按Court取数,另外六份全空。

这类漂移没有任何提示。处理办法是建一张别名表(Court→Court/Estate),并在读取时断言关键字段的空值率——空值率突然 100% 就是改名了。

四、楼层是字符串,单位号里还有字母

同一条记录里,字段类型并不统一:

recs=json.loads((RAW/"g24_en_r0.json").read_bytes().decode("utf-8-sig"))["records"]types={k:type(v).__name__fork,vinrecs[0].items()}print(types)# Scheme Type: str Court/Estate: str Block: str Wing: str# Floor: str Unit: str# Saleable Area of Flats (sq. m.): float Transaction Price: intfloors=sorted({r["Floor"]forrinrecs})print(floors[:5])# ['1', '10', '11', '12', '13'] ← 字典序,不是楼层顺序units=[r["Unit"]forrinrecs]print(sum(1foruinunitsifu.isdigit()),"/",len(units))# 3065 / 3069 ← 有 4 条不是纯数字(比如 '04A')

两个后果:

  1. 楼层是字符串,直接排序得到1, 10, 11, 12, 13…——想找「最高几层」或者按楼层分组,必须转成整数再排;
  2. 单位号里混着04A这种值,3,069 条里 4 条不是纯数字。所以「单位号是数字」这个假设不成立,int()会在这 4 条上抛异常——正好少到不容易被发现。

价格和面积反而是干净的:面积是浮点(35.4),价格是整数(715500)。所以不要因为「看起来都是数字」就统一处理。

五、把七份合在一起算均价,会算出一个不存在的数

最后看一眼口径:018(居屋 2018)均价267.6 万,绿置居各期在119.2 万到 224.2 万之间,七份合并后是210.7 万。

这个 210.7 万没有意义——它是两种不同性质的计划(居屋和绿置居的定价机制、单位面积都不同)加权出来的。均面积也一样,从 20.3 平方米到 38.6 平方米。合并统计之前,先确认「合并」这个动作在业务上是否成立。

好消息是中文版和英文版完全对齐:抽查两份,条数 4,431/4,431、3,069/3,069,逐条价格全部一致。所以跨语言对齐这一关,这份数据是过了的。

六、可以直接抄的做法

importjsonimportpathlib ALIASES={"Court":"Court/Estate"}# 旧名 → 新名INT_FIELDS=("Floor",)# 需要转整数的数字型字符串DATE_FIELD="Date of Agreement for Sale and Purchase (ASP)"defload_series(raw:pathlib.Path,code:str)->list:"""读一期刊的成交:别名归一 + 年份派生 + 类型修正。"""recs=json.loads((raw/f"{code}_en_r0.json").read_bytes().decode("utf-8-sig"))["records"]out=[]forrinrecs:rec={ALIASES.get(k,k):vfork,vinr.items()}d,m,y=rec[DATE_FIELD].split("/")# 明确按 D/M/YYYY 解析rec["date"]=f"{y}-{m}-{d}"rec["year"]=int(y)# 年份只从日期派生forfinINT_FIELDS:s=str(rec.get(f,"")).strip()rec[f"{f}_int"]=int(s)ifs.isdigit()elseNoneout.append(rec)# 关键字段全空 = 疑似改名,别让它静默通过missing=sum(1forxinoutifnotx.get("Court/Estate"))assertmissing<len(out),f"{code}: 屋苑字段全空,检查是否改名"returnout

四个要点收尾:年份只从日期字段派生,文件名当版本号,别让「文件名看起来像年份」骗过去;字段改名要靠空值率发现,建一张别名表兜底,并对关键字段断言「不能全空」;类型不要靠猜,数字型字符串显式转换,遇到非数字值留None而不是硬转;合并之前先问一句「合并在业务上成立吗」,不同定价机制的计划不能加权平均,样本量差 25 倍的批次也不能等权处理。

今天 11 次请求(七份英文 + 两份中文 + 两份第二轮快照)全部真实抓取,原始文件已落盘,脚本可以整篇复跑。

参考链接

  1. https://data.housingauthority.gov.hk/dataset/ssfs/ssfs-sale-transactions-g24_en.json
  2. https://data.gov.hk/en-data/api/3/action/package_show?id=hk-housing-gsh2024-ssfs-sale-transactions-g24
  3. https://data.housingauthority.gov.hk/

原创声明:本文所有数据于 2026 年 9 月 27 日实测抓取自中国香港房屋委员会公开数据集与 data.gov.hk,抓取与校验脚本随文附上,欢迎复现。

文中「文件名年份 ≠ 成交年份」是这一系列文件的实际形态描述,不构成对发布方的评价;做年度对比时请以记录内的签约日期为准。

如果这篇帮你避开了一次「整条时间轴平移一年」的返工,点个收藏,下一篇继续拆系列型数据的坑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 20:18:42

手机屏用MIPI、车载屏用LVDS?接口差异与调屏实战全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 20:18:28

论文改到最后,先别急着降重

论文写到最后&#xff0c;很多人会把注意力集中在一个数字上&#xff1a;重复率是多少&#xff0c;AIGC检测结果如何。但真正影响论文质量的&#xff0c;往往不是“改得像不像人”&#xff0c;而是论证是否清楚、表达是否准确、引用是否规范。一次完整的修改复盘让我意识到&…

作者头像 李华
网站建设 2026/9/28 20:18:01

游戏服务端架构拆解:登录、游戏、跨服是怎么各司其职的

游戏服务端架构拆解&#xff1a;登录、游戏、跨服是怎么各司其职的引言 很多游戏服务端部署时&#xff0c;会看到一大排可执行文件或脚本&#xff1a;xxx-login、xxx-game、xxx-cross……新手往往一脸懵&#xff1a;不就是一个服务端吗&#xff0c;为什么要拆这么多进程&#x…

作者头像 李华
网站建设 2026/9/28 20:17:52

风机叶片表面损伤检测数据集 | 风机叶片 表面损伤 污渍检测 无人机巡检 风电运维9119期

风机叶片表面损伤检测数据集 | 风机叶片 表面损伤 污渍检测 无人机巡检 风电运维9119期 数据集概述 本数据集专注于风机叶片表面损伤与污渍的视觉检测&#xff0c;服务于风电运维、无人机巡检及能源设施管理。数据源涵盖损伤与污渍两类目标&#xff0c;适配叶片缺陷识别、维护…

作者头像 李华
网站建设 2026/9/28 20:16:10

PNG图片压缩原理:无损压缩、色彩量化与优化工具

PNG图片可以压缩&#xff0c;但它的压缩方式与JPEG不同。PNG采用无损压缩&#xff0c;因此可以在不丢失任何像素信息的前提下减小文件体积。不过&#xff0c;这种无损特性也决定了它的压缩幅度有限&#xff1a;当图像已经过初步优化后&#xff0c;继续使用无损手段通常只能再减…

作者头像 李华