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--'})

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