#全美婴儿案例
数据集可以做很多事儿:
1、计算指定名字(可以是自己的,也可以是别人的)的年度比例
2、计算某个名字的相对排名
3、计算各年度最流行的名字,以及增长或减少最快的名字
4、分析名字趋势:元音、辅音、长度、总体多样性、拼写变化、首尾字母等
5、分析外源性趋势:圣经中的名字、名人、人口结构变化等
#为什么用read_table增加标题就会多增加两列?
names1880=pd.read_csv('E:/yob1880.txt',names=['name','sex','births'])
names1880[:10]
#用births列的sex组小计表示该年度的births总计
names1880.groupby('sex').births.sum()
#将各年度的数据整合在一个数据框中,用pandas.concat函数即可
#2010是目前最后一个有效的统计年度
years=range(1880,2011)
pieces=[]
columns=['name','sex','births']
for year in years:
path='E:/names/yob%d.txt' % year
frame=pd.read_csv(path,names=columns)
frame['year']=year
pieces.append(frame)
#将所有数据整合到单个DataFrame中
names_new=pd.concat(pieces,ignore_index=True)
#利用groupby和pivot_table在year和sex级进行聚合
total_births=names_new.pivot_table('births',index='year',columns='sex',aggfunc=sum)
total_births
#插入prob列,存放指定的婴儿数相对于总出生数的比例
def add_prop(group):
births=group.births.astype(float)
group['prop']=births/births.sum()
return group
names_new=names_new.groupby(['year','sex']).apply(add_prop)
names_new[:10]
#检查:验证所有的prob总和是否为1
import numpy as np
np.allclose(names_new.groupby(['year','sex']).prop.sum(),1)
#取数据子集,每对sex/year组合的前1000个名字
def get_top1000(group):
return group.sort_values(by='births',ascending=False)[:1000]
grouped=names_new.groupby(['year','sex'])
top1000=grouped.apply(get_top1000)
#将前1000个名字分为男女两个部分
boys=top1000[top1000.sex=='M']
girls=top1000[top1000.sex=='F']
#生成一个按year和name统计的总出生数据透视表
total_births=top1000.pivot_table('births',index='year',columns='name',aggfunc=sum)
subset=total_births[['John','Harry','Mary','Marilyn']]
%matplotlib inline
subset.plot(subplots=True,figsize=(12,10),grid=False,title="Number of births per year")
#评估命名多样性的增长,计算最流行的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))
#计算总出生人数前50%的不同名字的数量,只考虑2010年男孩的名字
df=boys[boys.year==2010]
#对prop降序,先计算prob的累计和cumsum,通过searchsorted找出0.5应该被插在哪里
prop_cumsum=df.sort_values(by='prop',ascending=False).prop.cumsum()
prop_cumsum[:10]
prop_cumsum.searchsorted(0.5)
#索引从0开始,应该+1,共117个。拿1900年比较,这个值要小的多,仅为25
df=boys[boys.year==1900]
prop_cumsum=df.sort_values(by='prop',ascending=False).prop.cumsum()
prop_cumsum.searchsorted(0.5)+1
def get_quantile_count(group,q=0.5):
group=group.sort_values(by='prop',ascending=False)
return group.prop.cumsum().searchsorted(q)[0]+1
#注意searchsorted(q)[0]需要先取[0]操作,否则画图会报错
diversity=top1000.groupby(['year','sex']).apply(get_quantile_count)
diversity=diversity.unstack('sex')
#依靠sex入栈操作,将Series转为DataFrame
diversity.head#diversity这个dataframe拥有两个时间序列,每个性别各一个,按年度
Out[112]:
diversity.plot(title="Number of popular names in top50%")
#最后一个字母的变革
#从name列取出最后一个字母
get_last_letter=lambda x:x[-1]
last_letters=names_new.name.map(get_last_letter)
last_letters.name='last_letter'
table=names_new.pivot_table('births',index=last_letters,columns=['sex','year'],
aggfunc=sum)
subtable=table.reindex(columns=[1900,1950,2000],level='year')
subtable.head()
Out[124]:
sex F M
year 1900 1950 2000 1900 1950 2000
last_letter
a 89934.0 576481.0 675485.0 870.0 4037.0 40837.0
b NaN 17.0 372.0 372.0 1632.0 50892.0
c NaN 16.0 525.0 299.0 6500.0 26998.0
d 3670.0 4413.0 4380.0 15499.0 263643.0 64251.0
e 107080.0 376863.0 318199.0 22731.0 168659.0 148821.0
#按总出生数对该表进行规范化处理,以便计算各性别各末字母占出生人数比例
subtable.sum()
Out[125]:
sex year
F 1900 299873.0
1950 1713001.0
2000 1813960.0
M 1900 150554.0
1950 1789936.0
2000 1961702.0
dtype: float64
letter_prop=subtable/subtable.sum().astype(float)
letter_prop[:10]
sex F M
year 1900 1950 2000 1900 1950 2000
last_letter
a 0.299907 0.336533 0.372381 0.005779 0.002255 0.020817
b NaN 0.000010 0.000205 0.002471 0.000912 0.025943
c NaN 0.000009 0.000289 0.001986 0.003631 0.013763
d 0.012239 0.002576 0.002415 0.102946 0.147292 0.032753
e 0.357084 0.220002 0.175417 0.150982 0.094226 0.075863
f NaN NaN 0.000015 0.000770 0.000475 0.000874
g 0.000110 0.000064 0.000322 0.001680 0.004155 0.001223
h 0.051032 0.045475 0.064617 0.041407 0.037949 0.043346
i 0.001201 0.010573 0.023460 0.001030 0.000347 0.009339
j NaN NaN 0.000054 NaN 0.000003 0.000468
import matplotlib.pyplot as plt
%matplotlib inline
#把所有的图画在同一个画布上
plt.figure(1)
fig,axes=plt.subplots(2,1,figsize=(12,20))
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','q','y'],'M'].T
dny_ts.head()
Out[158]:
last_letter d n q y
year
1880 0.083055 0.153213 NaN 0.075760
1881 0.083247 0.153214 NaN 0.077451
1882 0.085340 0.149560 NaN 0.077537
1883 0.084066 0.151646 NaN 0.079144
1884 0.086120 0.149915 NaN 0.080405
dny_ts.plot() #编程女孩名字的男孩名字 all_names=top1000.name.unique() mask=np.array(['lesl' in x.lower() for x in all_names]) lesley_like=all_names[mask] lesley_like Out[163]: 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.head() Out[170]: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--'})