groupby分为三个步骤:?拆分-应用-合并?
? ? ?groupby对象支持迭代,会生成一个包含组名和数据块的2维元组序列
import pandas as pd
road = "E:\python 资料\孙兴华 数据分析教程\Pandas课件\课件\pandas教程\课件026\分组聚合.xlsx"
data = pd.read_excel(road)
# 遍历 城市 和 区 这两列
for (i,j),group in data.groupby(["城市","区"]): #城市列赋值给i,区列赋值给j
print((i,j))
print(group)
?
? ? ? ? 对于由DataFrame产生的GroupBy对象,如果用单个列名或一组列名对其进行索引,就能实现选取部分列进行聚合的目的
参数说明:
? ? ? ? ? ? ?黄色部分:dataframe的列名,指要根据哪些列分组;也可传入一个判断语句
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 如:data.序号%2 == 0? 一一>??筛选出偶数序号
? ? ? ? ? ? ?红色部分:产生的groupby对象的列名,指要对哪些列去做聚合
? ? ? ? ? ? ?蓝色部分:聚合的方式
? ? ? ? ? ? ?as_index:是否用分组键作为索引(默认True)
juhe = data.groupby(['城市','区'])[['人数','金额']].sum()
print(juhe)
? ? ? ? 如果我们的分组信息,是以某种对应关系的方式给定,那么我们就可以利用字典来进行分组
import pandas as pd
road= "E:\python 资料\孙兴华 数据分析教程\Pandas课件\课件\pandas教程\课件026\分组聚合2.xlsx"
data = pd.read_excel(road,index_col='店号') #指定店名这一列,用作行名
print(data)
Correspondence = {'1月':'一季度','2月':'一季度','3月':'一季度','4月':'二季度'} #根据对应关系分组
data2 = data.groupby(Correspondence,axis=1) # 传入对应关系,按行分组
print(data2.sum()) # 聚合
? ? ? ? 我们要对哪个列进行分组,就把哪个列设为索引,然后直接在groupby中传入函数即可?
import pandas as pd
road = "E:\python 资料\孙兴华 数据分析教程\Pandas课件\课件\pandas教程\课件026\分组聚合.xlsx"
data = pd.read_excel(road,index_col='城市') #对哪个列进行分组,就把他设成索引
data2 = data.groupby(len)[['人数','金额']].sum()
print(data2)
? ? ? 这种方式是针对于分层索引的数据集,我们可以在轴索引的某个层级上进行聚合
import pandas as pd
road = 'E:\python 资料\孙兴华 数据分析教程\Pandas课件\课件\pandas教程\课件026\分组聚合3.xlsx'
data = pd.read_excel(road,index_col=[0,1]) # 设置分层索引
data2 = data.groupby(level='班级').mean()
print(data2)
?
? ? ? ? ? 聚合是指所有根据数组产生标量值(如mean、sum)的数据转换过程。
? ? ? ? ? 前面我们已经介绍过一些聚合操作,例如count(计数)、sum、mean、prod(乘积),这些方法都已经经过groupby优化,会自动排除NA值?
下面介绍agg函数:
? ? ? ?agg函数一般与groupby配合使用,agg是基于列的聚合操作,而groupby是基于行的?
?参数及注意事项:
- 若不是python内建函数,要以字符串形式输入函数名;若为自建函数,必须用agg接收
- func位置可以接收:函数,函数列表,字典{‘行名/列名’:‘函数名’}
- args位置用于接收函数的参数
? ?
? ? ? ? 若要同时使用多个函数,直接agg中传入一个包含多个函数的列表即可(字符串形式)
?我们也可通过传入多个(name,function)元组类型构成的列表,来使name作为聚合后的列名?
import pandas as pd
road = 'E:\python 资料\孙兴华 数据分析教程\Pandas课件\课件\pandas教程\课件026\分组聚合3.xlsx'
data = pd.read_excel(road,index_col=[0,1]) # 设置分层索引
data2 = data.groupby(level = 0)["语文"].agg([("均值",'mean'),("总和",'sum')])
print(data2)
? ? 若要在不同的列,实现不同的计算,我们可以给agg传递一个 含有列名与函数对应关系的字典?
# 仍然使用前面的数据
correspond = {"语文":"mean","数学":"sum"} # 列和函数的对应关系
data3 = data.groupby(level=0).agg(correspond)
print(data3)
??在数据分组后,经常会对一个DataFrame或GroupBy进行逐行、逐列和逐元素的操作,Pandas中的 map \ apply??可以解决绝大部分这样的数据处理需求
? ? ? ? ? map会根据提供的函数或字典对指定序列做映射,它更多地适用于简单的批量处理数据,function中的参数最好只有一个
- 语法:map(字典) 或? ?data.map(function)或 map(function,data)
? ? ? ? ? ? ?一般使用匿名函数 lambda 去定义函数,进行操作?
import pandas as pd
road = "E:\python 资料\孙兴华 数据分析教程\Pandas课件\课件\pandas教程\课件030-031\数据2.xlsx"
data = pd.read_excel(road)
print(data)
print("-"*40)
data2 = data.map(lambda x:"%.2f" % x) #每个元素保留两位小数
print(data2)
print("-"*40)
data3 = data.map(lambda x: x ** 2) #每个元素的平方
print(data3)
? ? ? ?在原数据中新增两列,?若为男就是先生,若为女就是女士;再根据体重判断体型,若大于80kg就是魁梧,小于80kg就是瘦小
import pandas as pd
road = "E:\python 资料\孙兴华 数据分析教程\Pandas课件\课件\pandas教程\课件030-031\数据2.xlsx"
data = pd.read_excel(road)
print(data)
print("-"*40)
data2 = data.map(lambda x:"%.2f" % x) #每个元素保留两位小数
print(data2)
print("-"*40)
data3 = data.map(lambda x: x ** 2) #每个元素的平方
print(data3)
apply() 函数的自由度较高,可以直接对 DataFrame 中元素进行逐元素的遍历操作,方便且高效;与map相比,它可以在一个函数中传入多个参数来使用,适用范围较广(可传入更复杂的函数)
参数说明:
? ? ? ? ? ?axis = :沿哪个轴进行数据处理(默认为0,处理每一列)
? ? ? ? ? ?row = :0表示把每一行或列作为 Series 传入函数中;1表示接收ndarry数组
? ? ? ? ? ?arg = :若函数有多个参数,则传入一个元组,接收第二至最后一个参数??
?其余说明事项:
- 在处理多个参数时,需要用arg参数接收第二至最后一个参数
- 在处理多行时,直接在data位置传入 dataframe 或者 df切片后的多列即可
- 当axis=1对行进行操作时,会默认将每一行数据以Series的形式(Series的索引为列名)传入指定函数,返回相应的结果;axis = 0同理
? ? ? ?要求:仍然使用map中案例二的数据,修改分数:所有人的语文成绩 +5 分?
def score_change(x,y): # x为科目,y为修改值
return x + y
#arg传入一个元组,接受第二个参数
data["语文"] = data["语文"].apply(score_change,args=(5,))
? 要求:计算每个人(逐行)三科的总成绩,并根据总成绩排序
data["总成绩"] = data[['语文','数学','英语']].apply(sum,axis=1) # 逐行相加
data = data.sort_values (by="总成绩",ascending=False) # 根据总成绩降序排序
print(data)
? ? ? ?要求:计算每个人的bmi
def BMI(data):
height = data["身高"]
weight = data["体重"]
BMI =weight / height ** 2
return BMI
data["BMI"] = data.apply(BMI,axis=1)
print(data)
透视表是一种可以对数据动态排布并且分类汇总的表格格式
可以让我们从不同的角度去分析一个大数据库,有点类似于分类筛选的高阶版操作
? 该部分笔记参考了以下文章:
? ? ? ? ?pivot_table ( data,? index = None,? values = None,??columns = None,? aggfunc = 'mean' )??
常用参数说明:?
? ? ? ? ? ? ? ? ? ?index:? 设置行分层字段,将选中的列设为行索引? ?👇
? ? ? ? ? ? ? ? ? ?values:输入一个含列名的列表,筛选我们需要保留的列
? ? ? ? ? ? ? ? ? ?columns:类似Index设置列分层字段,将选中的列设为列索引? ?👉
? ? ? ? ? ? ? ? ? ?aggfunc:设置我们对数据聚合时进行的函数操作,默认为 mean
? ? ? ? ? ? ? ? ? ?fill_value:替换缺失值
? ? ? ? ? ? ? ? ? ?drop_na:是否去除所有条目均为NA的列(默认False,不去除)
? ? ? ? ? ? ? ? ? ?margins:是否添加行 / 列计数 及 总计数(默认False,不添加)
? ? ? ?下面我们以詹姆斯某赛季的数据为例,来对pivot_table函数进行讲解
? step1? 首先导入数据,并展示前五场:
import pandas as pd
import numpy as np
road = "E:\python 资料\孙兴华 数据分析教程\Pandas课件\课件\pandas教程\课件028-029\Lebron_James.csv"
data = pd.read_table(road,sep=",")
print(data.head(5))
?step2??需要james在主客场和不同胜负情况(index)下的得分、篮板与助攻(values)三项数据
data1 = pd.pivot_table(data, index=['对手', '主客场'],values=['得分','助攻','篮板'])
print(data1.head(5))
? ?step3??我们还想获得james在主客场和不同胜负情况下的总得分、总篮板、总助攻(aggfunc)
? ? ? ? ? ? ? 此时应该向aggfunc中输入sum函数,按层次求和
# 这里要注意mean不是内置函数,它是numpy中的一个函数
data2 = pd.pivot_table(data, index=['对手', '主客场'],values=['得分','助攻','篮板'],
aggfunc=[sum,np.mean])
print(data2.head(5))
??step4??我们也可以通过columns再设置一个列索引,并且通过margin来汇总
# fill_value填充空值,margins=True进行汇总
data3 =pd.pivot_table(data,index=['主客场'],columns=['对手'],values=['得分'],aggfunc=[np.sum],fill_value=0,margins=1)
print(data3)
? ? 数据交叉表(crosstab)是数据透视表的一个特殊情况,计算的是分组的频率(count)
# 仍然使用上述数据
data2 = pd.crosstab([data.主客场,data.胜负],data.得分,margins=True)
print(data2)
import pandas as pd
road = "E:\python 资料\孙兴华 数据分析教程\Pandas课件\课件\pandas教程\课件028-029\Vlookup.xlsx"
data1 = pd.read_excel(road,sheet_name="花名册")
data2 = pd.read_excel(road,sheet_name="成绩单")
# 将 花名册 与 成绩单中的总分、学号 合并
hebing = pd.merge(data1,data2.loc[:,["学号","总分"]],how = "left",on = "学号")
print(hebing)
print("-" * 40)
# 将总分放到第二列的位置
score = hebing.总分 # 提取出 总分 列
hebing = hebing.drop("总分",axis = 1) # 在原数据中删除该列
hebing.insert(1,"总分",score) # 在原数据第二列插入新列
print(hebing)
?