Background
Latest Data Source: https://www.ssa.gov/oact/babynames/limits.html
yobYYYY.txt (1880 ~ 2016)
name,sex,number
这是一个非常标准的以逗号隔开的格式,可以用pandas.read_csv将其加载到DataFrame中。
1 C:\Users\I******>ipython --pylab
2 Python 2.7.13 | 64-bit | (default, Mar 30 2017, 11:20:05) [MSC v.1500 64 bit (AMD64)]
3 Type "copyright", "credits" or "license" for more information.
4
5 IPython 4.1.2 -- An enhanced Interactive Python.
6 ? -> Introduction and overview of IPython's features.
7 %quickref -> Quick reference.
8 help -> Python's own help system.
9 object? -> Details about 'object', use 'object??' for extra details.
10 Using matplotlib backend: TkAgg
11
12 In [1]: import pandas as pd
13
14 In [2]: names1880 = pd.read_csv('C:/Users/I******/Desktop/.../names/yob1880.txt', names=['name', 'sex', 'number'])
15
16 In [3]: names1880
17 Out[3]:
18 name sex number
19 0 Mary F 7065
20 1 Anna F 2604
21 2 Emma F 2003
22 3 Elizabeth F 1939
23 4 Minnie F 1746
24 5 Margaret F 1578
25 6 Ida F 1472
26 7 Alice F 1414
27 8 Bertha F 1320
28 9 Sarah F 1288
29 10 Annie F 1258
30 11 Clara F 1226
31 12 Ella F 1156
32 13 Florence F 1063
33 14 Cora F 1045
34 15 Martha F 1040
35 16 Laura F 1012
36 17 Nellie F 995
37 18 Grace F 982
38 19 Carrie F 949
39 20 Maude F 858
40 21 Mabel F 808
41 22 Bessie F 796
42 23 Jennie F 793
43 24 Gertrude F 787
44 25 Julia F 783
45 26 Hattie F 769
46 27 Edith F 768
47 28 Mattie F 704
48 29 Rose F 700
49 ... ... .. ...
50 1970 Philo M 5
51 1971 Phineas M 5
52 1972 Presley M 5
53 1973 Ransom M 5
54 1974 Reece M 5
55 1975 Rene M 5
56 1976 Roswell M 5
57 1977 Rowland M 5
58 1978 Sampson M 5
59 1979 Samual M 5
60 1980 Santos M 5
61 1981 Schuyler M 5
62 1982 Sheppard M 5
63 1983 Spurgeon M 5
64 1984 Starling M 5
65 1985 Sylvanus M 5
66 1986 Theadore M 5
67 1987 Theophile M 5
68 1988 Tilmon M 5
69 1989 Tommy M 5
70 1990 Unknown M 5
71 1991 Vann M 5
72 1992 Wes M 5
73 1993 Winston M 5
74 1994 Wood M 5
75 1995 Woodie M 5
76 1996 Worthy M 5
77 1997 Wright M 5
78 1998 York M 5
79 1999 Zachariah M 5
80
81 [2000 rows x 3 columns]
用number列的sex分组小计表示该年度的number总计。
1 In [4]: names1880.groupby('sex').number.sum()
2 Out[4]:
3 sex
4 F 90992
5 M 110491
6 Name: number, dtype: int64
将所有数据组装到一个DataFrame里面,并加上一个year字段。使用pandas.concat即可达到这个目的。
注意:第一,concat默认是按行将多个DataFrame组合到一起的;第二,必须指定ignore_index=True,因为我们不希望保留read_csv所返回的原始行号。
1 In [5]: years = range(1880, 2017)
2
3 In [6]: pieces = []
4
5 In [7]: columns = ['name', 'sex', 'number']
6
7 In [8]: for year in years:
8 ...: path = 'C:/Users/I******/Desktop/.../names/yob%d.txt' % year
9 ...: frame = pd.read_csv(path, names=columns)
10 ...: frame['year'] = year
11 ...: pieces.append(frame)
12 ...:
13
14 In [9]: names = pd.concat(pieces, ignore_index=True)
15
16 In [10]: names
17 Out[10]:
18 name sex number year
19 0 Mary F 7065 1880
20 1 Anna F 2604 1880
21 2 Emma F 2003 1880
22 3 Elizabeth F 1939 1880
23 4 Minnie F 1746 1880
24 5 Margaret F 1578 1880
25 6 Ida F 1472 1880
26 7 Alice F 1414 1880
27 8 Bertha F 1320 1880
28 9 Sarah F 1288 1880
29 10 Annie F 1258 1880
30 11 Clara F 1226 1880
31 12 Ella F 1156 1880
32 13 Florence F 1063 1880
33 14 Cora F 1045 1880
34 15 Martha F 1040 1880
35 16 Laura F 1012 1880
36 17 Nellie F 995 1880
37 18 Grace F 982 1880
38 19 Carrie F 949 1880
39 20 Maude F 858 1880
40 21 Mabel F 808 1880
41 22 Bessie F 796 1880
42 23 Jennie F 793 1880
43 24 Gertrude F 787 1880
44 25 Julia F 783 1880
45 26 Hattie F 769 1880
46 27 Edith F 768 1880
47 28 Mattie F 704 1880
48 29 Rose F 700 1880
49 ... ... .. ... ...
50 1891864 Zariyan M 5 2016
51 1891865 Zarren M 5 2016
52 1891866 Zaryn M 5 2016
53 1891867 Zaxon M 5 2016
54 1891868 Zaxtyn M 5 2016
55 1891869 Zaye M 5 2016
56 1891870 Zaymar M 5 2016
57 1891871 Zaymir M 5 2016
58 1891872 Zaynn M 5 2016
59 1891873 Zayshaun M 5 2016
60 1891874 Zedric M 5 2016
61 1891875 Zekariah M 5 2016
62 1891876 Zelan M 5 2016
63 1891877 Zephen M 5 2016
64 1891878 Zephyrus M 5 2016
65 1891879 Zeric M 5 2016
66 1891880 Zerin M 5 2016
67 1891881 Zethan M 5 2016
68 1891882 Zihao M 5 2016
69 1891883 Zimo M 5 2016
70 1891884 Zinn M 5 2016
71 1891885 Zirui M 5 2016
72 1891886 Ziya M 5 2016
73 1891887 Ziyang M 5 2016
74 1891888 Zoel M 5 2016
75 1891889 Zolton M 5 2016
76 1891890 Zurich M 5 2016
77 1891891 Zyahir M 5 2016
78 1891892 Zyel M 5 2016
79 1891893 Zylyn M 5 2016
80
81 [1891894 rows x 4 columns]
按年份、性别计数。
1 In [11]: total_number = names.pivot_table('number', index='year', columns='sex', aggfunc=sum)
2
3 In [12]: total_number.tail()
4 Out[12]:
5 sex F M
6 year
7 2012 1756347 1892094
8 2013 1749061 1885683
9 2014 1779496 1913434
10 2015 1776538 1907211
11 2016 1756647 1880674
作图。
1 In [13]: total_number.plot(title='Total number by sex and year')
插入一个prop列,用于存放指定名字的婴儿数相对于总出生数的比例。
1 In [14]: def add_prop(group):
2 ....: number = group.number.astype(float)
3 ....: group['prop'] = number / number.sum()
4 ....: return group
5 ....:
6
7 In [15]: names = names.groupby(['year', 'sex']).apply(add_prop)
8
9 In [16]: names
10 Out[16]:
11 name sex number year prop
12 0 Mary F 7065 1880 0.077644
13 1 Anna F 2604 1880 0.028618
14 2 Emma F 2003 1880 0.022013
15 3 Elizabeth F 1939 1880 0.021310
16 4 Minnie F 1746 1880 0.019189
17 5 Margaret F 1578 1880 0.017342
18 6 Ida F 1472 1880 0.016177
19 7 Alice F 1414 1880 0.015540
20 8 Bertha F 1320 1880 0.014507
21 9 Sarah F 1288 1880 0.014155
22 10 Annie F 1258 1880 0.013825
23 11 Clara F 1226 1880 0.013474
24 12 Ella F 1156 1880 0.012704
25 13 Florence F 1063 1880 0.011682
26 14 Cora F 1045 1880 0.011485
27 15 Martha F 1040 1880 0.011430
28 16 Laura F 1012 1880 0.011122
29 17 Nellie F 995 1880 0.010935
30 18 Grace F 982 1880 0.010792
31 19 Carrie F 949 1880 0.010429
32 20 Maude F 858 1880 0.009429
33 21 Mabel F 808 1880 0.008880
34 22 Bessie F 796 1880 0.008748
35 23 Jennie F 793 1880 0.008715
36 24 Gertrude F 787 1880 0.008649
37 25 Julia F 783 1880 0.008605
38 26 Hattie F 769 1880 0.008451
39 27 Edith F 768 1880 0.008440
40 28 Mattie F 704 1880 0.007737
41 29 Rose F 700 1880 0.007693
42 ... ... .. ... ... ...
43 1891864 Zariyan M 5 2016 0.000003
44 1891865 Zarren M 5 2016 0.000003
45 1891866 Zaryn M 5 2016 0.000003
46 1891867 Zaxon M 5 2016 0.000003
47 1891868 Zaxtyn M 5 2016 0.000003
48 1891869 Zaye M 5 2016 0.000003
49 1891870 Zaymar M 5 2016 0.000003
50 1891871 Zaymir M 5 2016 0.000003
51 1891872 Zaynn M 5 2016 0.000003
52 1891873 Zayshaun M 5 2016 0.000003
53 1891874 Zedric M 5 2016 0.000003
54 1891875 Zekariah M 5 2016 0.000003
55 1891876 Zelan M 5 2016 0.000003
56 1891877 Zephen M 5 2016 0.000003
57 1891878 Zephyrus M 5 2016 0.000003
58 1891879 Zeric M 5 2016 0.000003
59 1891880 Zerin M 5 2016 0.000003
60 1891881 Zethan M 5 2016 0.000003
61 1891882 Zihao M 5 2016 0.000003
62 1891883 Zimo M 5 2016 0.000003
63 1891884 Zinn M 5 2016 0.000003
64 1891885 Zirui M 5 2016 0.000003
65 1891886 Ziya M 5 2016 0.000003
66 1891887 Ziyang M 5 2016 0.000003
67 1891888 Zoel M 5 2016 0.000003
68 1891889 Zolton M 5 2016 0.000003
69 1891890 Zurich M 5 2016 0.000003
70 1891891 Zyahir M 5 2016 0.000003
71 1891892 Zyel M 5 2016 0.000003
72 1891893 Zylyn M 5 2016 0.000003
73
74 [1891894 rows x 5 columns]
注意:整数除法会向下圆整,由于number是整数,所以在计算分式时必须将分子或分母转换成浮点数。
在执行这样的分组处理时,一般都应该做一些有效性检查,比如验证所有分组的prop的总和是否为1。由于这是一个浮点型数据,所以用np.allclose来检查这个分组的总计值是否足够近似于(可能不会精确等于)1。
1 In [17]: np.allclose(names.groupby(['year', 'sex']).prop.sum(), 1)
2 Out[17]: True
为了便于实现更进一步的分析,取出该数据的一个子集:每对sex/year组合的前1000个名字。这又是一个分组操作。
1 In [18]: def get_top1000(group):
2 ....: return group.sort_values(by='number', ascending=False)[:1000]
3 ....:
4
5 In [19]: grouped = names.groupby(['year', 'sex'])
6
7 In [20: top1000 = grouped.apply(get_top1000)
8
9 In [21]: pieces = []
10
11 In [22]: for year, group in names.groupby(['year', 'sex']):
12 ....: pieces.append(group.sort_values(by='number', ascending=False)[:1000])
13 ....:
14
15 In [23]: top1000 = pd.concat(pieces, ignore_index=True)
16
17 In [24]: top1000
18 Out[24]:
19 name sex number year prop
20 0 Mary F 7065 1880 0.077644
21 1 Anna F 2604 1880 0.028618
22 2 Emma F 2003 1880 0.022013
23 3 Elizabeth F 1939 1880 0.021310
24 4 Minnie F 1746 1880 0.019189
25 5 Margaret F 1578 1880 0.017342
26 6 Ida F 1472 1880 0.016177
27 7 Alice F 1414 1880 0.015540
28 8 Bertha F 1320 1880 0.014507
29 9 Sarah F 1288 1880 0.014155
30 10 Annie F 1258 1880 0.013825
31 11 Clara F 1226 1880 0.013474
32 12 Ella F 1156 1880 0.012704
33 13 Florence F 1063 1880 0.011682
34 14 Cora F 1045 1880 0.011485
35 15 Martha F 1040 1880 0.011430
36 16 Laura F 1012 1880 0.011122
37 17 Nellie F 995 1880 0.010935
38 18 Grace F 982 1880 0.010792
39 19 Carrie F 949 1880 0.010429
40 20 Maude F 858 1880 0.009429
41 21 Mabel F 808 1880 0.008880
42 22 Bessie F 796 1880 0.008748
43 23 Jennie F 793 1880 0.008715
44 24 Gertrude F 787 1880 0.008649
45 25 Julia F 783 1880 0.008605
46 26 Hattie F 769 1880 0.008451
47 27 Edith F 768 1880 0.008440
48 28 Mattie F 704 1880 0.007737
49 29 Rose F 700 1880 0.007693
50 ... ... .. ... ... ...
51 273847 Keanu M 210 2016 0.000112
52 273848 Konner M 210 2016 0.000112
53 273849 Brent M 209 2016 0.000111
54 273850 Immanuel M 209 2016 0.000111
55 273851 Benicio M 208 2016 0.000111
56 273852 Ernest M 208 2016 0.000111
57 273853 Merrick M 208 2016 0.000111
58 273854 Yisroel M 208 2016 0.000111
59 273855 Lyle M 207 2016 0.000110
60 273856 Amare M 207 2016 0.000110
61 273857 Jad M 207 2016 0.000110
62 273858 Maddux M 206 2016 0.000110
63 273859 Creed M 206 2016 0.000110
64 273860 Krish M 206 2016 0.000110
65 273861 Giancarlo M 205 2016 0.000109
66 273862 Jamarion M 205 2016 0.000109
67 273863 Steve M 205 2016 0.000109
68 273864 Camilo M 205 2016 0.000109
69 273865 Anton M 204 2016 0.000108
70 273866 Jamar M 204 2016 0.000108
71 273867 Jeremias M 204 2016 0.000108
72 273868 Ralph M 204 2016 0.000108
73 273869 Wesson M 204 2016 0.000108
74 273870 Brenden M 203 2016 0.000108
75 273871 Eliezer M 203 2016 0.000108
76 273872 Braeden M 203 2016 0.000108
77 273873 Bode M 203 2016 0.000108
78 273874 Davian M 202 2016 0.000107
79 273875 Gus M 202 2016 0.000107
80 273876 Jonathon M 202 2016 0.000107
81
82 [273877 rows x 5 columns]
分析命名趋势。
首先将前1000个名字分为男女两个部分。
1 In [25]: boys = top1000[top1000.sex == 'M']
2
3 In [26]: girls = top1000[top1000.sex == 'F']
生成一张按year和name统计的总出生数透视表。
1 In [27]: total_number = top1000.pivot_table('number', index='year', columns='name', aggfunc=sum)
2
3 In [28]: total_number
4 Out[28]:
5 name Aaden Aadhya Aaliyah Aanya Aarav Aaron Aarush Ab Abagail \
6 year
7 1880 NaN NaN NaN NaN NaN 102.0 NaN NaN NaN
8 1881 NaN NaN NaN NaN NaN 94.0 NaN NaN NaN
9 1882 NaN NaN NaN NaN NaN 85.0 NaN NaN NaN
10 1883 NaN NaN NaN NaN NaN 105.0 NaN NaN NaN
11 1884 NaN NaN NaN NaN NaN 97.0 NaN NaN NaN
12 1885 NaN NaN NaN NaN NaN 88.0 NaN 6.0 NaN
13 1886 NaN NaN NaN NaN NaN 86.0 NaN NaN NaN
14 1887 NaN NaN NaN NaN NaN 78.0 NaN NaN NaN
15 1888 NaN NaN NaN NaN NaN 90.0 NaN NaN NaN
16 1889 NaN NaN NaN NaN NaN 85.0 NaN NaN NaN
17 1890 NaN NaN NaN NaN NaN 96.0 NaN NaN NaN
18 1891 NaN NaN NaN NaN NaN 69.0 NaN NaN NaN
19 1892 NaN NaN NaN NaN NaN 95.0 NaN NaN NaN
20 1893 NaN NaN NaN NaN NaN 81.0 NaN NaN NaN
21 1894 NaN NaN NaN NaN NaN 79.0 NaN NaN NaN
22 1895 NaN NaN NaN NaN NaN 94.0 NaN NaN NaN
23 1896 NaN NaN NaN NaN NaN 69.0 NaN NaN NaN
24 1897 NaN NaN NaN NaN NaN 87.0 NaN NaN NaN
25 1898 NaN NaN NaN NaN NaN 89.0 NaN NaN NaN
26 1899 NaN NaN NaN NaN NaN 71.0 NaN NaN NaN
27 1900 NaN NaN NaN NaN NaN 103.0 NaN NaN NaN
28 1901 NaN NaN NaN NaN NaN 80.0 NaN NaN NaN
29 1902 NaN NaN NaN NaN NaN 78.0 NaN NaN NaN
30 1903 NaN NaN NaN NaN NaN 93.0 NaN NaN NaN
31 1904 NaN NaN NaN NaN NaN 117.0 NaN NaN NaN
32 1905 NaN NaN NaN NaN NaN 96.0 NaN NaN NaN
33 1906 NaN NaN NaN NaN NaN 96.0 NaN NaN NaN
34 1907 NaN NaN NaN NaN NaN 130.0 NaN NaN NaN
35 1908 NaN NaN NaN NaN NaN 114.0 NaN NaN NaN
36 1909 NaN NaN NaN NaN NaN 142.0 NaN NaN NaN
37 ... ... ... ... ... ... ... ... ... ...
38 1987 NaN NaN NaN NaN NaN 12682.0 NaN NaN NaN
39 1988 NaN NaN NaN NaN NaN 14404.0 NaN NaN NaN
40 1989 NaN NaN NaN NaN NaN 15312.0 NaN NaN NaN
41 1990 NaN NaN NaN NaN NaN 14550.0 NaN NaN NaN
42 1991 NaN NaN NaN NaN NaN 14241.0 NaN NaN NaN
43 1992 NaN NaN NaN NaN NaN 14506.0 NaN NaN NaN
44 1993 NaN NaN NaN NaN NaN 13827.0 NaN NaN NaN
45 1994 NaN NaN 1451.0 NaN NaN 14381.0 NaN NaN NaN
46 1995 NaN NaN 1255.0 NaN NaN 13287.0 NaN NaN NaN
47 1996 NaN NaN 831.0 NaN NaN 11969.0 NaN NaN NaN
48 1997 NaN NaN 1738.0 NaN NaN 11165.0 NaN NaN NaN
49 1998 NaN NaN 1399.0 NaN NaN 10547.0 NaN NaN NaN
50 1999 NaN NaN 1088.0 NaN NaN 9853.0 NaN NaN 211.0
51 2000 NaN NaN 1496.0 NaN NaN 9551.0 NaN NaN 222.0
52 2001 NaN NaN 3352.0 NaN NaN 9534.0 NaN NaN 244.0
53 2002 NaN NaN 4778.0 NaN NaN 9001.0 NaN NaN 256.0
54 2003 NaN NaN 3671.0 NaN NaN 8862.0 NaN NaN 276.0
55 2004 NaN NaN 3488.0 NaN NaN 8388.0 NaN NaN 258.0
56 2005 NaN NaN 3456.0 NaN NaN 7800.0 NaN NaN 288.0
57 2006 NaN NaN 3743.0 NaN NaN 8294.0 NaN NaN 298.0
58 2007 NaN NaN 3955.0 NaN NaN 8933.0 NaN NaN 313.0
59 2008 956.0 NaN 4038.0 NaN 219.0 8536.0 NaN NaN 321.0
60 2009 1267.0 NaN 4367.0 NaN 270.0 7967.0 NaN NaN 297.0
61 2010 450.0 NaN 4661.0 NaN 438.0 7461.0 227.0 NaN 281.0
62 2011 275.0 NaN 5112.0 NaN 436.0 7613.0 NaN NaN NaN
63 2012 223.0 NaN 5502.0 NaN 435.0 7522.0 NaN NaN NaN
64 2013 203.0 NaN 5225.0 NaN 495.0 7297.0 NaN NaN NaN
65 2014 237.0 NaN 4875.0 266.0 531.0 7383.0 NaN NaN NaN
66 2015 297.0 NaN 4850.0 NaN 539.0 7144.0 211.0 NaN NaN
67 2016 NaN 284.0 4611.0 NaN 519.0 7118.0 NaN NaN NaN
68
69 name Abb ... Zoe Zoey Zoie Zola Zollie Zona Zora Zula \
70 year ...
71 1880 NaN ... 23.0 NaN NaN 7.0 NaN 8.0 28.0 27.0
72 1881 NaN ... 22.0 NaN NaN 10.0 NaN 9.0 21.0 27.0
73 1882 NaN ... 25.0 NaN NaN 9.0 NaN 17.0 32.0 21.0
74 1883 NaN ... 23.0 NaN NaN 10.0 NaN 11.0 35.0 25.0
75 1884 NaN ... 31.0 NaN NaN 14.0 6.0 8.0 58.0 27.0
76 1885 NaN ... 27.0 NaN NaN 12.0 6.0 14.0 48.0 38.0
77 1886 NaN ... 25.0 NaN NaN 8.0 NaN 20.0 52.0 43.0
78 1887 NaN ... 34.0 NaN NaN 23.0 NaN 28.0 46.0 33.0
79 1888 NaN ... 42.0 NaN NaN 23.0 7.0 30.0 42.0 45.0
80 1889 NaN ... 29.0 NaN NaN 22.0 NaN 29.0 53.0 55.0
81 1890 6.0 ... 42.0 NaN NaN 32.0 7.0 27.0 60.0 65.0
82 1891 NaN ... 34.0 NaN NaN 29.0 6.0 14.0 52.0 45.0
83 1892 NaN ... 34.0 NaN NaN 27.0 NaN 25.0 66.0 53.0
84 1893 NaN ... 23.0 NaN NaN 34.0 6.0 15.0 67.0 70.0
85 1894 NaN ... 28.0 NaN NaN 51.0 NaN 23.0 66.0 64.0
86 1895 NaN ... 34.0 NaN NaN 60.0 11.0 38.0 55.0 55.0
87 1896 NaN ... 36.0 NaN NaN 47.0 NaN 38.0 72.0 65.0
88 1897 NaN ... 35.0 NaN NaN 51.0 NaN 28.0 67.0 79.0
89 1898 NaN ... 30.0 NaN NaN 62.0 NaN 28.0 65.0 83.0
90 1899 NaN ... 27.0 NaN NaN 49.0 6.0 31.0 56.0 60.0
91 1900 NaN ... 26.0 NaN NaN 48.0 9.0 44.0 99.0 71.0
92 1901 NaN ... 26.0 NaN NaN 56.0 NaN 31.0 58.0 57.0
93 1902 NaN ... 34.0 NaN NaN 58.0 NaN 23.0 58.0 66.0
94 1903 NaN ... 19.0 NaN NaN 64.0 NaN 41.0 83.0 74.0
95 1904 NaN ... 27.0 NaN NaN 46.0 NaN 35.0 54.0 74.0
96 1905 NaN ... 24.0 NaN NaN 66.0 8.0 24.0 55.0 61.0
97 1906 NaN ... 19.0 NaN NaN 59.0 NaN 37.0 64.0 58.0
98 1907 NaN ... 19.0 NaN NaN 53.0 11.0 39.0 92.0 72.0
99 1908 NaN ... 23.0 NaN NaN 70.0 NaN 31.0 59.0 53.0
100 1909 NaN ... 22.0 NaN NaN 59.0 NaN 39.0 57.0 76.0
101 ... ... ... ... ... ... ... ... ... ... ...
102 1987 NaN ... 247.0 NaN NaN NaN NaN NaN NaN NaN
103 1988 NaN ... 241.0 NaN NaN NaN NaN NaN NaN NaN
104 1989 NaN ... 376.0 NaN NaN NaN NaN NaN NaN NaN
105 1990 NaN ... 478.0 NaN NaN NaN NaN NaN NaN NaN
106 1991 NaN ... 722.0 NaN NaN NaN NaN NaN NaN NaN
107 1992 NaN ... 981.0 NaN NaN NaN NaN NaN NaN NaN
108 1993 NaN ... 1193.0 NaN NaN NaN NaN NaN NaN NaN
109 1994 NaN ... 1333.0 NaN NaN NaN NaN NaN NaN NaN
110 1995 NaN ... 1726.0 219.0 NaN NaN NaN NaN NaN NaN
111 1996 NaN ... 2065.0 339.0 NaN NaN NaN NaN NaN NaN
112 1997 NaN ... 2362.0 407.0 NaN NaN NaN NaN NaN NaN
113 1998 NaN ... 2693.0 478.0 225.0 NaN NaN NaN NaN NaN
114 1999 NaN ... 3236.0 563.0 257.0 NaN NaN NaN NaN NaN
115 2000 NaN ... 3785.0 691.0 320.0 NaN NaN NaN NaN NaN
116 2001 NaN ... 4644.0 822.0 439.0 NaN NaN NaN NaN NaN
117 2002 NaN ... 4886.0 1182.0 438.0 NaN NaN NaN NaN NaN
118 2003 NaN ... 5085.0 1469.0 449.0 NaN NaN NaN NaN NaN
119 2004 NaN ... 5363.0 1622.0 515.0 NaN NaN NaN NaN NaN
120 2005 NaN ... 4958.0 2273.0 502.0 NaN NaN NaN NaN NaN
121 2006 NaN ... 5152.0 2849.0 531.0 NaN NaN NaN NaN NaN
122 2007 NaN ... 4933.0 3032.0 527.0 NaN NaN NaN NaN NaN
123 2008 NaN ... 4781.0 3445.0 493.0 NaN NaN NaN NaN NaN
124 2009 NaN ... 5144.0 3993.0 499.0 NaN NaN NaN NaN NaN
125 2010 NaN ... 6264.0 5203.0 508.0 NaN NaN NaN NaN NaN
126 2011 NaN ... 6299.0 6397.0 523.0 NaN NaN NaN NaN NaN
127 2012 NaN ... 6451.0 7462.0 516.0 NaN NaN NaN NaN NaN
128 2013 NaN ... 5969.0 7230.0 431.0 NaN NaN NaN NaN NaN
129 2014 NaN ... 5866.0 7392.0 365.0 NaN NaN NaN NaN NaN
130 2015 NaN ... 6032.0 6927.0 370.0 NaN NaN NaN NaN NaN
131 2016 NaN ... 5706.0 6414.0 311.0 NaN NaN NaN NaN NaN
132
133 name Zuri Zyaire
134 year
135 1880 NaN NaN
136 1881 NaN NaN
137 1882 NaN NaN
138 1883 NaN NaN
139 1884 NaN NaN
140 1885 NaN NaN
141 1886 NaN NaN
142 1887 NaN NaN
143 1888 NaN NaN
144 1889 NaN NaN
145 1890 NaN NaN
146 1891 NaN NaN
147 1892 NaN NaN
148 1893 NaN NaN
149 1894 NaN NaN
150 1895 NaN NaN
151 1896 NaN NaN
152 1897 NaN NaN
153 1898 NaN NaN
154 1899 NaN NaN
155 1900 NaN NaN
156 1901 NaN NaN
157 1902 NaN NaN
158 1903 NaN NaN
159 1904 NaN NaN
160 1905 NaN NaN
161 1906 NaN NaN
162 1907 NaN NaN
163 1908 NaN NaN
164 1909 NaN NaN
165 ... ... ...
166 1987 NaN NaN
167 1988 NaN NaN
168 1989 NaN NaN
169 1990 NaN NaN
170 1991 NaN NaN
171 1992 NaN NaN
172 1993 NaN NaN
173 1994 NaN NaN
174 1995 NaN NaN
175 1996 NaN NaN
176 1997 NaN NaN
177 1998 NaN NaN
178 1999 NaN NaN
179 2000 NaN NaN
180 2001 NaN NaN
181 2002 NaN NaN
182 2003 NaN NaN
183 2004 NaN NaN
184 2005 NaN NaN
185 2006 NaN NaN
186 2007 NaN NaN
187 2008 NaN NaN
188 2009 NaN NaN
189 2010 259.0 NaN
190 2011 313.0 NaN
191 2012 435.0 NaN
192 2013 567.0 NaN
193 2014 666.0 NaN
194 2015 712.0 NaN
195 2016 884.0 245.0
196
197 [137 rows x 7100 columns]
取出John、Harry、Mary和Marilyn这四个名字作为子集,并作图。
1 In [29]: subset = total_number[['John', 'Harry', 'Mary', 'Marilyn']]
2
3 In [30]: subset.plot(subplots=True, figsize=(12, 10), grid=False, title="Number of births per year")
评估命名多样性的增长
验证父母愿意给小孩起常见的名字越来越少:
一、计算最流行的1000个名字所占的比例,按year和sex进行聚合并绘图。
1 In [31]: table = top1000.pivot_table('prop', index='year', columns='sex', aggfunc=sum)
2
3 In [32]: table.plot(title='Sum of table1000.prop by year and sex', yticks=np.linspace(0, 1.2, 13), xticks=range(1880, 2020, 10))
前1000项的比例降低,说明名字的多样性确实出现了增长。
二、计算占总出生人数前50%的不同名字的数量,暂且只考虑2010年男孩的名字。
1 In [33]: df = boys[boys.year == 2010]
2
3 In [34]: df
4 Out[34]:
5 name sex number year prop
6 260877 Jacob M 22110 2010 0.011544
7 260878 Ethan M 17995 2010 0.009395
8 260879 Michael M 17336 2010 0.009051
9 260880 Jayden M 17163 2010 0.008961
10 260881 William M 17042 2010 0.008898
11 260882 Alexander M 16749 2010 0.008745
12 260883 Noah M 16442 2010 0.008584
13 260884 Daniel M 15827 2010 0.008263
14 260885 Aiden M 15531 2010 0.008109
15 260886 Anthony M 15482 2010 0.008083
16 260887 Joshua M 15432 2010 0.008057
17 260888 Mason M 14837 2010 0.007746
18 260889 Christopher M 14263 2010 0.007447
19 260890 Andrew M 14234 2010 0.007432
20 260891 David M 14181 2010 0.007404
21 260892 Matthew M 14119 2010 0.007372
22 260893 Logan M 14015 2010 0.007317
23 260894 Elijah M 13879 2010 0.007246
24 260895 James M 13870 2010 0.007242
25 260896 Joseph M 13816 2010 0.007213
26 260897 Gabriel M 12865 2010 0.006717
27 260898 Benjamin M 12427 2010 0.006488
28 260899 Ryan M 11967 2010 0.006248
29 260900 Samuel M 11954 2010 0.006241
30 260901 Jackson M 11813 2010 0.006168
31 260902 John M 11550 2010 0.006030
32 260903 Nathan M 11368 2010 0.005935
33 260904 Jonathan M 11116 2010 0.005804
34 260905 Christian M 11090 2010 0.005790
35 260906 Liam M 10927 2010 0.005705
36 ... ... .. ... ... ...
37 261847 Ronaldo M 203 2010 0.000106
38 261848 Yair M 203 2010 0.000106
39 261849 Lathan M 203 2010 0.000106
40 261850 Gibson M 202 2010 0.000105
41 261851 Keyon M 202 2010 0.000105
42 261852 Reagan M 202 2010 0.000105
43 261853 Daylen M 201 2010 0.000105
44 261854 Kingsley M 201 2010 0.000105
45 261855 Talan M 201 2010 0.000105
46 261856 Yehuda M 201 2010 0.000105
47 261857 Jordon M 200 2010 0.000104
48 261858 Slade M 200 2010 0.000104
49 261859 Sheldon M 200 2010 0.000104
50 261860 Dashawn M 200 2010 0.000104
51 261861 Cristofer M 200 2010 0.000104
52 261862 Clarence M 199 2010 0.000104
53 261863 Dillan M 199 2010 0.000104
54 261864 Kadin M 199 2010 0.000104
55 261865 Masen M 199 2010 0.000104
56 261866 Rowen M 199 2010 0.000104
57 261867 Clinton M 198 2010 0.000103
58 261868 Thaddeus M 198 2010 0.000103
59 261869 Yousef M 198 2010 0.000103
60 261870 Truman M 197 2010 0.000103
61 261871 Joziah M 196 2010 0.000102
62 261872 Simeon M 196 2010 0.000102
63 261873 Reuben M 196 2010 0.000102
64 261874 Keshawn M 196 2010 0.000102
65 261875 Eliezer M 196 2010 0.000102
66 261876 Enoch M 196 2010 0.000102
67
68 [1000 rows x 5 columns]
先计算prop的累积和cumsum,然后再通过searchsorted方法找出0.5应该被插入在哪个位置才能保证不破坏顺序。
1 In [35]: prop_cumsum = df.sort_values(by='prop', ascending=False).prop.cumsum()
2
3 In [36]: prop_cumsum[:10]
4 Out[36]:
5 260877 0.011544
6 260878 0.020939
7 260879 0.029990
8 260880 0.038951
9 260881 0.047849
10 260882 0.056593
11 260883 0.065178
12 260884 0.073441
13 260885 0.081550
14 260886 0.089633
15 Name: prop, dtype: float64
16
17 In [37]: prop_cumsum.searchsorted(0.5)
18 Out[37]: array([116], dtype=int64)
由于数组索引从0开始,因此要给结果+1,即最终结果为117。而1900年的25则要小得多。
1 In [38]: df = boys[boys.year == 1900]
2
3 In [39]: in1900 = df.sort_values(by='prop', ascending=False).prop.cumsum()
4
5 In [40]: in1900.searchsorted(0.5) + 1
6 Out[40]: array([25], dtype=int64)
Error
1 In [41]: def get_quantile_count(group, q=0.5):
2 ....: group = group.sort_values(by='prop', ascending=False)
3 ....: return group.prop.cumsum().searchsorted(q) + 1
4 ....:
5
6 In [42]: diversity = top1000.groupby(['year','sex']).apply(get_quantile_count)
7
8 In [43]: diversity = diversity.unstack('sex')
9
10 In [44]: diversity.head()
11 Out[44]:
12 sex F M
13 year
14 1880 [38] [14]
15 1881 [38] [14]
16 1882 [38] [15]
17 1883 [39] [15]
18 1884 [39] [16]
19
20 In [45]: diversity.plot(title="Number of popular names in top50%")
21 ---------------------------------------------------------------------------
22 TypeError Traceback (most recent call last)
23 <ipython-input-40-d380f36f6920> in <module>()
24 ----> 1 diversity.plot(title="Number of popular names in top50%")
25
26 C:\Users\I******\AppData\Local\Enthought\Canopy\App\appdata\canopy-2.1.3.3542.win-x86_64\lib\site-packages\pandas-0.20.3-py2.7-win-amd64.egg\pandas\plotting\_core.pyc in __call__(self, x, y, kind, ax, subplots, sharex, sharey, layout, figsize, use_index, title, grid, legend, style, logx, logy, loglog, xticks, yticks, xlim, ylim, rot, fontsize, colormap, table, yerr, xerr, secondary_y, sort_columns, **kwds)
27 2625 fontsize=fontsize, colormap=colormap, table=table,
28 2626 yerr=yerr, xerr=xerr, secondary_y=secondary_y,
29 -> 2627 sort_columns=sort_columns, **kwds)
30 2628 __call__.__doc__ = plot_frame.__doc__
31 2629
32
33 C:\Users\I******\AppData\Local\Enthought\Canopy\App\appdata\canopy-2.1.3.3542.win-x86_64\lib\site-packages\pandas-0.20.3-py2.7-win-amd64.egg\pandas\plotting\_core.pyc in plot_frame(data, x, y, kind, ax, subplots, sharex, sharey, layout, figsize, use_index, title, grid, legend, style, logx, logy, loglog, xticks, yticks, xlim, ylim, rot, fontsize, colormap, table, yerr, xerr, secondary_y, sort_columns, **kwds)
34 1867 yerr=yerr, xerr=xerr,
35 1868 secondary_y=secondary_y, sort_columns=sort_columns,
36 -> 1869 **kwds)
37 1870
38 1871
39
40 C:\Users\I******\AppData\Local\Enthought\Canopy\App\appdata\canopy-2.1.3.3542.win-x86_64\lib\site-packages\pandas-0.20.3-py2.7-win-amd64.egg\pandas\plotting\_core.pyc in _plot(data, x, y, subplots, ax, kind, **kwds)
41 1692 plot_obj = klass(data, subplots=subplots, ax=ax, kind=kind, **kwds)
42 1693
43 -> 1694 plot_obj.generate()
44 1695 plot_obj.draw()
45 1696 return plot_obj.result
46
47 C:\Users\I******\AppData\Local\Enthought\Canopy\App\appdata\canopy-2.1.3.3542.win-x86_64\lib\site-packages\pandas-0.20.3-py2.7-win-amd64.egg\pandas\plotting\_core.pyc in generate(self)
48 241 def generate(self):
49 242 self._args_adjust()
50 --> 243 self._compute_plot_data()
51 244 self._setup_subplots()
52 245 self._make_plot()
53
54 C:\Users\I******\AppData\Local\Enthought\Canopy\App\appdata\canopy-2.1.3.3542.win-x86_64\lib\site-packages\pandas-0.20.3-py2.7-win-amd64.egg\pandas\plotting\_core.pyc in _compute_plot_data(self)
55 350 if is_empty:
56 351 raise TypeError('Empty {0!r}: no numeric data to '
57 --> 352 'plot'.format(numeric_data.__class__.__name__))
58 353
59 354 self.data = numeric_data
60
61 TypeError: Empty 'DataFrame': no numeric data to plot
Solution01
python3的searchsorted()返回的是ndarray类型而不是int64类型,所以需要先取[0]元素,才能获得想要的数据。
1 In [46]: def get_quantile_count(group, q=0.5):
2 ....: group = group.sort_values(by='prop', ascending=False)
3 ....: return group.prop.cumsum().searchsorted(q)[0] + 1
4 ....:
5
6 In [47]: diversity = top1000.groupby(['year', 'sex']).apply(get_quantile_count)
7
8 In [48]: diversity = diversity.unstack('sex')
9
10 In [49]: diversity.head()
11 Out[49]:
12 sex F M
13 year
14 1880 38 14
15 1881 38 14
16 1882 38 15
17 1883 39 15
18 1884 39 16
19
20 In [50]: diversity.plot(title="Number of popular names in top50%")
21 Out[50]: <matplotlib.axes._subplots.AxesSubplot at 0xcbce208>
从图中可以看出,女孩名字的多样性总是比男孩的高,而且还在变得越来越高。
最后一个字母
将全部出生数据在年度、性别以及末字母上进行聚合。
1 In [51]: get_last_letter = lambda x: x[-1]
2
3 In [52]: last_letters = names.name.map(get_last_letter)
4
5 In [53]: last_letters.name = 'last_letter'
6
7 In [54]: table = names.pivot_table('number', index=last_letters, columns=['sex', 'year'], aggfunc=sum)
8
9 In [55]: subtable = table.reindex(columns=[1916, 1966, 2016], level='year')
10
11 In [56]: subtable.head()
12 Out[56]:
13 sex F M
14 year 1916 1966 2016 1916 1966 2016
15 last_letter
16 a 272225.0 616110.0 654193.0 3509.0 4630.0 29454.0
17 b NaN 100.0 645.0 1600.0 1732.0 26812.0
18 c 5.0 145.0 1284.0 1978.0 22036.0 21912.0
19 d 19035.0 3127.0 3418.0 118335.0 209457.0 42748.0
20 e 324987.0 364405.0 324067.0 108122.0 125970.0 125222.0
21
22 In [57]: subtable.sum()
23 Out[57]:
24 sex year
25 F 1916 1044335.0
26 1966 1691964.0
27 2016 1756647.0
28 M 1916 890100.0
29 1966 1783903.0
30 2016 1880674.0
31 dtype: float64
32
33 In [58]: letter_prop = subtable / subtable.sum().astype(float)
绘图
1 In [59]: import matplotlib.pyplot as plt
2
3 In [60]: fig, axes = plt.subplots(2, 1, figsize=(10, 8))
1 In [61]: letter_prop['M'].plot(kind='bar', rot=0, ax=axes[0], title='Male')
2 Out[61]: <matplotlib.axes._subplots.AxesSubplot at 0x3924ad68>
3
4 In [62]: letter_prop['F'].plot(kind='bar', rot=0, ax=axes[1], title='Female', legend=False)
5 Out[62]: <matplotlib.axes._subplots.AxesSubplot at 0x39340438>
回到之前创建的那个完整的表,按年度和性别对其进行规范化处理,并在男孩名字中选取几个字母,最后进行转置以便将各个列做成一个时间序列。
1 In [63]: letter_prop = table / table.sum().astype(float)
2
3 In [64]: dny_ts = letter_prop.loc[['d', 'n', 'y'], 'M'].T
4
5 In [65]: dny_ts.head()
6 Out[65]:
7 last_letter d n y
8 year
9 1880 0.083057 0.153216 0.075762
10 1881 0.083242 0.153212 0.077455
11 1882 0.085332 0.149561 0.077538
12 1883 0.084051 0.151653 0.079148
13 1884 0.086121 0.149926 0.080407
14
15 In [66]: dny_ts.plot()
16 Out[66]: <matplotlib.axes._subplots.AxesSubplot at 0x3c2737b8>
变成女孩名字的男孩名字
1 In [67]: all_names = top1000.name.unique()
2
3 In [68]: mask = np.array(['lesl' in x.lower() for x in all_names])
4
5 In [69]: lesley_like = all_names[mask]
6
7 In [70]: lesley_like
8 Out[70]: array(['Leslie', 'Lesley', 'Leslee', 'Lesli', 'Lesly'], dtype=object)
9
10 In [71]: filtered = top1000[top1000.name.isin(lesley_like)]
11
12 In [72]: filtered.groupby('name').number.sum()
13 Out[72]:
14 name
15 Leslee 993
16 Lesley 35032
17 Lesli 929
18 Leslie 376857
19 Lesly 11432
20 Name: number, dtype: int64
21
22 In [73]: table = filtered.pivot_table('number', index='year', columns='sex', aggfunc='sum')
23
24 In [74]: table = table.div(table.sum(1), axis=0)
25
26 In [75]: table.tail()
27 Out[75]:
28 sex F M
29 year
30 2012 1.0 NaN
31 2013 1.0 NaN
32 2014 1.0 NaN
33 2015 1.0 NaN
34 2016 1.0 NaN
35
36 In [76]: table.plot(style={'M': 'k-', 'F': 'k--'})
37 Out[76]: <matplotlib.axes._subplots.AxesSubplot at 0x3b1e2a58>