目录

  • 导入数据
  • 数据聚合+分析前准备
  • 分析趋势
  • 评估多样性


导入数据

继续上一节,python3.7, maxOS + jupyter notebook 参考的是*《利用Python进行数据分析》*一书,这次使用的是1880-2010年间全美婴儿姓名,下载估计需要但我还是提供网址https://www.ssa.gov/oact/babynames/limits.html 然后选择“National data”(如果不能下载可以私戳我)解压后是很多很多的txt文档,相比前一个movie的数据集,这个数据集体量更大并且具有明确的时间区分。

python实现效度分析和信度分析 python数据有效性分析_数据分析


由于这是一个非常标准的以逗号隔开的格式,所以使用pandas.read_csv将其加载到DataFrame中:

import pandas as pd
names1880 = pd.read_csv('/Users/wangchenghang/Desktop/names/yob1880.txt',names=['name', 'sex', 'births'])

这些文件中仅含当年出现超过5次的名字。为了简单起见,我们可以用births列的sex分组表示该年度的births总计:

names1880.groupby('sex').births.sum()

结果如下:



python实现效度分析和信度分析 python数据有效性分析_数据_02


数据聚合+分析前准备

由于该数据集按年度被分隔成了多个文件,所以第一件事就是要将所有数据都组装到一个DataFrame里面,并加上一个year的字段。 使用pandas.concat即可达到这个目的:

#2019是目前最后一个有效年份
years = range(1880,2019)
pieces = []
columns = ['name', 'sex', 'births']

for year in years:
    path = '/Users/vicky/Desktop/names/yob%d.txt' %year
    frame = pd.read_csv(path, names = columns)
    
    frame['year'] = year
    pieces.append(frame)
    
#将数据整合到单个dataframe中   
names = pd.concat(pieces, ignore_index= True)

这里需要注意:

  • concat默认是按行将多个Dataframe组合到一起的
  • igonre_index=True,是因为我们不希望保留read_csv所返回的原始行号

现在得到的巨大的Dataframe如下图所示:



python实现效度分析和信度分析 python数据有效性分析_数据_03


有了这些数据后,我们就可以使用groupbypivot_table在year和sex级别上对其进行聚合了:

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

顺便可视化一下:

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

python实现效度分析和信度分析 python数据有效性分析_可视化_04


下面可以继续插入一个prop列,用于存放指定名字的婴儿数相对总出生数的比例。prop值为0.02表示100名婴儿中有2名取了当前的名字。因此,我们先按year和sex分组,然后再将新列加到各个分组上:

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

记得之前想了好久怎么做也没做出来,反正这一步是真的学到了👌👌👌,得到的表应为:



python实现效度分析和信度分析 python数据有效性分析_python_05


为了保险我们再来检验一下所有的prop加和是不是为1,由于是float型,这里使用的是np.allclose

python实现效度分析和信度分析 python数据有效性分析_python_06


看起来没有错误👍 但为了实现更进一步的分析, 还需要取出该数据的一个子集:每对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)

得到如下Dataframe



python实现效度分析和信度分析 python数据有效性分析_数据分析_07


分析趋势

有了完整的数据集和刚才生成的top1000数据集,我们可以开始分析各种命名趋势了。首先将前1000个名字分为男女两个部分:

boys = top1000[top1000.sex == 'M']
girls = top1000[top1000.sex == 'F']

我们先生成一张按year和name统计的总出生透视表:

top1000.index = top1000.index.droplevel()
total_births = top1000.pivot_table('births', index = 'year', columns='name' , aggfunc=sum)
total_births

得到:

python实现效度分析和信度分析 python数据有效性分析_数据分析_08


我们再用plot方法绘制几个名字的曲线:

subset = total_births[['John','Harry','Mary','Marilyn']]
subset.plot(subplots=True, figsize=(12,10),grid=False,title='Number of births per year')

python实现效度分析和信度分析 python数据有效性分析_数据_09

评估多样性

这个其实牵扯一个思路问题,虽然书上写的思路很直接,但其实如果直观的去解决这个问题还是有些麻烦的。 基于之前top1000的表,那如果最流行的1000个名字所占的比例减少,那么也可以侧面证明:

top1000.index = top1000.index.droplevel()
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,2030,20)

得到的图为:

python实现效度分析和信度分析 python数据有效性分析_python实现效度分析和信度分析_10


确实前1000个流行的名字所占比例在下降。 但考虑另一个方法是计算占出生人数前50%的不同名字的数量(因为计算比较复杂,这里取1990年和2018年做比较):

python实现效度分析和信度分析 python数据有效性分析_数据分析_11


python实现效度分析和信度分析 python数据有效性分析_数据_12


可以明显的看出,名字的数量增长了许多。既然这个方法看起来是可行的,我们就可以对所有year/sex组合执行这个计算。按这两个字段进行groupby处理,然后用一个函数计算各分组的这个值:

def get_quantile_count(group, q=0.5):
    gruop = group.sort_values(by='prop' ,ascending= False)
    return group.prop.cumsum().searchsorted(q)+1

diversity = top1000.groupby(['year','sex']).apply(get_quantile_count)
diversity = diversity.unstack('sex')
diversity.plot(title = 'Number of popular names in top 50%', yticks = np.linspace(0, 300, 13), xticks = range(1880,2030,20))

结果如下:

python实现效度分析和信度分析 python数据有效性分析_数据分析_13