利用Python进行数据分析——第二章 引言(2):利用pandas对babynames数据集进行简单处理
使用数据集为1880年-1929年间美国婴儿名字的频率数据。数据集参见我的资源,附有网址链接。
数据为txt格式,部分数据如下图所示:
根据该数据及,可以进行以下处理:
- 计算指定名字的年度比例;
- 计算某个名字的相对排名;
- 计算各年度最流行的名字,以及增长或减少最快的名字;
- 分析名字的趋势:元音、辅音、长度、总体多样性、拼写变化、首位字母等;
- 分析外源性趋势:圣经中的名字、名人、人口结构变化等。
在次,只进行一些简单的操作。
先对其中一个文件进行操作,查看一下数据的相关内容:
import pandas as pd
import matplotlib.pyplot as plt
names = ["name","sex","births"]#给定读入数据的标签
names1880 = pd.read_csv("C:/Users/GuanLi/Desktop/babynames/datasetsbabynamesyob1880.txt",sep = ",",names=names)
print(names1880[:10])#输出前10条数据进行查看
可以看到前十条数据记录如下,含有姓名name、性别sex、出生数births等字段。
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
按照性别对1880年的出生婴儿总数量进行统计。
sex_births_sum = names1880.groupby("sex").births.sum()
print(sex_births_sum)
输出结果如下:
sex
F 90993
M 110493
Name: births, dtype: int64
上面是对数据集中1880年的婴儿姓名数据进行处理,所使用的整个数据集含有1880年-1929年共50个数据文件。所以,首先将所有数据整合到一个DataFrame中,并加上一个年份year字段,此处调用pandas.concat。
# coding=gbk
import pandas as pd
names = ["name","sex","births"]
years=range(1880,1930)
pieces = []
#通过for循环将50个文件读入
for year in years:
path = "C:/Users/GuanLi/Desktop/babynames/datasetsbabynamesyob"+str(year)+".txt"
frame = pd.read_csv(path,names = names)
frame["year"]=year
pieces.append(frame)#将frame添加到列表pieces中
names = pd.concat(pieces,ignore_index=True)##concat默认按行将多个DataFrame组合到一起
print(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
...
274820 Yoshimi M 5 1929
274821 Yoshiro M 5 1929
274822 Zeferino M 5 1929
274823 Zell M 5 1929
274824 Zygmund M 5 1929
将50个数据文件整合到一起之后,形成了一个含有274825条记录的数据,含有name、sex、births、year四个字段。
有了这些数据,就可以统计在1880年-1929年间,不同性别下婴儿的数量。
total_births = names.pivot_table("births",index="year",columns="sex",aggfunc=sum)
print(total_births)
输出结果如下:
sex F M
year
1880 90993 110493
1881 91955 100748
1882 107851 113687
1883 112322 104632
1884 129021 114445
1885 133056 107802
1886 144538 110785
1887 145983 101412
1888 178631 120857
1889 178369 110590
1890 190377 111026
1891 185486 101198
1892 212350 122038
1893 212908 112319
1894 222923 115775
1895 233632 117398
1896 237924 119575
1897 234199 112760
1898 258771 122703
1899 233022 106218
1900 299873 150554
1901 239351 106478
1902 264079 122660
1903 261976 119240
1904 275375 128129
1905 291641 132319
1906 295301 133159
1907 318558 146838
1908 334277 154339
1909 347191 163983
1910 396416 194198
1911 418180 225936
1912 557939 429926
1913 624317 512482
1914 761376 654746
1915 983824 848647
1916 1044249 890142
1917 1081194 925512
1918 1157585 1013720
1919 1130149 980215
1920 1198214 1064468
1921 1232845 1101374
1922 1200796 1088380
1923 1206239 1096227
1924 1248821 1132671
1925 1217217 1115798
1926 1185078 1110440
1927 1192207 1126259
1928 1152836 1107113
1929 1116284 1074833
在有了每一年的不同性别下出生婴儿的总数,就可以计算每个名字被使用的比例(频率)。插入prop列用来存放比例。先按year和sex分组,然后将新列(prop列)加到各个分组上。
#定义函数add_prop()来计算比例
def add_prop(group):
births = group.births.astype(float)#将出生数births装换成float型数据
group["prop"] = births/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
5 Margaret F 1578 1880 0.017342
...
274820 Yoshimi M 5 1929 0.000005
274821 Yoshiro M 5 1929 0.000005
274822 Zeferino M 5 1929 0.000005
274823 Zell M 5 1929 0.000005
274824 Zygmund M 5 1929 0.000005
如第一行数据prop=0.077643,表示每100个女婴儿中,就有8个(四舍五入)取名为Mary。
另外还可以绘制1880-1929年间美国出生婴儿不同性别随时间的变化图:
year = []#定义一个列表,用来做图的横轴年份
for i in range(1880,1930):
year.append(i)
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
ax.set_xlabel=("years")
plt.plot(year,total_births["M"])
plt.plot(year,total_births["F"])
plt.legend(loc="best",edgecolor="black")#设置图例边框颜色
plt.legend(loc="best",title="sex")
plt.title("Total births by sex and year")
plt.show()
绘图结果如下:
在上面一系列操作之后,得到的一个数据集names含有以下字段:name、sex、births、year、prop。在此数据中,我们取出每对sex/year组合的前1000个名字进行进一步的分析工作。
#定义抽取函数get_top1000()
def get_top1000(group):
return group.sort_index(by="births",ascending=False)[:1000]
grouped = names.groupby(["sex","year"])
top1000 = grouped.apply(get_top1000)
print(top1000)
接下来的工作在top1000数据集上进行相关的分析。
分析起名字的趋势:
首先将前1000个名字分为男、女两部分。
boys = top1000[top1000.sex == "M"]
girls = top1000[top1000.sex == "F"]
在此基础上,可以进行某些名字在美国婴儿中使用的变化情况分析。比如,绘制top1000中,John、Harry、Mary三个名字随时间的变化趋势:
fig1=plt.figure()
plt.plot(year,top1000_total_births["John"])
plt.plot(year,top1000_total_births["Harry"])
plt.plot(year,top1000_total_births["Mary"])
plt.title("Number of births per year")
plt.legend(loc="best",edgecolor="black",title="name")
plt.show()
结果如下图:
可以看出在1880-1929年间,三个名字趋势为先上升后下降。这也说明三个名字在一开始很流行,到后来父母给孩子起比较流行,或者说大众化的名字就很少了。教材上采用了1880-2010年间的数据,可以看到更长时间范围内的变化。
为进一步验证名字的变化趋势,可以计算最流行的1000个名字所占的比例,并绘制变化图。
table=top1000.pivot_table("prop",index="year",columns="sex",aggfunc=sum)
fig2=plt.figure()
plt.plot(year,table["F"])
plt.plot(year,table["M"])
plt.legend(loc="best")
plt.title("sum of top1000.prop by year and sex")
plt.show()
结果如下:
sex F M
year
1880 1.000000 0.997375
1881 1.000000 1.000000
1882 0.998702 0.995646
1883 0.997596 0.998566
1884 0.993156 0.994539
1885 0.992251 0.995501
1886 0.989504 0.995035
1887 0.988279 0.996697
1888 0.984241 0.992429
1889 0.984061 0.994981
1890 0.982566 0.992749
1891 0.982177 0.993725
1892 0.979746 0.988815
1893 0.980001 0.991720
1894 0.978571 0.989048
1895 0.975479 0.989071
1896 0.975660 0.988041
1897 0.976558 0.989349
1898 0.972806 0.987197
1899 0.975170 0.990115
1900 0.967760 0.979702
1901 0.972304 0.989603
1902 0.970467 0.985749
1903 0.969490 0.986020
1904 0.968142 0.982502
1905 0.967038 0.981650
1906 0.967535 0.981759
1907 0.964942 0.976975
1908 0.964500 0.976409
1909 0.962744 0.973412
1910 0.959797 0.969778
1911 0.960108 0.967743
1912 0.955857 0.958370
1913 0.953979 0.955881
1914 0.951697 0.952579
1915 0.948814 0.950604
1916 0.948050 0.950211
1917 0.947547 0.950382
1918 0.946388 0.950806
1919 0.945567 0.949201
1920 0.945281 0.950184
1921 0.945001 0.951235
1922 0.944200 0.950868
1923 0.945099 0.952030
1924 0.944637 0.952422
1925 0.944954 0.953723
1926 0.945526 0.953889
1927 0.945487 0.954031
1928 0.946658 0.954890
1929 0.947905 0.956236
从图中可以看出,名字的多样性出现了增长,从而使某一具体的名字所占比例出现下降。假设我们将名字所占比例从高到低排序,前50%的名字定义为比较流行的名字。那么可以根据前50%名字的数量来观察名字的多样性变化。
def get_quantile_count(group,q=0.5):
group = group.sort_index(by="prop",ascending=False)
return group.prop.cumsum().searchsorted(q) + 1
diversity = top1000.groupby(["year","sex"]).apply(get_quantile_count)
diversity = diversity.unstack("sex")
print(diversity)
fig3=plt.figure()
plt.plot(year,diversity["F"])
plt.plot(year,diversity["M"])
plt.legend(loc="best")
plt.title("Number of popular names in top 50%")
plt.show()
可以得到1880-1930年间,占比前50%的姓名数量和趋势图:
sex F M
year
1880 [38] [14]
1881 [38] [14]
1882 [38] [15]
1883 [39] [15]
1884 [39] [16]
...
1925 [52] [28]
1926 [52] [28]
1927 [52] [28]
1928 [52] [28]
1929 [51] [28]
从图中可以看出女孩姓名的多样性总是比男孩的高。两者的总体变化趋势为升高,即婴儿名字的多样性在升高,名字种类越来越多。
(后面还有名字末字母的分析、名字“变性”分析,_,不做了,哈哈)