索引:
pandas.read_csv
pandas.concat
ignore_index=True
groupby或pivot_table进行聚合
np.allclose
计算prop的累计和cumsum
searchsorted
1880-2010年间全美婴儿姓名
由于这是一个非常标准的以逗号隔开的格式,所以可以用pandas.read_csv将其加载到DataFrame
import pandas as pd
names1880=pd.read_csv('C:\\pytest\\ch02\\names\\yob1880.txt',names=['name','sex','births'])
names1880
name | sex | births | |
---|---|---|---|
0 | Mary | F | 7065 |
1 | Anna | F | 2604 |
2 | Emma | F | 2003 |
3 | Elizabeth | F | 1939 |
4 | Minnie | F | 1746 |
5 | Margaret | F | 1578 |
6 | Ida | F | 1472 |
7 | Alice | F | 1414 |
8 | Bertha | F | 1320 |
9 | Sarah | F | 1288 |
10 | Annie | F | 1258 |
11 | Clara | F | 1226 |
12 | Ella | F | 1156 |
13 | Florence | F | 1063 |
14 | Cora | F | 1045 |
15 | Martha | F | 1040 |
16 | Laura | F | 1012 |
17 | Nellie | F | 995 |
18 | Grace | F | 982 |
19 | Carrie | F | 949 |
20 | Maude | F | 858 |
21 | Mabel | F | 808 |
22 | Bessie | F | 794 |
23 | Jennie | F | 793 |
24 | Gertrude | F | 787 |
25 | Julia | F | 783 |
26 | Hattie | F | 769 |
27 | Edith | F | 768 |
28 | Mattie | F | 704 |
29 | Rose | F | 700 |
… | … | … | … |
1970 | Philo | M | 5 |
1971 | Phineas | M | 5 |
1972 | Presley | M | 5 |
1973 | Ransom | M | 5 |
1974 | Reece | M | 5 |
1975 | Rene | M | 5 |
1976 | Roswell | M | 5 |
1977 | Rowland | M | 5 |
1978 | Sampson | M | 5 |
1979 | Samual | M | 5 |
1980 | Santos | M | 5 |
1981 | Schuyler | M | 5 |
1982 | Sheppard | M | 5 |
1983 | Spurgeon | M | 5 |
1984 | Starling | M | 5 |
1985 | Sylvanus | M | 5 |
1986 | Theadore | M | 5 |
1987 | Theophile | M | 5 |
1988 | Tilmon | M | 5 |
1989 | Tommy | M | 5 |
1990 | Unknown | M | 5 |
1991 | Vann | M | 5 |
1992 | Wes | M | 5 |
1993 | Winston | M | 5 |
1994 | Wood | M | 5 |
1995 | Woodie | M | 5 |
1996 | Worthy | M | 5 |
1997 | Wright | M | 5 |
1998 | York | M | 5 |
1999 | Zachariah | M | 5 |
2000 rows × 3 columns
用births列的sex分组小计表示该年度的births总计
names1880.groupby('sex').births.sum()
sex
F 90993
M 110493
Name: births, dtype: int64
由于该数据集按年度被分隔成对个文件,所以首先要将所有数据都组装到一个DataFrame里面,并加上一个year字段。使用pandas.concat即可达到这个目的。
years=range(1880,2011)
pieces=[]
columns=['name','sex','births']
for year in years:
path = 'C:\\pytest\\ch02\\names\\yob%d.txt' % year
frame = pd.read_csv(path,names=columns)
frame['year']=year
pieces.append(frame)
names = pd.concat(pieces,ignore_index=True)
注意:
第一,concat默认是按行将多个DataFrame组合到一起的;
第二,必须指定ignore_index=True,因为我们不希望保留read_csv所返回的原始行号。
现在我们就得到了一个非常大的DataFrame,它含有全部的名字数据。
names
name | sex | births | year | |
---|---|---|---|---|
0 | Mary | F | 7065 | 1880 |
1 | Anna | F | 2604 | 1880 |
2 | Emma | F | 2003 | 1880 |
3 | Elizabeth | F | 1939 | 1880 |
4 | Minnie | F | 1746 | 1880 |
5 | Margaret | F | 1578 | 1880 |
6 | Ida | F | 1472 | 1880 |
7 | Alice | F | 1414 | 1880 |
8 | Bertha | F | 1320 | 1880 |
9 | Sarah | F | 1288 | 1880 |
10 | Annie | F | 1258 | 1880 |
11 | Clara | F | 1226 | 1880 |
12 | Ella | F | 1156 | 1880 |
13 | Florence | F | 1063 | 1880 |
14 | Cora | F | 1045 | 1880 |
15 | Martha | F | 1040 | 1880 |
16 | Laura | F | 1012 | 1880 |
17 | Nellie | F | 995 | 1880 |
18 | Grace | F | 982 | 1880 |
19 | Carrie | F | 949 | 1880 |
20 | Maude | F | 858 | 1880 |
21 | Mabel | F | 808 | 1880 |
22 | Bessie | F | 794 | 1880 |
23 | Jennie | F | 793 | 1880 |
24 | Gertrude | F | 787 | 1880 |
25 | Julia | F | 783 | 1880 |
26 | Hattie | F | 769 | 1880 |
27 | Edith | F | 768 | 1880 |
28 | Mattie | F | 704 | 1880 |
29 | Rose | F | 700 | 1880 |
… | … | … | … | … |
1690754 | Zaviyon | M | 5 | 2010 |
1690755 | Zaybrien | M | 5 | 2010 |
1690756 | Zayshawn | M | 5 | 2010 |
1690757 | Zayyan | M | 5 | 2010 |
1690758 | Zeal | M | 5 | 2010 |
1690759 | Zealan | M | 5 | 2010 |
1690760 | Zecharia | M | 5 | 2010 |
1690761 | Zeferino | M | 5 | 2010 |
1690762 | Zekariah | M | 5 | 2010 |
1690763 | Zeki | M | 5 | 2010 |
1690764 | Zeriah | M | 5 | 2010 |
1690765 | Zeshan | M | 5 | 2010 |
1690766 | Zhyier | M | 5 | 2010 |
1690767 | Zildjian | M | 5 | 2010 |
1690768 | Zinn | M | 5 | 2010 |
1690769 | Zishan | M | 5 | 2010 |
1690770 | Ziven | M | 5 | 2010 |
1690771 | Zmari | M | 5 | 2010 |
1690772 | Zoren | M | 5 | 2010 |
1690773 | Zuhaib | M | 5 | 2010 |
1690774 | Zyeire | M | 5 | 2010 |
1690775 | Zygmunt | M | 5 | 2010 |
1690776 | Zykerion | M | 5 | 2010 |
1690777 | Zylar | M | 5 | 2010 |
1690778 | Zylin | M | 5 | 2010 |
1690779 | Zymaire | M | 5 | 2010 |
1690780 | Zyonne | M | 5 | 2010 |
1690781 | Zyquarius | M | 5 | 2010 |
1690782 | Zyran | M | 5 | 2010 |
1690783 | Zzyzx | M | 5 | 2010 |
1690784 rows × 4 columns
有了这些数据,我们就可以利用groupby或pivot_table在year和sex级别上对其进行聚合了。如图,按性别和年度统计的总出生数。
total_births = names.pivot_table('births',index='year',columns='sex',aggfunc=sum)
total_births.tail()
sex | F | M |
---|---|---|
year | ||
2006 | 1896468 | 2050234 |
2007 | 1916888 | 2069242 |
2008 | 1883645 | 2032310 |
2009 | 1827643 | 1973359 |
2010 | 1759010 | 1898382 |
import matplotlib.pyplot as plot
total_births.plot(title='Total births by sex and year')
plot.show()
下面插入一个prop列,用于存放指定名字的婴儿数相对于总出生数的比例。
def add_prop(group):
births = group.births.astype(float)
group['prop'] = births/births.sum()
return group
names = names.groupby(['year','sex']).apply(add_prop)
names
name | sex | births | year | prop | |
---|---|---|---|---|---|
0 | Mary | F | 7065 | 1880 | 0.077643 |
1 | Anna | F | 2604 | 1880 | 0.028618 |
2 | Emma | F | 2003 | 1880 | 0.022013 |
3 | Elizabeth | F | 1939 | 1880 | 0.021309 |
4 | Minnie | F | 1746 | 1880 | 0.019188 |
5 | Margaret | F | 1578 | 1880 | 0.017342 |
6 | Ida | F | 1472 | 1880 | 0.016177 |
7 | Alice | F | 1414 | 1880 | 0.015540 |
8 | Bertha | F | 1320 | 1880 | 0.014507 |
9 | Sarah | F | 1288 | 1880 | 0.014155 |
10 | Annie | F | 1258 | 1880 | 0.013825 |
11 | Clara | F | 1226 | 1880 | 0.013474 |
12 | Ella | F | 1156 | 1880 | 0.012704 |
13 | Florence | F | 1063 | 1880 | 0.011682 |
14 | Cora | F | 1045 | 1880 | 0.011484 |
15 | Martha | F | 1040 | 1880 | 0.011429 |
16 | Laura | F | 1012 | 1880 | 0.011122 |
17 | Nellie | F | 995 | 1880 | 0.010935 |
18 | Grace | F | 982 | 1880 | 0.010792 |
19 | Carrie | F | 949 | 1880 | 0.010429 |
20 | Maude | F | 858 | 1880 | 0.009429 |
21 | Mabel | F | 808 | 1880 | 0.008880 |
22 | Bessie | F | 794 | 1880 | 0.008726 |
23 | Jennie | F | 793 | 1880 | 0.008715 |
24 | Gertrude | F | 787 | 1880 | 0.008649 |
25 | Julia | F | 783 | 1880 | 0.008605 |
26 | Hattie | F | 769 | 1880 | 0.008451 |
27 | Edith | F | 768 | 1880 | 0.008440 |
28 | Mattie | F | 704 | 1880 | 0.007737 |
29 | Rose | F | 700 | 1880 | 0.007693 |
… | … | … | … | … | … |
1690754 | Zaviyon | M | 5 | 2010 | 0.000003 |
1690755 | Zaybrien | M | 5 | 2010 | 0.000003 |
1690756 | Zayshawn | M | 5 | 2010 | 0.000003 |
1690757 | Zayyan | M | 5 | 2010 | 0.000003 |
1690758 | Zeal | M | 5 | 2010 | 0.000003 |
1690759 | Zealan | M | 5 | 2010 | 0.000003 |
1690760 | Zecharia | M | 5 | 2010 | 0.000003 |
1690761 | Zeferino | M | 5 | 2010 | 0.000003 |
1690762 | Zekariah | M | 5 | 2010 | 0.000003 |
1690763 | Zeki | M | 5 | 2010 | 0.000003 |
1690764 | Zeriah | M | 5 | 2010 | 0.000003 |
1690765 | Zeshan | M | 5 | 2010 | 0.000003 |
1690766 | Zhyier | M | 5 | 2010 | 0.000003 |
1690767 | Zildjian | M | 5 | 2010 | 0.000003 |
1690768 | Zinn | M | 5 | 2010 | 0.000003 |
1690769 | Zishan | M | 5 | 2010 | 0.000003 |
1690770 | Ziven | M | 5 | 2010 | 0.000003 |
1690771 | Zmari | M | 5 | 2010 | 0.000003 |
1690772 | Zoren | M | 5 | 2010 | 0.000003 |
1690773 | Zuhaib | M | 5 | 2010 | 0.000003 |
1690774 | Zyeire | M | 5 | 2010 | 0.000003 |
1690775 | Zygmunt | M | 5 | 2010 | 0.000003 |
1690776 | Zykerion | M | 5 | 2010 | 0.000003 |
1690777 | Zylar | M | 5 | 2010 | 0.000003 |
1690778 | Zylin | M | 5 | 2010 | 0.000003 |
1690779 | Zymaire | M | 5 | 2010 | 0.000003 |
1690780 | Zyonne | M | 5 | 2010 | 0.000003 |
1690781 | Zyquarius | M | 5 | 2010 | 0.000003 |
1690782 | Zyran | M | 5 | 2010 | 0.000003 |
1690783 | Zzyzx | M | 5 | 2010 | 0.000003 |
1690784 rows × 5 columns
在执行这样的分组处理时,一般都应该做一些有效性检查。由于这是一个浮点型数据,所以可以用np.allclose来检查这个分组总计值是否足够近似于1
import numpy as np
np.allclose(names.groupby(['year','sex']).prop.sum(),1)
True
为了便于进一步分析,取出该数据的一个子集:每对sex/year组合的前1000个名字。这也是一个分组操作。
def get_top1000(group):
return group.sort_index(by='births',ascending=False)[:1000]
grouped = names.groupby(['year','sex'])
top1000 = grouped.apply(get_top1000)
C:\Anaconda3\lib\site-packages\ipykernel\__main__.py:2: FutureWarning: by argument to sort_index is deprecated, pls use .sort_values(by=...)
from ipykernel import kernelapp as app
top1000
name | sex | births | year | prop | |||
---|---|---|---|---|---|---|---|
year | sex | ||||||
1880 | F | 0 | Mary | F | 7065 | 1880 | 0.077643 |
1 | Anna | F | 2604 | 1880 | 0.028618 | ||
2 | Emma | F | 2003 | 1880 | 0.022013 | ||
3 | Elizabeth | F | 1939 | 1880 | 0.021309 | ||
4 | Minnie | F | 1746 | 1880 | 0.019188 | ||
5 | Margaret | F | 1578 | 1880 | 0.017342 | ||
6 | Ida | F | 1472 | 1880 | 0.016177 | ||
7 | Alice | F | 1414 | 1880 | 0.015540 | ||
8 | Bertha | F | 1320 | 1880 | 0.014507 | ||
9 | Sarah | F | 1288 | 1880 | 0.014155 | ||
10 | Annie | F | 1258 | 1880 | 0.013825 | ||
11 | Clara | F | 1226 | 1880 | 0.013474 | ||
12 | Ella | F | 1156 | 1880 | 0.012704 | ||
13 | Florence | F | 1063 | 1880 | 0.011682 | ||
14 | Cora | F | 1045 | 1880 | 0.011484 | ||
15 | Martha | F | 1040 | 1880 | 0.011429 | ||
16 | Laura | F | 1012 | 1880 | 0.011122 | ||
17 | Nellie | F | 995 | 1880 | 0.010935 | ||
18 | Grace | F | 982 | 1880 | 0.010792 | ||
19 | Carrie | F | 949 | 1880 | 0.010429 | ||
20 | Maude | F | 858 | 1880 | 0.009429 | ||
21 | Mabel | F | 808 | 1880 | 0.008880 | ||
22 | Bessie | F | 794 | 1880 | 0.008726 | ||
23 | Jennie | F | 793 | 1880 | 0.008715 | ||
24 | Gertrude | F | 787 | 1880 | 0.008649 | ||
25 | Julia | F | 783 | 1880 | 0.008605 | ||
26 | Hattie | F | 769 | 1880 | 0.008451 | ||
27 | Edith | F | 768 | 1880 | 0.008440 | ||
28 | Mattie | F | 704 | 1880 | 0.007737 | ||
29 | Rose | F | 700 | 1880 | 0.007693 | ||
… | … | … | … | … | … | … | … |
2010 | M | 1677617 | Yair | M | 201 | 2010 | 0.000106 |
1677616 | Talan | M | 201 | 2010 | 0.000106 | ||
1677614 | Keyon | M | 201 | 2010 | 0.000106 | ||
1677613 | Kael | M | 201 | 2010 | 0.000106 | ||
1677618 | Demarion | M | 200 | 2010 | 0.000105 | ||
1677619 | Gibson | M | 200 | 2010 | 0.000105 | ||
1677620 | Reagan | M | 200 | 2010 | 0.000105 | ||
1677621 | Cristofer | M | 199 | 2010 | 0.000105 | ||
1677622 | Daylen | M | 199 | 2010 | 0.000105 | ||
1677623 | Jordon | M | 199 | 2010 | 0.000105 | ||
1677624 | Dashawn | M | 198 | 2010 | 0.000104 | ||
1677625 | Masen | M | 198 | 2010 | 0.000104 | ||
1677629 | Rowen | M | 197 | 2010 | 0.000104 | ||
1677631 | Yousef | M | 197 | 2010 | 0.000104 | ||
1677630 | Thaddeus | M | 197 | 2010 | 0.000104 | ||
1677628 | Kadin | M | 197 | 2010 | 0.000104 | ||
1677627 | Dillan | M | 197 | 2010 | 0.000104 | ||
1677626 | Clarence | M | 197 | 2010 | 0.000104 | ||
1677634 | Slade | M | 196 | 2010 | 0.000103 | ||
1677632 | Clinton | M | 196 | 2010 | 0.000103 | ||
1677633 | Sheldon | M | 196 | 2010 | 0.000103 | ||
1677636 | Keshawn | M | 195 | 2010 | 0.000103 | ||
1677637 | Menachem | M | 195 | 2010 | 0.000103 | ||
1677635 | Joziah | M | 195 | 2010 | 0.000103 | ||
1677638 | Bailey | M | 194 | 2010 | 0.000102 | ||
1677639 | Camilo | M | 194 | 2010 | 0.000102 | ||
1677640 | Destin | M | 194 | 2010 | 0.000102 | ||
1677641 | Jaquan | M | 194 | 2010 | 0.000102 | ||
1677642 | Jaydan | M | 194 | 2010 | 0.000102 | ||
1677645 | Maxton | M | 193 | 2010 | 0.000102 |
261877 rows × 5 columns
分析命名趋势
利用刚才生产的top1000数据集,就可以开始分析各种命名趋势。
boys=top1000[top1000.sex == 'M']
girls=top1000[top1000.sex == 'F']
import matplotlib.pyplot as plot
total_births = top1000.pivot_table('births',index='year',columns='name',aggfunc=sum)
total_births
name | Aaden | Aaliyah | Aarav | Aaron | Aarush | Ab | Abagail | Abb | Abbey | Abbie | … | Zoa | Zoe | Zoey | Zoie | Zola | Zollie | Zona | Zora | Zula | Zuri |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
year | |||||||||||||||||||||
1880 | NaN | NaN | NaN | 102.0 | NaN | NaN | NaN | NaN | NaN | 71.0 | … | 8.0 | 23.0 | NaN | NaN | 7.0 | NaN | 8.0 | 28.0 | 27.0 | NaN |
1881 | NaN | NaN | NaN | 94.0 | NaN | NaN | NaN | NaN | NaN | 81.0 | … | NaN | 22.0 | NaN | NaN | 10.0 | NaN | 9.0 | 21.0 | 27.0 | NaN |
1882 | NaN | NaN | NaN | 85.0 | NaN | NaN | NaN | NaN | NaN | 80.0 | … | 8.0 | 25.0 | NaN | NaN | 9.0 | NaN | 17.0 | 32.0 | 21.0 | NaN |
1883 | NaN | NaN | NaN | 105.0 | NaN | NaN | NaN | NaN | NaN | 79.0 | … | NaN | 23.0 | NaN | NaN | 10.0 | NaN | 11.0 | 35.0 | 25.0 | NaN |
1884 | NaN | NaN | NaN | 97.0 | NaN | NaN | NaN | NaN | NaN | 98.0 | … | 13.0 | 31.0 | NaN | NaN | 14.0 | 6.0 | 8.0 | 58.0 | 27.0 | NaN |
1885 | NaN | NaN | NaN | 88.0 | NaN | 6.0 | NaN | NaN | NaN | 88.0 | … | 6.0 | 27.0 | NaN | NaN | 12.0 | 6.0 | 14.0 | 48.0 | 38.0 | NaN |
1886 | NaN | NaN | NaN | 86.0 | NaN | NaN | NaN | NaN | NaN | 84.0 | … | 13.0 | 25.0 | NaN | NaN | 8.0 | NaN | 20.0 | 52.0 | 43.0 | NaN |
1887 | NaN | NaN | NaN | 78.0 | NaN | NaN | NaN | NaN | NaN | 104.0 | … | 9.0 | 34.0 | NaN | NaN | 23.0 | NaN | 28.0 | 46.0 | 33.0 | NaN |
1888 | NaN | NaN | NaN | 90.0 | NaN | NaN | NaN | NaN | NaN | 137.0 | … | 11.0 | 42.0 | NaN | NaN | 23.0 | 7.0 | 30.0 | 42.0 | 45.0 | NaN |
1889 | NaN | NaN | NaN | 85.0 | NaN | NaN | NaN | NaN | NaN | 107.0 | … | 14.0 | 29.0 | NaN | NaN | 22.0 | NaN | 29.0 | 53.0 | 55.0 | NaN |
1890 | NaN | NaN | NaN | 96.0 | NaN | NaN | NaN | 6.0 | NaN | 140.0 | … | NaN | 42.0 | NaN | NaN | 32.0 | 7.0 | 27.0 | 60.0 | 65.0 | NaN |
1891 | NaN | NaN | NaN | 69.0 | NaN | NaN | NaN | NaN | NaN | 124.0 | … | NaN | 34.0 | NaN | NaN | 29.0 | 6.0 | 14.0 | 52.0 | 45.0 | NaN |
1892 | NaN | NaN | NaN | 95.0 | NaN | NaN | NaN | NaN | NaN | 119.0 | … | NaN | 34.0 | NaN | NaN | 27.0 | NaN | 25.0 | 66.0 | 53.0 | NaN |
1893 | NaN | NaN | NaN | 81.0 | NaN | NaN | NaN | NaN | NaN | 115.0 | … | NaN | 23.0 | NaN | NaN | 34.0 | 6.0 | 15.0 | 67.0 | 70.0 | NaN |
1894 | NaN | NaN | NaN | 79.0 | NaN | NaN | NaN | NaN | NaN | 118.0 | … | NaN | 28.0 | NaN | NaN | 51.0 | NaN | 23.0 | 66.0 | 64.0 | NaN |
1895 | NaN | NaN | NaN | 94.0 | NaN | NaN | NaN | NaN | NaN | 92.0 | … | NaN | 34.0 | NaN | NaN | 60.0 | 11.0 | 38.0 | 55.0 | 55.0 | NaN |
1896 | NaN | NaN | NaN | 69.0 | NaN | NaN | NaN | NaN | NaN | 121.0 | … | NaN | 36.0 | NaN | NaN | 47.0 | NaN | 38.0 | 72.0 | 65.0 | NaN |
1897 | NaN | NaN | NaN | 87.0 | NaN | NaN | NaN | NaN | NaN | 97.0 | … | NaN | 35.0 | NaN | NaN | 51.0 | NaN | 28.0 | 67.0 | 79.0 | NaN |
1898 | NaN | NaN | NaN | 89.0 | NaN | NaN | NaN | NaN | NaN | 120.0 | … | NaN | 30.0 | NaN | NaN | 62.0 | NaN | 28.0 | 65.0 | 83.0 | NaN |
1899 | NaN | NaN | NaN | 71.0 | NaN | NaN | NaN | NaN | NaN | 87.0 | … | NaN | 27.0 | NaN | NaN | 49.0 | 6.0 | 31.0 | 56.0 | 60.0 | NaN |
1900 | NaN | NaN | NaN | 104.0 | NaN | NaN | NaN | NaN | NaN | 112.0 | … | NaN | 26.0 | NaN | NaN | 48.0 | 9.0 | 44.0 | 99.0 | 71.0 | NaN |
1901 | NaN | NaN | NaN | 80.0 | NaN | NaN | NaN | NaN | NaN | 87.0 | … | NaN | 26.0 | NaN | NaN | 56.0 | NaN | 31.0 | 58.0 | 57.0 | NaN |
1902 | NaN | NaN | NaN | 78.0 | NaN | NaN | NaN | NaN | NaN | 91.0 | … | NaN | 34.0 | NaN | NaN | 58.0 | NaN | 23.0 | 58.0 | 66.0 | NaN |
1903 | NaN | NaN | NaN | 93.0 | NaN | NaN | NaN | NaN | NaN | 91.0 | … | NaN | 19.0 | NaN | NaN | 64.0 | NaN | 41.0 | 83.0 | 74.0 | NaN |
1904 | NaN | NaN | NaN | 117.0 | NaN | NaN | NaN | NaN | NaN | 80.0 | … | NaN | 27.0 | NaN | NaN | 46.0 | NaN | 35.0 | 54.0 | 74.0 | NaN |
1905 | NaN | NaN | NaN | 96.0 | NaN | NaN | NaN | NaN | NaN | 73.0 | … | NaN | 24.0 | NaN | NaN | 66.0 | 8.0 | 24.0 | 55.0 | 61.0 | NaN |
1906 | NaN | NaN | NaN | 96.0 | NaN | NaN | NaN | NaN | NaN | 72.0 | … | NaN | 19.0 | NaN | NaN | 59.0 | NaN | 37.0 | 64.0 | 58.0 | NaN |
1907 | NaN | NaN | NaN | 130.0 | NaN | NaN | NaN | NaN | NaN | 79.0 | … | NaN | 19.0 | NaN | NaN | 53.0 | 11.0 | 39.0 | 92.0 | 72.0 | NaN |
1908 | NaN | NaN | NaN | 114.0 | NaN | NaN | NaN | NaN | NaN | 84.0 | … | NaN | 23.0 | NaN | NaN | 70.0 | NaN | 31.0 | 59.0 | 53.0 | NaN |
1909 | NaN | NaN | NaN | 142.0 | NaN | NaN | NaN | NaN | NaN | 57.0 | … | NaN | 22.0 | NaN | NaN | 59.0 | NaN | 39.0 | 57.0 | 76.0 | NaN |
… | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … |
1981 | NaN | NaN | NaN | 14832.0 | NaN | NaN | NaN | NaN | 383.0 | 292.0 | … | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1982 | NaN | NaN | NaN | 14538.0 | NaN | NaN | NaN | NaN | 372.0 | 275.0 | … | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1983 | NaN | NaN | NaN | 14627.0 | NaN | NaN | NaN | NaN | 419.0 | 223.0 | … | NaN | 174.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1984 | NaN | NaN | NaN | 13387.0 | NaN | NaN | NaN | NaN | 357.0 | 249.0 | … | NaN | 200.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1985 | NaN | NaN | NaN | 13123.0 | NaN | NaN | NaN | NaN | 314.0 | 233.0 | … | NaN | 193.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1986 | NaN | NaN | NaN | 12685.0 | NaN | NaN | NaN | NaN | 369.0 | 228.0 | … | NaN | 213.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1987 | NaN | NaN | NaN | 12676.0 | NaN | NaN | NaN | NaN | 327.0 | 228.0 | … | NaN | 248.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1988 | NaN | NaN | NaN | 14393.0 | NaN | NaN | NaN | NaN | 404.0 | 226.0 | … | NaN | 238.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1989 | NaN | NaN | NaN | 15312.0 | NaN | NaN | NaN | NaN | 470.0 | 265.0 | … | NaN | 376.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1990 | NaN | NaN | NaN | 14545.0 | NaN | NaN | NaN | NaN | 507.0 | 311.0 | … | NaN | 478.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1991 | NaN | NaN | NaN | 14240.0 | NaN | NaN | NaN | NaN | 451.0 | 278.0 | … | NaN | 722.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1992 | NaN | NaN | NaN | 14494.0 | NaN | NaN | NaN | NaN | 430.0 | 260.0 | … | NaN | 978.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1993 | NaN | NaN | NaN | 13819.0 | NaN | NaN | NaN | NaN | 503.0 | 291.0 | … | NaN | 1194.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1994 | NaN | 1451.0 | NaN | 14379.0 | NaN | NaN | NaN | NaN | 597.0 | 351.0 | … | NaN | 1332.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1995 | NaN | 1254.0 | NaN | 13277.0 | NaN | NaN | NaN | NaN | 549.0 | 351.0 | … | NaN | 1726.0 | 219.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1996 | NaN | 831.0 | NaN | 11956.0 | NaN | NaN | NaN | NaN | 552.0 | 349.0 | … | NaN | 2063.0 | 339.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1997 | NaN | 1737.0 | NaN | 11156.0 | NaN | NaN | NaN | NaN | 645.0 | 386.0 | … | NaN | 2363.0 | 407.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1998 | NaN | 1399.0 | NaN | 10539.0 | NaN | NaN | NaN | NaN | 661.0 | 398.0 | … | NaN | 2690.0 | 478.0 | 225.0 | NaN | NaN | NaN | NaN | NaN | NaN |
1999 | NaN | 1088.0 | NaN | 9846.0 | NaN | NaN | 211.0 | NaN | 710.0 | 430.0 | … | NaN | 3238.0 | 561.0 | 257.0 | NaN | NaN | NaN | NaN | NaN | NaN |
2000 | NaN | 1494.0 | NaN | 9548.0 | NaN | NaN | 222.0 | NaN | 660.0 | 432.0 | … | NaN | 3783.0 | 691.0 | 320.0 | NaN | NaN | NaN | NaN | NaN | NaN |
2001 | NaN | 3351.0 | NaN | 9529.0 | NaN | NaN | 244.0 | NaN | 687.0 | 526.0 | … | NaN | 4642.0 | 822.0 | 439.0 | NaN | NaN | NaN | NaN | NaN | NaN |
2002 | NaN | 4775.0 | NaN | 8993.0 | NaN | NaN | 256.0 | NaN | 600.0 | 514.0 | … | NaN | 4883.0 | 1182.0 | 438.0 | NaN | NaN | NaN | NaN | NaN | NaN |
2003 | NaN | 3670.0 | NaN | 8851.0 | NaN | NaN | 276.0 | NaN | 625.0 | 536.0 | … | NaN | 5080.0 | 1465.0 | 448.0 | NaN | NaN | NaN | NaN | NaN | NaN |
2004 | NaN | 3482.0 | NaN | 8381.0 | NaN | NaN | 258.0 | NaN | 504.0 | 500.0 | … | NaN | 5359.0 | 1621.0 | 515.0 | NaN | NaN | NaN | NaN | NaN | NaN |
2005 | NaN | 3452.0 | NaN | 7796.0 | NaN | NaN | 287.0 | NaN | 451.0 | 445.0 | … | NaN | 4953.0 | 2266.0 | 502.0 | NaN | NaN | NaN | NaN | NaN | NaN |
2006 | NaN | 3737.0 | NaN | 8279.0 | NaN | NaN | 297.0 | NaN | 404.0 | 440.0 | … | NaN | 5145.0 | 2839.0 | 530.0 | NaN | NaN | NaN | NaN | NaN | NaN |
2007 | NaN | 3941.0 | NaN | 8914.0 | NaN | NaN | 313.0 | NaN | 349.0 | 468.0 | … | NaN | 4925.0 | 3028.0 | 526.0 | NaN | NaN | NaN | NaN | NaN | NaN |
2008 | 955.0 | 4028.0 | 219.0 | 8511.0 | NaN | NaN | 317.0 | NaN | 344.0 | 400.0 | … | NaN | 4764.0 | 3438.0 | 492.0 | NaN | NaN | NaN | NaN | NaN | NaN |
2009 | 1265.0 | 4352.0 | 270.0 | 7936.0 | NaN | NaN | 296.0 | NaN | 307.0 | 369.0 | … | NaN | 5120.0 | 3981.0 | 496.0 | NaN | NaN | NaN | NaN | NaN | NaN |
2010 | 448.0 | 4628.0 | 438.0 | 7374.0 | 226.0 | NaN | 277.0 | NaN | 295.0 | 324.0 | … | NaN | 6200.0 | 5164.0 | 504.0 | NaN | NaN | NaN | NaN | NaN | 258.0 |
131 rows × 6868 columns
用DataFrame的plot方法绘制几个名字的曲线图:
subset=total_births[['John','Harry','Mary','Marilyn']]
subset.plot(subplots=True,figsize=(12,10),grid=False,title="Number of births per year")
array([<matplotlib.axes._subplots.AxesSubplot object at 0x0000027F80E4F908>,
<matplotlib.axes._subplots.AxesSubplot object at 0x0000027F80E508D0>,
<matplotlib.axes._subplots.AxesSubplot object at 0x0000027F80F4FDA0>,
<matplotlib.axes._subplots.AxesSubplot object at 0x0000027F80E9DEB8>], dtype=object)
plot.show()
评估命名多样性的增长
计算最流行的1000个名字所占比例,按year和sex进行聚合并绘图
table=top1000.pivot_table('prop',index='year',columns='sex',aggfunc=sum)
table.plot(title='Sum of table1000.prop by year and sex',yticks=np.linspace(0,1.2,13),xticks=range(1880,2020,10))
plot.show()
df=boys[boys.year==2010]
df
name | sex | births | year | prop | |||
---|---|---|---|---|---|---|---|
year | sex | ||||||
2010 | M | 1676644 | Jacob | M | 21875 | 2010 | 0.011523 |
1676645 | Ethan | M | 17866 | 2010 | 0.009411 | ||
1676646 | Michael | M | 17133 | 2010 | 0.009025 | ||
1676647 | Jayden | M | 17030 | 2010 | 0.008971 | ||
1676648 | William | M | 16870 | 2010 | 0.008887 | ||
1676649 | Alexander | M | 16634 | 2010 | 0.008762 | ||
1676650 | Noah | M | 16281 | 2010 | 0.008576 | ||
1676651 | Daniel | M | 15679 | 2010 | 0.008259 | ||
1676652 | Aiden | M | 15403 | 2010 | 0.008114 | ||
1676653 | Anthony | M | 15364 | 2010 | 0.008093 | ||
1676654 | Joshua | M | 15238 | 2010 | 0.008027 | ||
1676655 | Mason | M | 14728 | 2010 | 0.007758 | ||
1676656 | Christopher | M | 14135 | 2010 | 0.007446 | ||
1676657 | Andrew | M | 14093 | 2010 | 0.007424 | ||
1676658 | David | M | 14042 | 2010 | 0.007397 | ||
1676659 | Matthew | M | 13954 | 2010 | 0.007350 | ||
1676660 | Logan | M | 13943 | 2010 | 0.007345 | ||
1676661 | Elijah | M | 13735 | 2010 | 0.007235 | ||
1676662 | James | M | 13714 | 2010 | 0.007224 | ||
1676663 | Joseph | M | 13657 | 2010 | 0.007194 | ||
1676664 | Gabriel | M | 12722 | 2010 | 0.006701 | ||
1676665 | Benjamin | M | 12280 | 2010 | 0.006469 | ||
1676666 | Ryan | M | 11886 | 2010 | 0.006261 | ||
1676667 | Samuel | M | 11776 | 2010 | 0.006203 | ||
1676668 | Jackson | M | 11693 | 2010 | 0.006159 | ||
1676669 | John | M | 11424 | 2010 | 0.006018 | ||
1676670 | Nathan | M | 11269 | 2010 | 0.005936 | ||
1676671 | Jonathan | M | 11028 | 2010 | 0.005809 | ||
1676672 | Christian | M | 10965 | 2010 | 0.005776 | ||
1676673 | Liam | M | 10852 | 2010 | 0.005716 | ||
… | … | … | … | … | … | ||
… | Yair | M | 201 | 2010 | 0.000106 | ||
1677617 | Talan | M | 201 | 2010 | 0.000106 | ||
1677616 | Keyon | M | 201 | 2010 | 0.000106 | ||
1677614 | Kael | M | 201 | 2010 | 0.000106 | ||
1677613 | Demarion | M | 200 | 2010 | 0.000105 | ||
1677618 | Gibson | M | 200 | 2010 | 0.000105 | ||
1677619 | Reagan | M | 200 | 2010 | 0.000105 | ||
1677620 | Cristofer | M | 199 | 2010 | 0.000105 | ||
1677621 | Daylen | M | 199 | 2010 | 0.000105 | ||
1677622 | Jordon | M | 199 | 2010 | 0.000105 | ||
1677623 | Dashawn | M | 198 | 2010 | 0.000104 | ||
1677624 | Masen | M | 198 | 2010 | 0.000104 | ||
1677625 | Rowen | M | 197 | 2010 | 0.000104 | ||
1677629 | Yousef | M | 197 | 2010 | 0.000104 | ||
1677631 | Thaddeus | M | 197 | 2010 | 0.000104 | ||
1677630 | Kadin | M | 197 | 2010 | 0.000104 | ||
1677628 | Dillan | M | 197 | 2010 | 0.000104 | ||
1677627 | Clarence | M | 197 | 2010 | 0.000104 | ||
1677626 | Slade | M | 196 | 2010 | 0.000103 | ||
1677634 | Clinton | M | 196 | 2010 | 0.000103 | ||
1677632 | Sheldon | M | 196 | 2010 | 0.000103 | ||
1677633 | Keshawn | M | 195 | 2010 | 0.000103 | ||
1677636 | Menachem | M | 195 | 2010 | 0.000103 | ||
1677637 | Joziah | M | 195 | 2010 | 0.000103 | ||
1677635 | Bailey | M | 194 | 2010 | 0.000102 | ||
1677638 | Camilo | M | 194 | 2010 | 0.000102 | ||
1677639 | Destin | M | 194 | 2010 | 0.000102 | ||
1677640 | Jaquan | M | 194 | 2010 | 0.000102 | ||
1677641 | Jaydan | M | 194 | 2010 | 0.000102 | ||
1677642 | Maxton | M | 193 | 2010 | 0.000102 |
1000 rows × 5 columns
在对prop降序排列后,我们想知道前面有多少个名字的人数加起来才够50%。虽然编写一个for循环确实也能达到目的,但NumPy有一种更聪明的矢量方式。先计算prop的累计和cumsum,然后通过searchsorted方法找出0.5应该被插入在哪个位置才能保证不破坏顺序。
prop_cumsum=df.sort_index(by='prop',ascending=False).prop.cumsum()
C:\Anaconda3\lib\site-packages\ipykernel\__main__.py:1: FutureWarning: by argument to sort_index is deprecated, pls use .sort_values(by=…) if __name__ == ‘__main__’:
prop_cumsum[:10]
year sex
2010 M 1676644 0.011523
1676645 0.020934
1676646 0.029959
1676647 0.038930
1676648 0.047817
1676649 0.056579
1676650 0.065155
1676651 0.073414
1676652 0.081528
1676653 0.089621
Name: prop, dtype: float64
prop_cumsum.searchsorted(0.5)
array([116], dtype=int64)
df=boys[boys.year==1900]
in1900=df.sort_index(by='prop',ascending=False).prop.cumsum()
in1900.searchsorted(0.5)+1
C:\Anaconda3\lib\site-packages\ipykernel\__main__.py:2: FutureWarning: by argument to sort_index is deprecated, pls use .sort_values(by=...)
from ipykernel import kernelapp as app
array([25], dtype=int64)
按这两个字段进行groupby处理,然后用一个函数计算各分组的这个值。
def get_quantile_count(group,q=0.5):
group=group.sort_index(by='prop',ascending=False)
return group.prop.cumsum().searchsorted(0.5)[0]+1 #注意这里和书上不一样
diversity=top1000.groupby(['year','sex']).apply(get_quantile_count)
diversity=diversity.unstack('sex') #依靠Sex入栈操纵,变Series为DataFrame
C:\Anaconda3\lib\site-packages\ipykernel\__main__.py:2: FutureWarning: by argument to sort_index is deprecated, pls use .sort_values(by=...)
from ipykernel import kernelapp as app
现在,diversity这个DataFrame拥有两个时间序列(每个性别各一个,按年度索引)。
diversity.head()
sex | F | M |
---|---|---|
year | ||
1880 | 38 | 14 |
1881 | 38 | 14 |
1882 | 38 | 15 |
1883 | 39 | 15 |
1884 | 39 | 16 |
diversity.plot(title="Number of popular names in top 50%")
plot.show()
“最后一个字母”的变革
从name列取出最后一个字母
get_last_letter=lambda x:x[-1]
last_letters=names.name.map(get_last_letter)
last_letters.name='last_letter'
table=names.pivot_table('births',index=last_letters,columns=['sex','year'],aggfunc=sum)
subtable=table.reindex(columns=[1910,1960,2010],level='year')
subtable.head()
sex | F | M | ||||
---|---|---|---|---|---|---|
year | 1910 | 1960 | 2010 | 1910 | 1960 | 2010 |
last_letter | ||||||
a | 108376.0 | 691247.0 | 670605.0 | 977.0 | 5204.0 | 28438.0 |
b | NaN | 694.0 | 450.0 | 411.0 | 3912.0 | 38859.0 |
c | 5.0 | 49.0 | 946.0 | 482.0 | 15476.0 | 23125.0 |
d | 6750.0 | 3729.0 | 2607.0 | 22111.0 | 262112.0 | 44398.0 |
e | 133569.0 | 435013.0 | 313833.0 | 28655.0 | 178823.0 | 129012.0 |
按总出生人数对该表进行规范化处理:
subtable.sum()
sex year
F 1910 396416.0
1960 2022062.0
2010 1759010.0
M 1910 194198.0
1960 2132588.0
2010 1898382.0
dtype: float64
有了这个字母比例数据后,就可以生产一张各年度各性别的条形图了。
letter_prop=subtable/subtable.sum().astype(float)
import matplotlib.pyplot as plt
fig,axes=plt.subplots(2,1,figsize=(10,8))
letter_prop['M'].plot(kind='bar',rot=0,ax=axes[0],title='Male')
letter_prop['F'].plot(kind='bar',rot=0,ax=axes[1],title='Female',legend=False)
plt.show()
回到之前创建的那个完整的表,按年度和性别对其进行规范化处理,并在男孩名字中选取几个字母,最后进行转置以便将各个列做成一个时间序列:
letter_prop=table/table.sum().astype(float)
dny_ts=letter_prop.ix[['d','n','y'],'M'].T
dny_ts.head()
last_letter | d | n | y |
---|---|---|---|
year | |||
1880 | 0.083055 | 0.153213 | 0.075760 |
1881 | 0.083247 | 0.153214 | 0.077451 |
1882 | 0.085340 | 0.149560 | 0.077537 |
1883 | 0.084066 | 0.151646 | 0.079144 |
1884 | 0.086120 | 0.149915 | 0.080405 |
有了这个时间序列的DataFrame之后,就可以通过其plot方法绘制出一张趋势图了:
dny_ts.plot()
plt.show()
变成女孩名字的男孩名字(以及相反的情况)
all_names=top1000.name.unique()
mask=np.array(['lesl'in x.lower() for x in all_names])
lesley_like=all_names[mask]
lesley_like
array(['Leslie', 'Lesley', 'Leslee', 'Lesli', 'Lesly'], dtype=object)
利用这个结果过滤其他的名字,并按名字分组计算出生数以查看相对频率:
filtered=top1000[top1000.name.isin(lesley_like)]
filtered.groupby('name').births.sum()
name
Leslee 1082
Lesley 35022
Lesli 929
Leslie 370429
Lesly 10067
Name: births, dtype: int64
接下来按性别和年度进行聚合,并按年度进行规范化处理:
table=filtered.pivot_table('births',index='year',columns='sex',aggfunc='sum')
table=table.div(table.sum(1),axis=0)
table.tail()
sex | F | M |
---|---|---|
year | ||
2006 | 1.0 | NaN |
2007 | 1.0 | NaN |
2008 | 1.0 | NaN |
2009 | 1.0 | NaN |
2010 | 1.0 | NaN |
绘制分性别的年度曲线图:
table.plot(style={'M':'k-','F':'k--'})
plt.show()