示例:人口趋势

现在我们已经准备好处理大型数据表格了。下面的文件包含 “美国按年龄和性别单年计算的常住人口年度估计”。注意 read_table 可以直接从 URL 读取数据。

[In ]:
from datascience import *
import numpy as np
path_data = '../../../assets/data/'
np.set_printoptions(threshold=50)
[In ]:
# As of August 2021, this census file is online here: 
data = 'http://www2.census.gov/programs-surveys/popest/technical-documentation/file-layouts/2010-2019/nc-est2019-agesex-res.csv'

# A local copy can be accessed here in case census.gov moves the file:
# data = path_data + 'nc-est2019-agesex-res.csv'

full_census_table = Table.read_table(data)
full_census_table
SEX  | AGE  | CENSUS2010POP | ESTIMATESBASE2010 | POPESTIMATE2010 | POPESTIMATE2011 | POPESTIMATE2012 | POPESTIMATE2013 | POPESTIMATE2014 | POPESTIMATE2015 | POPESTIMATE2016 | POPESTIMATE2017 | POPESTIMATE2018 | POPESTIMATE2019
0    | 0    | 3944153       | 3944160           | 3951430         | 3963092         | 3926570         | 3931258         | 3954787         | 3983981         | 3954773         | 3893990         | 3815343         | 3783052
0    | 1    | 3978070       | 3978090           | 3957730         | 3966225         | 3977549         | 3942698         | 3948891         | 3973133         | 4002903         | 3972711         | 3908830         | 3829599
0    | 2    | 4096929       | 4096939           | 4090621         | 3970654         | 3978925         | 3991740         | 3958711         | 3966321         | 3991349         | 4020045         | 3987032         | 3922044
0    | 3    | 4119040       | 4119051           | 4111688         | 4101644         | 3981531         | 3991017         | 4005928         | 3974351         | 3982984         | 4006946         | 4033038         | 3998665
0    | 4    | 4063170       | 4063186           | 4077346         | 4121488         | 4111490         | 3992502         | 4004032         | 4020292         | 3989750         | 3997280         | 4018719         | 4043323
0    | 5    | 4056858       | 4056872           | 4064521         | 4087054         | 4131049         | 4121876         | 4004576         | 4017589         | 4035033         | 4003452         | 4008443         | 4028281
0    | 6    | 4066381       | 4066412           | 4072904         | 4074531         | 4096631         | 4141126         | 4133372         | 4017388         | 4031568         | 4048018         | 4014057         | 4017227
0    | 7    | 4030579       | 4030594           | 4042990         | 4082821         | 4084175         | 4106756         | 4152666         | 4145872         | 4030888         | 4044139         | 4058370         | 4022319
0    | 8    | 4046486       | 4046497           | 4025501         | 4052773         | 4092559         | 4094513         | 4118349         | 4165033         | 4158848         | 4042924         | 4054236         | 4066194
0    | 9    | 4148353       | 4148369           | 4125312         | 4035319         | 4062726         | 4103052         | 4106068         | 4130887         | 4177895         | 4170813         | 4053179         | 4061874
... (296 rows omitted)

表格只显示了前 10 行。稍后我们将看到如何显示整个表格;不过,对于大型表格来说,这通常没什么用。

该表格的描述在线可查。

SEX 列包含数字代码:0 表示总计,1 表示男性,2 表示女性。这种二元分类背后的假设是有争议的。我们将在下一节讨论。

在本节中,我们将关注年龄和人口规模。

AGE 列包含以完成年数计算的年龄,但特殊值 999 是总人口的总和。“年龄” 100 也有特殊状态。在该类别中,人口普查局包括了所有 100 岁及以上的人。

其他列包含 2010 年至 2019 年每个性别和年龄类别中美国人口的估计值。人口普查是每十年进行一次:最近一次人口普查在 2020 年进行,前一次在 2010 年。人口普查局还每年估计人口变化。正如该局在其方法描述中所解释的,它 “将[估计的变化]加到上一次十年一次的人口普查中,以每年更新人口估计。”

通常,公开可用的表格包含的信息会超出特定调查或分析所需。为了将大型表格变成更可用的形式,我们必须进行一些数据清洗

假设我们只对 2014 年到 2019 年的人口变化感兴趣。让我们 select 相关的列。

[In ]:
partial_census_table = full_census_table.select('SEX', 'AGE', 'POPESTIMATE2014', 'POPESTIMATE2019')
partial_census_table
SEX  | AGE  | POPESTIMATE2014 | POPESTIMATE2019
0    | 0    | 3954787         | 3783052
0    | 1    | 3948891         | 3829599
0    | 2    | 3958711         | 3922044
0    | 3    | 4005928         | 3998665
0    | 4    | 4004032         | 4043323
0    | 5    | 4004576         | 4028281
0    | 6    | 4133372         | 4017227
0    | 7    | 4152666         | 4022319
0    | 8    | 4118349         | 4066194
0    | 9    | 4106068         | 4061874
... (296 rows omitted)

我们可以简化所选列的标签。

