本文记录2022年3月组队学习-动手学数据分析教程知识点,采用kaggle上泰坦尼克的任务,实战数据分析全流程。
教程内容开源地址:
github: https://github.com/datawhalechina/hands-on-data-analysis
gitee:https://gitee.com/datawhalechina/hands-on-data-analysis
接下来要重点研究一下数据重构。本章我们着重研究一下SAC过程(split-apply-combine),对数据基于某一些规则将数据源拆成若干组,apply是对每一组独立地使用函数,combine指将每一组的结果组合成某一类数据结构.
3.1 准备本次实验平台为: Jupyter Notebook、Numpy、Pandas
# 导入基本库 import pandas as pd3.2 分组模式及其对象 3.2.1 单一分组
分组操作在日常生活中使用极其广泛,例如:
依据 性别 分组,统计全国人口 寿命 的 平均值
依据 班级 分组,筛选出组内 分数 的 平均值超过80分的班级
从上述的几个例子中不难看出,想要实现分组操作,必须明确三个要素:分组依据 、 数据来源 、 操作及其返回结果 。同时从充分性的角度来说,如果明确了这三方面,就能确定一个分组操作,从而分组代码的一般模式即:
dataframe.groupby(分组依据)[数据来源].使用操作
例如:
统计泰坦尼克号男性与女性的平均票价
# dataframe: result 分组依据 result["Sex"] 数据来源result.groupby(result["Sex"])["Fare"] # 具体操作 mean() result.groupby(result["Sex"])["Fare"].mean()
统计泰坦尼克号中男女的存活人数
# dataframe result 分组依据 result["Sex"] 数据来源["Survived"] 具体操作 sum() result.groupby(result["Sex"])["Survived"].sum()
统计客舱不同等级的存活人数
result.groupby(result["Pclass"])["Survived"].sum()3.2.2 多维分组
前面提到的若干例子都是以单一维度进行分组的,比如根据性别,如果现在需要根据多个维度进行分组,该如何做?事实上,只需在 groupby 中传入相应列名构成的列表即可。
比如:
统计在不同等级的票中的不同年龄的船票花费的平均值
# 分组依据 Pclass与Age 数据来源 Fare 具体操作 mean() result.groupby(["Pclass", "Age"])["Fare"].mean()3.2.3 逻辑布尔运算分组
目前为止, groupby 的分组依据都是直接可以从列中按照名字获取的,那如果希望通过一定的复杂逻辑来分组.
比如:
根据年龄大于18岁小于四十岁的男女存活人数分组
从索引可以看出,其实最后产生的结果就是按照条件列表中元素的值(此处是 True 和 False )来分组
# 分组条件 condition = (result["Age"] > 18) & (result["Age"] < 40) result.groupby(condition)["Survived"].sum()3.2.4 Groupby对象
我们注意到最终具体做分组操作时,所调用的方法都来自于 pandas 中的 groupby 对象,这个对象定义了许多方法与属性,本次我们主要说明一些主要使用的方法与属性。
# 查看定义的方法与属性
print([attr for attr in dir(grouped_single) if not attr.startswith('_')])
groups与ngroups属性,返回从组名映射到组索引列表的字典,以及分组个数
result.groupby(result["Sex"])["Survived"].groups # result.groupby(result["Sex"])["Survived"].ngroups
size() 在 groupby 对象上表示统计每个组的元素个数
result.groupby(result["Sex"])["Survived"].size()
get_group() 可以直接获取所在组对应的行,但必须提前知道组的具体名字
gb = result.groupby(result["Sex"])
gb.get_group("male")
3.2.5 聚合函数
知识点:
- 内置聚合函数
直接定义在groupby对象的聚合函数,因为它的速度基本都会经过内部的优化,使用功能时应当优先考虑。大致:max/min/mean/median/count/all/any/idxmax/idxmin/mad/nunique/skew/quantile/sum/std/var/sem/size/prod
- agg()方法
虽然在 groupby 对象上定义了许多方便的函数,但仍然有以下不足:
无法对特定的列使用特定的聚合函数无法使用自定义的聚合函数无法同时使用多个函数
agg()方法可以解决上述问题
# 多列使用多个函数
result.groupby('Sex').agg({'Fare': 'mean', 'Pclass': 'count'}).rename(columns=
{'Fare': 'mean_fare', 'Pclass': 'count_pclass'})
# 使用自定义函数
result.groupby('Sex').agg(lambda x: x.mean()-x.min())
3.3 数据索引变形
知识点:
stack()与unstack()函数unstack() 函数的作用是把行索引转为列索引,unstack() 的主要参数是移动的层号,默认转化最内层,移动到列索引的最内层,同时支持同时转化多个层。与 unstack() 相反, stack() 的作用就是把列索引的层压入行索引,其用法完全类似
result = pd.read_csv('result.csv')
unit_result= result.stack()
unit_result.head()
3.4 数据合并
知识点:
把两张相关的表按照某一个或某一组键连接起来是一种常见操作, 在关系型连接中,键是十分重要的,往往用参数on表示。另一重要的是连接的方式, 在pandas 中的关系型连接函数 merge 和 join 中提供了 how 参数来代表连接形式,分为左连接 left 、右连接 right 、内连接 inner 、外连接 outer
具体区别:https://www.cnblogs.com/yyjie/p/7788413.htmlpandas中给我们定义了append、assign、combine、update、concat、merge以及join这些方法来帮助完成数据合并流程
请思考什么是append/assign/combine/update/concat/merge/join各自最适合使用的场景。
append: 通过dict Series或Dataframe对象向Dataframe对象添加新的行 不会修改原来的Dataframe 而是创建一个新的副本 是concat 在行添加方向的快捷方法 assign:通过Series 或者Dataframe中的可调用的列(lambda方法) 添加到Dataframe 返回一个Dataframe combine: 与另一个Dataframe按列组合,这里是按照规则进行逐列组合,自动索引对齐,缺失值补充为NaN update:使用来自另一个Dataframe的非NaN值就地进行修改,在索引上对齐,没有返回值 concat:通过dict Series或Dataframe在一个维度拼接另一个维度取并或交集 根据join方式 比较使用于添加任意数量的Dataframe 不过最好需要使用列表表达式,因为concat()制作了数据的完整副本 merge:将两个pandas对象横向合并,遇到重复的索引项时会使用笛卡尔积。与concat在axis=1的差别在于on参数可以指定在key值下连接 join:这是将两个可能具有不同索引的列Dataframes合并为单个结果的便捷方法3.4.1:使用concat方法进行数据合并
知识点:
在 concat() 中,最常用的有三个参数,它们是 axis, join, keys ,分别表示拼接方向,连接形式,以及在新表中指示来自于哪一张旧表的名字。这里需要特别注意, join 和 keys 与 join 函数和键的概念没有任何关系。在默认状态下的 axis=0 ,表示纵向拼接多个表,常常用于多个样本的拼接;而 axis=1 表示横向拼接多个表,常用于多个字段或特征的拼接。纵向拼接会根据列索引对其,默认状态下 join=outer ,表示保留所有的列,并将不存在的值设为缺失; join=inner ,表示保留两个表都出现过的列。横向拼接则根据行索引对齐, join 参数可以类似设置。keys 参数的使用场景在于多个表合并后,用户仍然想要知道新表中的数据来自于哪个原表,这时可以通过 keys 参数产生多级索引进行标记。
#写入代码 result_up = pd.concat([train_left_up, train_right_up], axis=1) result_down = pd.concat([train_left_down, train_right_down], axis=1) result = pd.concat([result_up, result_down], axis=0) result.head()
# 内连接 pd.concat([train_left_up, train_right_up], axis=1, join="inner")3.4.2 使用join、assign和append方法进行数据合并。
知识点:
append()函数把一个序列追加到表的行末。在 append 中,如果原表是默认整数序列的索引,那么可以使用 ignore_index=True 对新序列对应的索引自动标号,否则必须对 Series 指定 name 属性。assign()函数把一个序列追加到表的列末。对于 assign 而言,虽然可以利用其添加新的列,但一般通过 df['new_col'] = ... 的形式就可以等价地添加新列。同时,使用 [] 修改的缺点是它会直接在原表上进行改动,而 assign 返回的是一个临时副本。join() 函数来处理索引连接。主要参数为: on 和how以及lsuffix和rsuffix。
#写入代码 result_join_up = train_left_up.join(train_right_up) result_join_down = train_left_down.join(train_right_down) result_append = result_join_up.append([result_join_down]) result_append.head()3.4.3 使用merge完成数据合并
知识点:
merge()用于两张表根据某一列的值来连接。主要参数为: left_on、right_on、on以及suffix。两个表中想要连接的列不具备相同的列名,通过left_on与right_on指定。如果两个表中的列出现了重复的列名,那么可以通过 suffixes 参数指定。在某些时候出现重复元素是麻烦的,这种时候就要指定 on 参数为多个列使得正确连接。
#写入代码 result_up = pd.merge(train_left_up,train_right_up,left_index=True,right_index=True) result_down = pd.merge(train_left_down,train_right_down,left_index=True,right_index=True) result = result_up.append(result_down) result.head()3.5 总结
在现实生活中,需要对刚拿到手的数据进行很多的预处理,数据集的重构是我们数据分析前期比较重要的任务,因此特别需要耐心和谨慎来做数据的预处理,也许它不是最难的,但它一定是最麻烦的。



