《利用Python进行数据分析》学习笔记——第二章(3)




1880-2010年间全美婴儿姓名



用pandas.read_csv加载.txt文件

图2.1 用read_csv加载.txt文件

        DataFrame.names1880中只有births这一列是int型,所有在使用sum()函数他似乎是会默认使用births列进行分组(groupby)

图2.2 默认对births列进行分组


读取所有数据,并组装到一个DataFrame中,再加上一个year字段:

图2.3 读取所有数据

        range(1880,2011)是因为range是左闭右开的,而2010是最后一个有效统计年度。

        frame['year']=year,当没有指定行的话,那么整个的'year'列都会赋予相同的值。


将所有数据整合到单个DataFrame中:

图2.4 将所有数据整合到单个DataFrame中

        concat默认按行将多个DataFrame组合到一起,pieces是由多个DataFrame组合成的list,所以这些单个的数据而具有各自的索引(index),因此在组合的时候我们需要忽视现在的索引(index),然后concat会为这个新的组合的DataFrame设置新的索引(index)


        如果不设置ignore_index=True这个参数的话,也不会报错,那样的话这个DataFrame就会有相同的index。那么,当我们根据这个index进行索引的时候就会将这些拥有相同index的数据全部提取出来:

图2.4 没有设置ignore_index=True的索引结果

        可以看到正好每个年份都有一个相同的index


利用pivot_table在year和sex级别上进行聚合:

图2.5 数据透视表

        .tail()是输出最后的5行,.head()的话则是开始的5行。下面是用groupby进行分组的方式:

图2.6  groupby进行分组

        用groupby的话要注意使用.unstack(),不要让数据堆叠在一起。


        画出图像:

图2.7 按性别和年度统计的总出生数


插入prop列,用于存放指定名字的婴儿数相对于总出生数的比例:

图2.8 插入prop列

        ‘用于存放指定名字的婴儿数相对于总出生数的比例’,这句话我一开始没有理解,所以对其中定义的add_prop(group)函数的计算结果感到疑惑:

图2.9 prop的总数

        按照我对这句话最初的理解,prop的总数应该为1才对,而结果是262(sum进行浮点计算会丢失精度,因而结果应该是262)。

        那么按照这个理解,这句话具体的含义应该是‘指定名字且相同性别的婴儿相对于同一年份婴儿的总出生数的比例’(感觉好像有点长,不知道还有没更简洁的表达方式):

图2.10 分组的prop总和

        其实还是对groupby这个函数的理解不到位,不然其实通过代码是可以轻易的反推出题意的。


检查分组总计值:

图2.11 分组总计值为1


取出每对sex/year组合的前1000个名字:

图2.12 取出每对sex/year组合的前1000个名字  

        这里除了书上的两种方法,为了让它看起来更简洁,就把方法1的函数用lambda代替了。



分析命名趋势

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

图2.13 布尔型数组索引


生成一张按year和name统计的总出生数的数据透视表:

图2.14 按year和name统计的总出生数透视表

        这里出现了警告,大概意思应该是'year'同时具有两个属性,index level (索引水平)column label(列标签),我一开始以为是pivot_table的参数问题,所以用groupby也试了一下,发现依旧出现这样的警告,也不知道怎么消除。但是问题应该不大,毕竟是可以运行的。


用plot方法绘制名字的曲线图:

图2.15 plot方法绘图

        这里的subplots参数分成若干子图,figsize图的尺寸,grid网格。生成的图像:

图2.16 几个男孩和女孩名字随时间变化的使用数量


评估命名多样性的增长

        图2.16所反映的降低情况可能意味着父母愿意给小孩起常见的名字越来越少。这个假设可以从数据中得到验证。

一个办法是计算最流行的1000个名字所占比例:

按year和sex进行聚合并绘图:

图2.17 分性别统计的前1000个名字在总出生人数中的比例

        通过前1000项的比例降低,可以得知名字的多样性出现了增长。


另一个办法是计算占总出生人数前50%的不同名字的数量:

图2.18 计算cumsum,确定0.5的位置

        cumnum()计算前n项的累加和,所以用在这里时要注意排序。

        searchsorted()寻找某个数应该插在数组的什么位置上,返回值是Index,也就是说0.5应该插在索引为116的位置,又由于index是从0开始,所以0.5应作为第116+1=117个数添加进去,这里可以看一下index=115和Index=116的数分别是多少:

