一种拟合身高曲线的方法

最近渤海在吧里发了青岛的历年身高数据,我们也再次确认了之前的想法——中国存在本地青年男性身高达到177,女性达到164厘米的城市。这里排除了大连,是因为尽管大连很早就出现了超过177/164厘米的调查,但是同期也存在与之相反的数据。

中国内部发展程度的差距很大。要揭示身高极限,全国数据不如分省数据,而分省数据不如单城市的城区数据。然而单城市的样本量较少,按照学生体质健康调研的要求,城市城区单性别,每个年龄段只需要50人作为样本。某些省市会按照200%准备,也就是100人样本。样本量并不算大,随机误差也不小。一个简单的例子:假设标准差为6厘米,样本量100人,平均身高为175.5厘米,那么我们对真实身高的估计是以95%的概率,真实身高落在[174.3, 176.7]的范围内,以99.7%的概率落在[173.7, 177.3]范围内。这就是这个数据能告诉我们的所有信息,真实的身高可能是176.4,也可能是174.5,不能再知道更多了。

下面是2010年北京市海淀区的学生体质调研中的男生数据,如果我们现在的任务是估计这批海淀学生的成年身高,要尽量准确,该怎么办?

2010年北京市海淀区学生体质与健康调研身高
性别 年龄 人数 平均身高/cm 标准差/cm
7~ 69 130.07 4.86
8~ 99 134.42 5.65
9~ 87 140.26 5.20
10~ 82 146.37 6.00
11~ 88 152.46 8.29
12~ 77 160.21 9.04
13~ 91 165.35 8.74
14~ 87 173.39 5.53
15~ 93 174.32 5.94
16~ 82 175.19 6.96
17~ 87 175.92 6.09
18 62 175.78 5.55
7~ 88 128.30 4.74
8~ 93 132.82 5.61
9~ 94 139.41 5.85
10~ 81 145.10 6.43
11~ 74 152.46 5.81
12~ 69 157.75 6.20
13~ 78 161.19 5.51
14~ 74 162.48 6.09
15~ 76 162.70 5.85
16~ 86 162.71 5.03
17~ 93 161.57 5.04
18 59 163.22 5.96

吧友们到现在总结出了下面几种办法:

  1. 只取17岁(至于为什么是17岁,我在前面的文章中解释过了)。
  2. 17~18岁求平均。这是渤海之前制作分省身高表格用的。
  3. 综合考虑15~18岁数据。如果18岁数据异常则直接舍去,如果15、16岁数据高于17岁,则一起并入求平均。这对女生数据尤其有用,因为在发达地区的15~16岁,女生增长就很少了。勾魂眼用这个方法比较多。

第1种方法是无偏的,也就是说如果样本量够大,这个方法得到的身高会最准确,但是由于它「利用」到的数据最少,波动也最大。第2种办法利用了2倍的数据,波动因为减少为之前的0.71倍,更加稳定,但是由于18岁数据的种种问题,不是无偏的。第3种方法利用的数据量最大,波动应该是最小的,但是引入了太多主观因素(怎么定义异常?),可能会有内生的偏差。

一种整体的思路

我对这个问题的解决方法是不再单独估计某个年龄段的身高(比如说17岁),而是将7~18岁的数据作为一个整体,去估计7~18岁的生长发育曲线。这样我能使用到所有已知的数据,而不仅仅是15、16岁之后的。也就是说,假设我在一张纸上画出了所有的数据点,我要用一条曲线把他们连起来。

北京市海淀区2010年7~18岁男生平均身高、95%置信区间
北京市海淀区2010年7~18岁男生平均身高、95%置信区间

看起来数据不是很好,7~13岁均匀生长,然后在14岁有个凸增,再放缓,看起来不对。我们熟知的男生生长曲线,是这样的。

中国2005年标准生长发育表男生中位数,4~18岁
中国2005年标准生长发育表男生中位数,4~18岁

放在一起是这样的。

北京海淀2010和中国2005对比
北京海淀2010和中国2005对比

看起来好了些,海淀2010比中国2005整体更高,这是自然的,左右方向可能也需要调整。如果适度地将蓝线平移,似乎就能得到比较好地结果。仅仅平移可能不够,毕竟如果整体身高更高,生长期增长的量也会更高,这时候就需要将曲线在上下方向上进行拉伸。对于生长发育周期更长的人群,我们也可能需要在左右方向进行拉伸。

这就是我的思路,将标准的生长发育图进行适当的平移、放缩,使之与身高数据尽可能接近,这时候我们就得到了拟合的生长曲线。

怎么衡量接近的程度

假设$f$是一个生长发育曲线,如果年龄是$a$,给出$a$岁时对应的中位或者平均身高为$f(a)$。假设我们的一共有$N$组身高数据,其中第$i$组,对应的年龄是$a_i$,平均身高是$h_i$,样本量是$N_i$,标准差是$\sigma_i$,$i=1,2,\ldots,n$。那么我们可以定义偏差度

\[R(f) = \sum_{i=1}^n \frac{N_i(f(a_i) - h_i)^2}{\sigma_i^2}\]

这是偏差度是在某种模型下似然度的负对数,在此就不详细多说了。我们在极小化这个偏差度$R$时,也在最大化某个模型的似然度。

怎么平移、放缩生长发育曲线

假设$f_0$是标准的生长发育曲线(比如中国2005),那么我们可以用下面的公式定义一族$f_0^{k_x, b_x, k_y, b_y}$:

\[f_0^{k_x, b_x, k_y, b_y}(x) = k_y f_0 (k_x x + b_x) + b_y\]

也就是说,给定生长发育曲线,我们的模型共有四个参数。我们改变这四个参数的值,使得$R$最小。

代码实现

根据上面的思路,我用Python实现了上述的拟合算法,并把代码放到了Github仓库shengzhang-quxian-nihe里。有一定计算机基础的话,在安装Python和相应包之后,就可以运行并且自己试验了。

海淀生长发育曲线

这就是运行代码得到的最佳拟合。如果相信这个拟合曲线的话,对应的18.0岁身高是176.1厘米。

北京海淀2010测量数据与拟合曲线
北京海淀2010测量数据与拟合曲线

这里舍弃了海淀18~19年龄段的数据,因为中国2005生长发育曲线只给到18.0岁的数据,再往后就没有了。

知识共享许可协议
本作品采用
知识共享署名 3.0 中国大陆许可协议
 进行许可。