Python for Data Analysis | Names

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>

 

Reference

01 http://blog.csdn.net/u010456562/article/details/51346594

posted @ 2017-09-06 13:59  PrinceMay  阅读(818)  评论(0编辑  收藏  举报