图2.19 查看Index=115 和index=116的数据

        这里一开始脑子没有转过来,还在想0.5明明在二者之间,为什么他应该放在117这个位置。这个问题就和‘小明跑步比赛中超过了第一名,现在他是第几名’一样傻。。。

        与1900年做比较:

图2.20 1900年0.5的位置



用一个函数计算各分组的'searcheasored(0.5)+1'值:

图2.21 计算各分组'searcheasored(0.5)+1'  的值  

        这里我犯了一个很大错误,书上的程序是“diversity = diversity.unstack('sex')”,这里我写的时候自作聪明写成了“diversity.unstack()”,当然在这里的输出图表结果是不影响的。但是,在后面绘图的时候,由于'sex'堆叠在一起,所以输出的图和我想要的是有区别的。并且还花费了我大量时间查找错误。

        另外从这里输出的DataFrame中的数据带有括号,而书上的结果是没有的,这应该又是python3和python2区别了。而且如果没注意到这个问题,绘图时就会报错。


这个简单函数还是尝试用lambda写一下:

图2.22 用lambda函数计算'searchsorted(0.5)+1'的值


绘制图表:

先看一下没堆叠的错误的图:    

图2.23 'sex'堆叠的图表

        当然如果要是完全按照书上来的话是不会出现这样的问题的(python3还是有其他问题的)


        上面说了,DataFrame的结果和书上有区别(带括号),当我们用这个直接用这个结果绘图的时候会报这样的错:

图2.24 TypeError

        类型错误,说我们的DataFrame里没有数值类型(numeric)


        所以先看一下那个带括号的数据是什么类型:

图2.25 ndarray类型数据


    所以为了将图像正常输出来,就要用类型转换astype(int):

图2.26 正常输出的按年度统计的密度表

        从图中可以看出,女孩名字的多样性总是比男孩高,而且还在变得越来越高



“最后一个字母”的变革

        为了了解男孩名字在最后一个字母上的分布发生变化,我首先将全部出生数据在年度、性别以及及末字母上进行了聚合:

图2.27 末字母聚合

        这里的map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。



选出具有一定代表性的三年:

图2.29 具有代表性的三年


按总出生数对该表进行规范化处理,以计算各性别各末字母占总出生人数的比例:

图2.30 表规范化处理

        这里没有和书上一样用数据类型转换,发现结果还是一样的,所以先在这去掉,如果后面出现问题,可以更好的理解这里转换的意义。


生成各年度各性别的条形图:

图2.31 程序
图2.32 男孩女孩名字中各个末字母的比例

        fig、axes分别是绘制的图一些参数,fig主要是绘制的图中,轴以外的部分;而axes也就是这个坐标轴的参数。

        subplots是绘制子图,在这里将它男成2行1列的图,axes[0]就是第一行,axes[1]就是第二行。

        这里我将参数改一下,就可以稍微理解一些参数的意义:

图2.33 更改参数测试


        从图2.32可以看出,从20世纪60年代开始,以字母“n”结尾的男孩名字出现了显著的增长。回到之前创建的那个完整表,按年度和性别对其进行规范化处理,并在男孩名字中选取几个字母,最后进行转置以便将各个列做成一个时间序列:

图3.34 时间序列

        这里的.T就是转置的意思


绘制趋势图:

图3.35 各年出生的男孩中名字以d/n/y结尾的人数比例


变成女孩名字的男孩名字(以及相反情况)

回到top1000数据集,找出其中以“lesl”开头的一组名字:

图2.36 找出以“lesl”开头的名字

        这里的.unique()是用于求唯一值,感觉用起来和list里面的set有点像。

        这里的['lesl' in x.lower() for x in all_namesl] 又是一个布尔值运算数组,如果看mask的值可以看到:

图2.38 mask的值



过滤其他的名字,并按名字分组计算出生数以查看相对频率:

图2.37 过滤其他的名字,并按名字分组计算出生数以查看相对频率

        pd.isin(values),是否包含数据框中的元素


按性别和年度进行聚合,并按年度进行规范化处理:

图2.38 按性别和年度进行聚合,并按年度进行规范化处理

        这里的.div()我好像之前写过,不过还是不太熟悉(很尴尬),div主要是用作小数除法。


绘制年度曲线图:

图3.39 各年度使用“Lesley型”名字的男女比例





你可能感兴趣的:(《利用Python进行数据分析》学习笔记——第二章(3))