[In ]:
us_pop = partial_census_table.relabeled('POPESTIMATE2014', '2014').relabeled('POPESTIMATE2019', '2019')
us_pop
SEX  | AGE  | 2014    | 2019
0    | 0    | 3954787 | 3783052
0    | 1    | 3948891 | 3829599
0    | 2    | 3958711 | 3922044
0    | 3    | 4005928 | 3998665
0    | 4    | 4004032 | 4043323
0    | 5    | 4004576 | 4028281
0    | 6    | 4133372 | 4017227
0    | 7    | 4152666 | 4022319
0    | 8    | 4118349 | 4066194
0    | 9    | 4106068 | 4061874
... (296 rows omitted)

97-100 岁

作为热身,让我们检查总人口,由 SEX 代码 0 标记。由于所有这些行在 SEX 列中都具有相同的值 0,我们将删除该列。

[In ]:
us_pop_by_age = us_pop.where('SEX', are.equal_to(0)).drop('SEX')
us_pop_by_age
AGE  | 2014    | 2019
0    | 3954787 | 3783052
1    | 3948891 | 3829599
2    | 3958711 | 3922044
3    | 4005928 | 3998665
4    | 4004032 | 4043323
5    | 4004576 | 4028281
6    | 4133372 | 4017227
7    | 4152666 | 4022319
8    | 4118349 | 4066194
9    | 4106068 | 4061874
... (92 rows omitted)

现在让我们看看最高年龄段的人口。

[In ]:
us_pop_by_age.where('AGE', are.between(97, 101))
AGE  | 2014  | 2019
97   | 82948 | 116969
98   | 59546 | 86150
99   | 41277 | 57124
100  | 70685 | 100322

不出所料,年龄越大,人数越少。例如,99 岁的人比 98 岁的人少。

AGE 为 100 的人数比 99 岁的人数要多得多。这是因为 AGE 为 100 的行不仅代表 100 岁的人。它还包括那些超过 100 岁的人。

百分比变化

表格 us_pop_by_age 的每一列都是相同长度的数组,因此列之间可以通过算术运算组合。下面的数组包含 2014 年至 2019 年的人口变化。每个条目对应 us_pop_by_age 的一行。

[In ]:
change = us_pop_by_age.column('2019') - us_pop_by_age.column('2014')
change
array([-171735, -119292,  -36667, ...,   15847,   29637, 9938515])

我们可以为 us_pop_by_age 增加一个列,包含这些变化,既包括绝对值,也包括相对于 2014 年值的百分比。

[In ]:
us_pop_change = us_pop_by_age.with_columns(
    'Change', change,
    'Percent Change', change/us_pop_by_age.column('2014')
)
us_pop_change.set_format('Percent Change', PercentFormatter)
AGE  | 2014    | 2019    | Change  | Percent Change
0    | 3954787 | 3783052 | -171735 | -4.34%
1    | 3948891 | 3829599 | -119292 | -3.02%
2    | 3958711 | 3922044 | -36667  | -0.93%
3    | 4005928 | 3998665 | -7263   | -0.18%
4    | 4004032 | 4043323 | 39291   | 0.98%
5    | 4004576 | 4028281 | 23705   | 0.59%
6    | 4133372 | 4017227 | -116145 | -2.81%
7    | 4152666 | 4022319 | -130347 | -3.14%
8    | 4118349 | 4066194 | -52155  | -1.27%
9    | 4106068 | 4061874 | -44194  | -1.08%
... (92 rows omitted)

Percent Change 列中显示的几乎所有条目都是负数,表明最年轻年龄段的人口下降。然而,总人口增长了约 990 万人,百分比变化略高于 3%。

[In ]:
us_pop_change.where('AGE', are.equal_to(999))
AGE  | 2014      | 2019      | Change  | Percent Change
999  | 318301008 | 328239523 | 9938515 | 3.12%

让我们将其与每个年龄的变化进行比较。为了方便解读,我们将按 Change 列中包含的人口绝对变化值的降序对表格进行排序。

[In ]:
us_pop_change.where(
    'AGE', are.below(999)
).sort('Change', descending=True)
AGE  | 2014    | 2019    | Change | Percent Change
72   | 2191642 | 3191048 | 999406 | 45.60%
68   | 2567511 | 3345475 | 777964 | 30.30%
69   | 2530460 | 3252423 | 721963 | 28.53%
70   | 2461426 | 3136704 | 675278 | 27.43%
71   | 2516392 | 3083083 | 566691 | 22.52%
76   | 1692960 | 2222392 | 529432 | 31.27%
62   | 3677408 | 4156645 | 479237 | 13.03%
28   | 4345247 | 4818725 | 473478 | 10.90%
64   | 3481789 | 3950578 | 468789 | 13.46%
38   | 3848856 | 4305576 | 456720 | 11.87%
... (91 rows omitted)

看看最前面的几行。虽然总人口的百分比变化约为 3%,但对于 60 多岁末和 70 岁出头的人来说,这一比例跃升至 20% 以上。这一惊人的变化促成了所谓的美国老龄化。

什么可以解释这种大幅增长?我们可以通过检查相关群体出生的年份来探索这个问题。

  • 2014 年年龄在 69 至 72 岁之间的人出生于 1942 年至 1945 年间。珍珠港事件发生在 1941 年底,到 1942 年,美国军队已深度卷入一场大规模战争,该战争于 1945 年结束。

  • 2019 年年龄在 69 至 72 岁之间的人出生于 1947 年至 1950 年间,正值美国二战后婴儿潮的高峰期。

战后出生率的激增是我们观察到的巨大变化的一个主要原因。

[In ]: