数据分析实例
14.3 1880-2010年间全美婴儿姓名
可以从http://www.ssa.gov/oact/babynames/limits.html 网址下载相关数据
import pandas as pd
names1880 =pd.read_csv('datasets/babynames/yob1880.txt',
names=['name', 'sex', 'births'])
print(names1880)
name sex births
0 Mary F 7065
1 Anna F 2604
2 Emma F 2003
3 Elizabeth F 1939
4 Minnie F 1746
... ... .. ...
1995 Woodie M 5
1996 Worthy M 5
1997 Wright M 5
1998 York M 5
1999 Zachariah M 5
[2000 rows x 3 columns]
#按照性别统计该年的人数
names1880.groupby('sex').births.sum()
sex
F 90993
M 110493
Name: births, dtype: int64
#该数据集包含多个年份数据,首先将其整合到一个数据中
years = range(1880, 2011)
pieces = []
columns = ['name', 'sex', 'births']
for year in years:
path = 'datasets/babynames/yob%d.txt' % year
frame = pd.read_csv(path, names=columns)
frame['year'] = year
pieces.append(frame)
names = pd.concat(pieces, ignore_index=True)
total_births = names.pivot_table('births', index='year',
columns='sex', aggfunc=sum)
total_births.tail()
total_births.plot(title='Total births by sex and year')
<matplotlib.axes._subplots.AxesSubplot at 0x17b33870>
total_births.plot(title='Total births by sex and year')
<matplotlib.axes._subplots.AxesSubplot at 0x1809a130>
在这里插入图片描述
#在这儿增加一列表示当前名字的频率,如果为0.02表示每100个婴儿中有2个取了这个名字
def add_prop(group):
group['prop'] = group.births / group.births.sum()
return group
names = names.groupby(['year', 'sex']).apply(add_prop)
print(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
... ... .. ... ... ...
1690885 Zymaire M 5 2010 0.000003
1690886 Zyonne M 5 2010 0.000003
1690887 Zyquarius M 5 2010 0.000003
1690888 Zyran M 5 2010 0.000003
1690889 Zzyzx M 5 2010 0.000003
[1690890 rows x 5 columns]
#有些时候需要做一些检查,例如检查所有分组中的prop的综合是否为1
print(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
#取没对sex/year组合的前1000个名字
def get_top1000(group):
return group.sort_values(by='births', ascending=False)[:1000]
grouped = names.groupby(['year', 'sex'])
top1000 = grouped.apply(get_top1000)
top1000.reset_index(inplace=True, drop=True)
#也可以按着下面的方法做。自己还可以做一些其他的方法。
'''
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)
'''
"\npieces = []\nfor year, group in names.groupby(['year', 'sex']):\n pieces.append(group.sort_values(by='births', ascending=False)[:1000])\ntop1000 = pd.concat(pieces, ignore_index=True)\n"
print(top1000)
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
... ... .. ... ... ...
261872 Camilo M 194 2010 0.000102
261873 Destin M 194 2010 0.000102
261874 Jaquan M 194 2010 0.000102
261875 Jaydan M 194 2010 0.000102
261876 Maxton M 193 2010 0.000102
[261877 rows x 5 columns]
分析命名趋势
根据得到的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.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 131 entries, 1880 to 2010
Columns: 6869 entries, Aaden to Zuri
dtypes: float64(6869)
memory usage: 6.9 MB
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 0x18186050>,
<matplotlib.axes._subplots.AxesSubplot object at 0x176E75F0>,
<matplotlib.axes._subplots.AxesSubplot object at 0x17705610>,
<matplotlib.axes._subplots.AxesSubplot object at 0x17724650>],
dtype=object)
在这里插入图片描述
评估命名多样性的增长
通过分析查看取名的趋势
table = top1000.pivot_table('prop', index='year',
columns='sex', aggfunc=sum)
import numpy as np
table.plot(title='Sum of table1000.prop by year and sex',
yticks=np.linspace(0, 1.2, 13), xticks=range(1880, 2020, 10))
<matplotlib.axes._subplots.AxesSubplot at 0x17797d70>
在这里插入图片描述
#还可以计算不同名字的数量
df = boys[boys.year == 2010]
在排序后,还需要计算多少个名字之和是前50%。
prop_cumsum = df.sort_values(by='prop', ascending=False).prop.cumsum()
prop_cumsum.values.searchsorted(0.5)#返回应该在频率上插入0.5的位置。
116
#利用1900年的数据,数据量相对较小
df = boys[boys.year == 1900]
in1900 = df.sort_values(by='prop', ascending=False).prop.cumsum()
in1900.values.searchsorted(0.5) + 1
25
def get_quantile_count(group, q=0.5):
group = group.sort_values(by='prop', ascending=False)
return group.prop.cumsum().values.searchsorted(q) + 1
diversity = top1000.groupby(['year', 'sex']).apply(get_quantile_count)
diversity = diversity.unstack('sex')
#可以查看前50%的人名中的个数
print(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%")
<matplotlib.axes._subplots.AxesSubplot at 0x1781e810>
在这里插入图片描述
“最后1个字母”的变革
#聚合名字最后一个字母
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')#统计代表性年份
print(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()
letter_prop = subtable / subtable.sum()
print(letter_prop)
sex F M
year 1910 1960 2010 1910 1960 2010
last_letter
a 0.273390 0.341853 0.381240 0.005031 0.002440 0.014980
b NaN 0.000343 0.000256 0.002116 0.001834 0.020470
c 0.000013 0.000024 0.000538 0.002482 0.007257 0.012181
d 0.017028 0.001844 0.001482 0.113858 0.122908 0.023387
e 0.336941 0.215133 0.178415 0.147556 0.083853 0.067959
f NaN 0.000010 0.000055 0.000783 0.004325 0.001188
g 0.000144 0.000157 0.000374 0.002250 0.009488 0.001404
h 0.051529 0.036224 0.075852 0.045562 0.037907 0.051670
i 0.001526 0.039965 0.031734 0.000844 0.000603 0.022628
j NaN NaN 0.000090 NaN NaN 0.000769
k 0.000121 0.000156 0.000356 0.036581 0.049384 0.018541
l 0.043189 0.033867 0.026356 0.065016 0.104904 0.070367
m 0.001201 0.008613 0.002588 0.058044 0.033827 0.024657
n 0.079240 0.130687 0.140210 0.143415 0.152522 0.362771
o 0.001660 0.002439 0.001243 0.017065 0.012829 0.042681
p 0.000018 0.000023 0.000020 0.003172 0.005675 0.001269
q NaN NaN 0.000030 NaN NaN 0.000180
r 0.013390 0.006764 0.018025 0.064481 0.031034 0.087477
s 0.039042 0.012764 0.013332 0.130815 0.102730 0.065145
t 0.027438 0.015201 0.007830 0.072879 0.065655 0.022861
u 0.000684 0.000574 0.000417 0.000124 0.000057 0.001221
v NaN 0.000060 0.000117 0.000113 0.000037 0.001434
w 0.000020 0.000031 0.001182 0.006329 0.007711 0.016148
x 0.000015 0.000037 0.000727 0.003965 0.001851 0.008614
y 0.110972 0.152569 0.116828 0.077349 0.160987 0.058168
z 0.002439 0.000659 0.000704 0.000170 0.000184 0.001831
#生成各年度各性别的条形图
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2, 1, figsize=(10,10))
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)
<matplotlib.axes._subplots.AxesSubplot at 0x18d59590>
在这里插入图片描述
letter_prop = table / table.sum()
dny_ts = letter_prop.loc[['d', 'n', 'y'], 'M'].T
print(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
dny_ts.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x18d12ed0>
在这里插入图片描述
变成女孩名字的男孩名字(以及相反的情况)
all_names = pd.Series(top1000.name.unique())
lesley_like = all_names[all_names.str.lower().str.contains('lesl')]
lesley_like
632 Leslie
2294 Lesley
4262 Leslee
4728 Lesli
6103 Lesly
dtype: object
filtered = top1000[top1000.name.isin(lesley_like)]
filtered.groupby('name').births.sum()
name
Leslee 1082
Lesley 35023
Lesli 929
Leslie 370442
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)
print(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--'})
<matplotlib.axes._subplots.AxesSubplot at 0x18fd6430>
在这里插入图片描述
Name: rating, dtype: float64
说明:
放上参考链接,这个系列都是复现的这个链接中的内容。
放上原链接: https://www.jianshu.com/p/04d180d90a3f
作者在链接中放上了书籍,以及相关资源。因为平时杂七杂八的也学了一些,所以这次可能是对书中的部分内容的复现。也可能有我自己想到的内容,内容暂时都还不定。在此感谢原简书作者SeanCheney的分享。
网友评论