《利用python进行数据分析》学习笔记(三)

来源:互联网 发布:电影级别剪辑软件 编辑:程序博客网 时间:2024/04/29 07:05

处理US Baby Names 1880-2010 data set

导入表格数据

import pandas as pdyears = range(1880, 2011)pieces = []columns = ['name', 'sex', 'births']for year in years:    path = 'ch02/names/yob%d.txt' % year    frame = pd.read_csv(path, names=columns)    # 添加year列    frame['year'] = year    pieces.append(frame)# 把所有数据拼接到一个dataframe里names = pd.concat(pieces, ignore_index=True)

read_csv本身读进来是一个dataframe,但是因为我们要利用for循环读取多个并将它们依次append于一个list中,所以最后需要利用pd.concat()将list中的所有dataframe合并为一个。 ignore_index=True是为了重置index。

  • names数据
    这里写图片描述

数据聚合与重建

# 在year和sex上对names进行聚合total_births = names.pivot_table('births', index='year', columns='sex',aggfunc=sum)# 按性别和年度统计的总出生数total_births.plot(title='Total births by sex and year')# 插入prop列,用来存放指定名字的婴儿数相对于总出生数的比例def add_prop(group):    # 整数除法会向下取整    births = group.births.astype(float)    group['prop'] = births / births.sum()    return groupnames = names.groupby(['year', 'sex']).apply(add_prop)# 检验所有分组的prop总和是否足够近似于1np.allclose(names.groupby(['year', 'sex']).prop.sum(), 1)# 取出每对sex/year组合的前1000个名字def get_top1000(group):    return group.sort_index(by='births', ascending=False)[:1000]grouped = names.groupby(['year', 'sex'])top1000 = grouped.apply(get_top1000)
  • total_births画图(按性别和年度统计的总出生数)
    这里写图片描述

  • names
    这里写图片描述

  • pandas.DataFrame.groupby
    具体参数不在这里赘述,请参考下面文档,这里讲讲自己的试验与理解。
    http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.groupby.html
    groupby从字面上很好理解,就是我们根据一些columns,来对数据进行group聚合,问题是groupby后的数据到底是什么样的,无法正确理解数据形式就很难进行后面的处理,于是做了试验:
# 因为groupby对象是无法直接输出的,除非使用了sum,mean,size等函数才行,# 所以我们利用for和append把它的内在结构拉出来看看结果如何yy = names.groupby(['year','sex'])xx = []for y in yy:    xx.append(y)xx

下面是xx的输出结果,只提取一部分

[((1880, 'F'),           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  ...        ...  ...    ...   ...       ...  940     Vertie   F       5  1880  0.000055  941      Wilma   F       5  1880  0.000055  [942 rows x 5 columns]), ((1880, 'M'),            name sex  births  year      prop  942        John   M    9655  1880  0.087381  943     William   M    9533  1880  0.086277

那么现在就很明了了,个人理解,groupby对象是一个具有multi-index的dataframe,它是由多个dataframe组合而成,而且每个dataframe具有自己的index,比如这里的话就是[‘year’,’sex’]((1880,’F’)对应的是一个dataframe,(1880,’M’)又对应一个dataframe)。所以当它们应用sum,mean,size之后,就相当于把一个dataframe压缩成了一行,这样拼起来又是一个一般的二维dataframe就可以输出了。

  • pandas.DataFrame.apply
    接下来介绍apply,同样具体参数不在这里赘述了,请参考下面文档,在这里主要讲讲自己的理解。
    http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.apply.html
    首先提一下关于apply和map的区别,都是映射函数,apply是应用于dataframe的,而map是应用于series的。官方文档中,对apply的描述是将函数应用到dataframe的输入轴向上,对于一般的dataframe(也就是单一index),那么axis=0,就可以理解为是将每个column提出来输入到函数中(也就是一个个Series)。而代码中是将groupby后的对象输入到函数中,上面讲了groupby对象是具有multi-index的,那么这次应用到输入轴向的话,就不再是应用于每个column,而是应用于每个小的dataframe,这样的话,函数add_prop就好理解了。

  • numpy.allclose
    https://docs.scipy.org/doc/numpy/reference/generated/numpy.allclose.html

分析命名趋势

# 将前1000个名字分为男女两个部分boys = top1000[top1000.sex == 'M']girls = top1000[top1000.sex == 'F']# 按year和name统计的总出生数透视表total_births = top1000.pivot_table('births', index='year', columns='name', aggfunc=sum)# 对这4个名字按年份绘图subset = total_births[['John', 'Harry', 'Mary', 'Marilyn']]subset.plot(subplots=True, figsize=(12, 10), grid=False, title="Number of births per year")### 评估命名多样性的增长## 方法一# 计算最流行的1000个名字所占的比例,再按year和sex进行聚合并绘图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, 2020, 10))## 方法二# 统计占总出生人数钱50%的不同名字的数量def get_quantile_count(group, q=0.5):    group = group.sort_index(by='prop', ascending=False)    return group.prop.cumsum().values.searchsorted(q) + 1diversity = top1000.groupby(['year', 'sex']).apply(get_quantile_count)diversity = diversity.unstack('sex')# diversity画图diversity.plot(title="Number of popular names in top 50%")
  • total_births
    这里写图片描述

  • subset画图(几个男孩和女孩名字随时间变化的使用数量)
    这里写图片描述

  • table画图(分性别统计的前1000个名字在总出生人数中的比例)
    这里写图片描述

  • diversity画图(前50%人数中,名字的个数)
    这里写图片描述

  • numpy.searchsorted(a,v,side=’left’)
    在一个sorted的数组a中,找到indices,使得对应的v插入到这些indices之前,a数组的顺序能够不变
    https://docs.scipy.org/doc/numpy/reference/generated/numpy.searchsorted.html

最后一个字母的变革
# 从name column里面提取最后一个字母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')subtable.sum()# 求出末位字母所占比例letter_prop = subtable / subtable.sum().astype(float)# 生成各年度男孩女孩各个末字母的比例的条形图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)# 各年出生的男孩中名字以d/n/y结尾的人数的比例letter_prop = table / table.sum().astype(float)dny_ts = letter_prop.ix[['d', 'n', 'y'], 'M'].Tdny_ts.plot()
  • letter_prop[‘M’]和letter_prop[‘F’]画图(男孩女孩中各个末字母的比例)
    这里写图片描述

  • dny_ts画图(各年出生的男孩中名字以d/n/y结尾的人数比例)
    这里写图片描述

变成女孩名字的男孩名字(以及相反情况)
# 名字去重all_names = top1000.name.unique()# 对all_names的所有元素进行判定,以'lesl'开头的名字将会标为True,其余的为False,也就是说mask是一个布尔量的数组mask = np.array(['lesl' in x.lower() for x in all_names])# 再利用布尔索引取出开头为'lesl'的名字lesley_like = all_names[mask]# 过滤掉其他名字filtered = top1000[top1000.name.isin(lesley_like)]filtered.groupby('name').births.sum()# 按性别和年度进行聚合,并按年度进行规范化处理,算出比例table = filtered.pivot_table('births', index='year', columns='sex', aggfunc='sum')table = table.div(table.sum(1), axis=0)# 绘制一张分性别的年度曲线图table.plot(style={'M': 'k-', 'F': 'k--'})
  • table画图(各年度使用”Lesley型”名字的男女比例)
    这里写图片描述

  • pandas.DataFrame.div
    http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.div.html

阅读全文
0 0
原创粉丝点击