14_3_美国1880_2010年的婴儿名字

2020-05-11  本文已影响0人  弦好想断
more babynames\yob1880.txt

more命令直接在文本编辑器中打开。

import pandas as pd
import numpy as np
names1880=pd.read_csv('babynames\yob1880.txt',names=['name','sex','births'])
names1880.head()
names1880.groupby('sex').sum()#婴儿的出生总数
names1880.groupby('sex').size()#名字的个数

因为原数据的每份文件都分散地按年的存储为很多个TXT文件,这里将所有数据集集中到一个DataFrame中,然后再添加一个对应的年份字段。

years = range(1880,2011)
pieces = []
columns = ['name','sex','births']
for year in years:
   path = 'babynames\yob%d.txt' % year#这里匹配的是%d对应的值
   frame = pd.read_csv(path,names=columns)
   frame['year']=year
   pieces.append(frame)
names = pd.concat(pieces,ignore_index=True)#concat默认情况下将DataFrame对象以逐行方式联合在一起。
names#传递ignore_index=True,不保留原始索引

透视表的方法取出每年的出生人数按性别求和

total_births=names.pivot_table(values='births',index='year',columns='sex',aggfunc=sum)
total_births.head()

画个图

total_births.plot(title='Total borths by sex and year')

插入一个prop列,给出每个婴儿名字相对于出生总数的比例

def add_prop(group):
    group['prop']=group.births/group.births.sum()
    return group
names = names.groupby(['year','sex']).apply(add_prop)
names

进行完整性检查

names.groupby(['year','sex']).prop.sum()
year  sex
1880  F      1.0
      M      1.0
1881  F      1.0
      M      1.0
1882  F      1.0
            ... 
2008  M      1.0
2009  F      1.0
      M      1.0
2010  F      1.0
      M      1.0
Name: prop, Length: 262, dtype: float64

每个性别/年份组合的前1000名(认真看传入参数)

#受欢迎的名字的前1000名(通过起名的个数进行排序)
def get_top1000(group):
    return group.sort_values(by='births',ascending=False)[:1000]
top1000 = names.groupby(['year','sex'],group_keys=False).apply(get_top1000)
#重置索引
top1000.reset_index(inplace=True,drop=True)
top1000
#使用DIY方式
pieces = []
for year,group in names.groupby(['year','sex']):
    pieces.append(group.sort_values(by='births',ascending=False)[:1000])
top1000 = pd.concat(pieces,ignore_index=True)
top1000#返回结果同上图

分析名字趋势

#分成男孩和女孩两部分
boys = top1000[top1000.sex=='M']
girls = top1000[top1000.sex=='F']
#按年份和名字形成出生总数的数据透视表
total_births=top1000.pivot_table('births',index='year',columns='name',aggfunc=sum)
total_births

绘制少数名称的数据透视表

#一些男孩名字和女孩名字随时间变化的趋势
subset=total_births[['John','Harry','Mary','Marilyn']]
subset.plot(subplots=True,figsize=(12,10),grid=False,title='Number of births per year')

起常用名字(前1000)的概率随时间的变化

#受欢迎的名字在每一年的出现概率
table = top1000.pivot_table('prop',index='year',columns='sex',aggfunc=sum)
#受欢迎(前1000)的名字出现概率随时间变化
table.plot(title='Sum of top1000.prop by year and sex',xticks=range(1880,2010,10),yticks=np.linspace(0,1.2,13))

我们看看2010年男孩的名字

df2010 = boys[boys.year==2010]
df2010
in2010 = df2010.sort_values(by='prop',ascending=False).prop.cumsum()#按降序,累加求和
in2010
260877    0.011523
260878    0.020934
260879    0.029959
260880    0.038930
260881    0.047817
            ...   
261872    0.842748
261873    0.842850
261874    0.842953
261875    0.843055
261876    0.843156
Name: prop, Length: 1000, dtype: float64
in2010.values.searchsorted(0.5)#索引为116时累加和达到0.5
116#由于数组是零索引的,所以要+1变成117

按性别和年龄分组,受欢迎程度前50%的姓名个数

def get_quantile_count(group,q=0.5):
    group = group.sort_values(by='prop',ascending=False).prop.cumsum()
    return group.values.searchsorted(q)+1
#按性别和年龄分组,受欢迎程度前50%的姓名个数
top1000.groupby(['year','sex']).apply(get_quantile_count)
year  sex
1880  F       38
      M       14
1881  F       38
      M       14
1882  F       38
            ... 
2008  M      109
2009  F      241
      M      114
2010  F      246
      M      117
Length: 262, dtype: int64
diversity = top1000.groupby(['year','sex']).apply(get_quantile_count)
diversity.unstack('sex')
diversity.plot(title='Number of popular names in top 50%')

最后一个字母

从name列提取最后一个字母

last_letters = names.name.map(lambda x:x[-1])
last_letters.name = 'last_letter'
lsat_letters
table = names.pivot_table(values='births',index = last_letters,columns=['sex','year'],aggfunc=sum)
table
#选出三个具有代表性的年份
suitable=table.reindex(columns=[1910,1960,2010],level='year')
suitabl
#归一化处理
letter_prop = suitable/suitable.sum()
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)
#关键字参数必须跟随在位置参数后面

以n结尾的男孩名字经历了显著的增长

#为男孩名字选择一个字母子集,最后转换为使每列成为一个时间序列
letter_prop = table/table.sum()
dny_ts = letter_prop.loc[['d','y','n'],'M'].T#所有男性
dny_ts
dny_ts.plot()
#姓名以‘y’,'d','n'结尾的男性婴儿的频率标准化后的值

男孩变成女孩名字趋势

all_names = pd.Series(top1000.name.unique())
lesley_like = all_names[all_names.str.lower().str.contains('lesl')]
filterend = top1000[top1000.name.isin(lesley_like)]
filterend
filterend.groupby('name').births.sum()
name
Leslee      1082
Lesley     35022
Lesli        929
Leslie    370429
Lesly      10067
Name: births, dtype: int64
table = filterend.pivot_table('births',index='year',columns='sex',aggfunc=sum)
table
table = table.div(table.sum(1),axis=0)
table.plot(style={'M':'k-','F':'k--'})

代码细节值得考量,分析思路要多看几遍。

上一篇下一篇

猜你喜欢

热点阅读