一种拟合身高曲线的方法
最近渤海在吧里发了青岛的历年身高数据,我们也再次确认了之前的想法——中国存在本地青年男性身高达到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年北京市海淀区的学生体质调研中的男生数据,如果我们现在的任务是估计这批海淀学生的成年身高,要尽量准确,该怎么办?
| 性别 | 年龄 | 人数 | 平均身高/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 |
吧友们到现在总结出了下面几种办法:
- 只取17岁(至于为什么是17岁,我在前面的文章中解释过了)。
- 17~18岁求平均。这是渤海之前制作分省身高表格用的。
- 综合考虑15~18岁数据。如果18岁数据异常则直接舍去,如果15、16岁数据高于17岁,则一起并入求平均。这对女生数据尤其有用,因为在发达地区的15~16岁,女生增长就很少了。勾魂眼用这个方法比较多。
第1种方法是无偏的,也就是说如果样本量够大,这个方法得到的身高会最准确,但是由于它「利用」到的数据最少,波动也最大。第2种办法利用了2倍的数据,波动因为减少为之前的0.71倍,更加稳定,但是由于18岁数据的种种问题,不是无偏的。第3种方法利用的数据量最大,波动应该是最小的,但是引入了太多主观因素(怎么定义异常?),可能会有内生的偏差。
一种整体的思路
我对这个问题的解决方法是不再单独估计某个年龄段的身高(比如说17岁),而是将7~18岁的数据作为一个整体,去估计7~18岁的生长发育曲线。这样我能使用到所有已知的数据,而不仅仅是15、16岁之后的。也就是说,假设我在一张纸上画出了所有的数据点,我要用一条曲线把他们连起来。
看起来数据不是很好,7~13岁均匀生长,然后在14岁有个凸增,再放缓,看起来不对。我们熟知的男生生长曲线,是这样的。
放在一起是这样的。
看起来好了些,海淀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厘米。
这里舍弃了海淀18~19年龄段的数据,因为中国2005生长发育曲线只给到18.0岁的数据,再往后就没有了。