前言:
💞💞大家好,我是书生♡,本阶段和大家一起分享和探索数据分析,本篇文章主要讲述了【Pandas高手进阶:掌握分组分箱与合并变形,解锁数据整理新技能】等等。欢迎大家一起探索讨论!!!
💞💞代码是你的画笔,创新是你的画布,用它们绘出属于你的精彩世界,不断挑战,无限可能!
个人主页⭐: 书生♡
gitee主页🙋♂:闲客
专栏主页💞:大数据开发
博客领域💥:大数据开发,java编程,前端,算法,Python
写作风格💞:超前知识点,干货,思路讲解,通俗易懂
支持博主💖:关注⭐,点赞、收藏⭐、留言💬
目录
1. 分组
分组 (Grouping):
分组是指将数据集中的记录按照一个或多个特定的列(字段)进行分类的过程。在Python的Pandas库中,groupby()函数就是用来实现这一功能的。当你对数据进行分组后,可以对每个分组执行各种统计运算,如求和、平均值、计数等,从而更好地理解数据的分布和特性。
例如,假设你有一个销售数据集,你可以按产品类别分组,然后计算每类产品的总销售额。
这有助于识别哪些产品线表现最好。
2. 分组对象DataFrameGroupBy
数据准备:
# 导包:
import pandas as pd
import numpy as np
# 加载数据
df = pd.read_csv('../data/LJdata.csv')
df.head()
2 .1 groupby分组函数返回分组对象
2.1.1 分组操作
分组对象 --创建分组对象
df.groupby(by=[分组列1, 分组列2, ...], as_index=)
- by: 根据指定的列进行分组
- as_index: 是否将分组列作为索引, 默认为True
- 返回分组对象, 可以使用分组对象的其他方法和属性
当你调用groupby()函数时,它并不立即执行任何计算,而是返回一个DataFrameGroupBy或SeriesGroupBy对象,具体取决于你是在DataFrame还是Series上调用的groupby()。
这个返回的对象是一个可迭代的容器,包含了原始数据的不同分组。每个分组都是由一组行组成的,这些行共享相同的分组键值。你可以将DataFrameGroupBy或SeriesGroupBy对象视为一个“视图”,允许你对每个分组执行进一步的操作,如聚合、转换或过滤等。
- 基于一列进行分组操作
group_df = df.groupby(by=['户型'], as_index=False)
group_df
- 基于多列进行分组操作
group_df1 = df.groupby(by=['户型','朝向'], as_index=True)
print(group_df1)
2.1.2 分组聚合操作
调用聚合函数,分组计算
group_df.agg(聚合函数)
group_df.agg([聚合函数1, 聚合函数2, ...])
返回的分组对象可以直接使用,或选择一列做聚合、转换、过滤操作;比如要计算不同区域、不同户型的平均租金
# 对所有列求平均值,只对数值列进行聚合
group_df1 = df.groupby(by=['户型','朝向'], as_index=True)
group_df1.mean()
2.2 取出每组第一条或最后一条数据
df.first()
df.last()
加载数据:
group_df = df.groupby(by=['户型'], as_index=False)
- 取每组第一条数据
# 取出每组第一条
group_df.first()
- 取每组最后一条数据
group_df.last()
2.3 获取分组后每组的名称(索引)
获取组名索引
df.grouper.result_index
加载数据:
group_df1 = df.groupby(by=['户型','朝向'], as_index=True)
获取组名索引
#获取组名索引
group_df1.grouper.result_index
2.4 get_group()按分组依据获取其中一组
当你使用groupby()方法对数据进行分组后,可以使用get_group()方法从DataFrameGroupBy对象中提取特定分组的数据。get_group()方法接收一个参数,即你想要提取的分组的键值,然后返回与该键值对应的所有行组成的DataFrame。
df.get_group(name = 列名1)
按分组依据获取一组
df.get_group((列名1,列名2))
按分组依据获取多组
列名必须是我们的分组字段其参数确实是用来指定你想要从中提取数据的分组。这个参数必须是groupby()操作中使用的分组字段的一个有效值,而不是列名本身。
加载数据:
group_df = df.groupby(by=['户型','朝向'], as_index=True)
- 根据分组字段获取其中的一组
group_df.get_group(name='1室0厅')
- 根据分组字段获取其中的多组
group_df1.get_group(('1室0厅','东'))
3. 分组聚合
分组聚合(Group By)是一种非常强大的功能,用于对数据集进行分组并应用聚合函数。这可以让你按一个或多个列的值对数据进行分类,并对每一类执行统计计算,如求和、平均数、最大值、最小值等。
加载数据:
df = pd.read_csv('../data/LJdata.csv')
df.head()
3.1 分组后直接聚合
分组后直接进行聚合计算并返回df
df.groupby(by=[列名1, 列名2, ...]).聚合函数()
- 统计每个户型的个数,只统计数值列,非缺失值的数量
# 统计每个户型的个数,只统计数值列,非缺失值的数量
df.groupby(by=['户型']).count()
- 分组列不作为索引,默认将分组字段作为索引,设置成False可以不设置成索引
# 分组列不作为索引
df.groupby(by=['户型'], as_index=False).count()
- 统计每个户型个数(唯一值 )
# 统计每个户型个数(唯一值 )
df.groupby(by=['户型']).nunique()
3.2 分组后指定单列或多列聚合
分组后指定单列或多列聚合
df.groupby(['列名1', '列名2'])['指定列1'].聚合函数()
df.groupby(['列名1', '列名2'])[['指定列1', '指定列2', ...]].聚合函数()
3.2.1 一列进行分组一列/多列聚合操作
# 统计一列进行分组一列/多列聚合操作
print(df.groupby(by=['户型'])[['价格']].mean())
df.groupby(by=['户型'])[['价格', '面积']].mean()
3.2.2 多列进行分组一列聚合操作
# 统计多列进行分组一列聚合操作
df.groupby(by=['户型', '朝向'])[['价格']].mean()
3.2.3 多列进行多列分组多列聚合操作
# 统计多列进行多列分组多列聚合操作
df.groupby(by=['户型', '朝向'])[['价格', '面积']].mean()
3.3 分组后使用多个聚合函数
同时使用多个内置聚合函数,全部放入一个Python列表,
然后把整个列表传入agg或aggregate函数中;返回以分组列作为索引,每一个聚合计算结果作为列的全新df
df.groupby(['列名1', '列名2'])[['指定列1', '指定列2']].agg(['函数名', '函数名'])
- 一列进行分组一列/多列多聚合操作,每一个列多会进行多次聚合
# 统计一列进行分组一列/多列多聚合操作,每一个列多会进行多次聚合
df.groupby(by='户型')[['价格', '面积']].agg(['mean', 'max','min'])
3.4 分组后对多列分别使用不同的聚合函数
agg
函数中可以传入字典,字典的key是df的列名,与key对应的value是pandas内置的聚合计算函数、其名称的字符串;返回以分组列作为索引,每一个聚合计算结果作为列的全新df
df.groupby(by=['分组字段', '分组字段']).agg({ '数值列':'函数', '数值列':'函数', '数值列':'函数' })
# 分组后对多列分别使用不同的聚合函数
df.groupby(by=['户型', '朝向']).agg({
'价格':'mean',
'面积':'sum',
'看房人数':'max'
})
3.5 分组后使用自定义聚合函数
分组之后指定列,对该列的值使用自定义的函数
分组后使用自定义聚合函数
df.groupby(['列名1', '列名2']).agg(函数)
df.groupby(['列名1', '列名2']).agg(函数, args1=xxx, args2=xxx)
df.groupby(['列名1', '列名2'])['指定列1', '指定列2'].agg(函数, args1=xxx,args2=xxx)
- 自定义函数,没有别的参数
# 定义自定义函数
def func(s):
# 参数s是分组之后指定的每一列
s_mean = s.sum() / s.size
return s_mean
res = df.groupby('区域')[['价格', '看房人数']].agg(func)
print(res)
# 与下面的代码效果相同
# df.groupby('区域')[['价格', '看房人数']].mean()
- 定义自定义函数,有其他的参数
# 定义自定义函数,有其他的参数
def func(s,arg1):
# 参数s是分组之后指定的每一列
s_mean = s.sum() / s.size
return s_mean+arg1
res = df.groupby('区域')['价格'].agg(func,arg1=100)
print(res)
4. 分组转换聚合
转换 (Transforming)
转换是在每个分组上执行某种函数,但结果会与原始DataFrame的形状保持一致。这意味着转换函数会应用于每个分组,然后将结果重新组合成与原DataFrame相同形状的新DataFrame。
加载数据:
df = pd.read_csv('../data/LJdata.csv')
df.head()
4.1 分组后指定列数据转换聚合
分组后,对指定列的值做聚合计算,只返回计算结果,不返回分组情况
分组转换聚合 -> 类似于sql中窗口函数操作
df.groupby(['列名1', '列名2'])['指定列1', '指定列2'].transform('函数')
函数可以是内置函数 sum/mean/max/min, 也可以是自定函数
分组聚合和分组转换聚合的区别:
- 分组聚合: 有多少组, 就有多少行结果
- 分组转换聚合: 不改变原数据的行数据, 将每组的聚合结果放到每行数据后
# 分组转换聚合 -> 类似于sql中窗口函数操作
# df.groupby(by=, as_index=)[[列名1, 列名2, ...]].transform(函数名)
# 函数可以是内置函数 sum/mean/max/min, 也可以是自定函数,只能跟一个函数
# 分组聚合: 有多少组, 就有多少行结果
# 分组转换聚合: 不改变原数据的行数据, 将每组的聚合结果放到每行数据后
df.groupby(by=['户型'])[['价格','面积']].transform('mean')
- 使用分组转换聚合,生成新的一列,导入到df中
# 使用分组转换聚合,生成新的一列,导入到df中
df['平均价格'] = df.groupby(by='户型')['价格'].transform('mean')
df['价格差值'] = df['价格'] - df['平均价格']
df
4.2 分组后使用自定义函数进行转换聚合
transform使用自定义的函数,注意此时传入的函数名没有引号
- 函数不传递其它参数
def func(s):
# 参数s是分组之后指定的每一列
s_mean = s.sum() / s.size
return s_mean
df.groupby(by=['户型'])[['价格','面积']].transform(func)
- 自定义函数带有其他参数
# 自定义函数带有其他参数
def func2(x, arg1):
ret = x.sum() / x.count()
return ret + arg1
df.groupby(by='户型')[['价格', '看房人数']].transform(func=func2, arg1=10)
4.3 分组聚合 和 分组转换的区别
在Pandas中,分组聚合(Aggregation)和分组转换(Transformation)是两种不同的数据操作方式,尽管它们都是在数据分组后进行的,但它们的目的和输出有所不同。
- 分组聚合 (Aggregation)
分组聚合的主要目的是减少数据维度,通过计算每个分组的统计摘要来生成新的DataFrame或Series。聚合函数通常包括求和(sum)、平均值(mean)、最大值(max)、最小值(min)等。聚合操作的结果通常是比原始数据集更小的数据结构,因为每个分组被压缩成了单个值或少量值。
- 分组转换 (Transformation)
分组转换则是在每个分组上执行一个函数,但结果会与原始DataFrame的形状保持一致。这意味着转换操作会为每个分组产生一个结果,然后将这些结果重新组合成与原始DataFrame相同形状的新DataFrame。转换通常用于标准化数据、计算比率或执行其他需要保留每个观察值级别的操作。
总结
- 聚合通常用于生成汇总统计数据,输出结果的行数少于或等于原始数据集。
- 转换则保留了原始数据集的行数,但可能修改了列值,适用于需要在每个数据点级别进行计算的情况。
5. 分组过滤
分组后接filter方法,filter传入一个返回布尔值的匿名函数,该函数的入参就是groupby分组之后的每一组数据或是每组选中的一列数据,返回False的数据会被过滤掉。
分组过滤操作,保留True对应的组数据
df.groupby(by=, as_index=).filter(返回布尔值的函数)
返回布尔值的函数: 一般写匿名函数, 返回布尔值s对象
- 分组过滤操作----s对象
# 分组过滤操作
# 匿名函数中的x就是每组的s对象
df.groupby(df['户型'])[['价格']].filter(lambda x: x.mean() > 5000)
- 分组过滤操作----df对象
# 匿名函数中的x就是每组的df, 每组中的价格列数据
df.groupby(by='户型').filter(lambda x: x['价格'].mean() > 5000)
6. 分箱(数据离散化)
6.1 概述
分箱(Binning),也称为数据离散化,是数据预处理中的一个重要步骤,主要用于将连续型变量转换为分类变量。通过分箱,可以简化模型,使数据更易于理解和分析,同时也能处理异常值和缺失值等问题。分箱技术广泛应用于数据挖掘、机器学习和统计分析中。
分箱的类型
分箱主要分为以下几种类型:
-
等深分箱(Equal-depth binning):也称为等频分箱,将数据划分为具有相同数量观察值的区间。这样每个箱子里的样本数大致相同。
-
等宽分箱(Equal-width binning):将数据范围分成宽度相等的区间。这种分箱方式下,箱子的宽度是固定的,但每个箱子里的样本数可能不同。
-
自定义分箱:根据业务需求或领域知识,手动定义区间边界进行分箱。这种方式灵活性高,但需要更多的领域知识来确定边界。
分箱的应用
分箱在多种场景下都有应用:
- 数据简化:减少连续变量的维度,使其成为分类变量,便于某些算法(如决策树)的处理。
- 异常值处理:通过分箱,可以将极端值归入特定的区间,避免异常值对模型的影响。
- 缺失值填充:分箱后,可以用箱的中心值或众数填充缺失值。
- 数据可视化:分箱有助于创建直方图和箱线图等,使得数据分布更加清晰。
在Pandas中实现分箱
在Pandas库中,有两种主要的函数用于实现分箱:
pd.cut()
:用于等宽分箱或自定义分箱,可以指定边界。pd.qcut()
:用于等深分箱,基于数据的分布来决定箱的边界。
6.2 数据离散化(分箱) --cut
数据离散化(分箱)
-
数据离散化(分箱) -> 根据列值对数据进行分组, 根据身高值分成 高中低 类似于sql中的case when
-
pd.cut(x=, bins=, labels=, right=, include_lowest=)
- x:需要分箱的列数据 df[列名]
- bins:分箱的边界值, 接受列表 [0, 10, 20, 30]
- labels:分箱后的组名, 如果不指定,根据边界值自动生成->组名[0, 10)
- right: 是否包含边界值, 默认True左开右闭 False左闭右开
- include_lowest: 是否包含第一组中的起始边界值 默认False不包含 True包含
- 根据列值对数据进行分组
# 数据离散化(分箱), 根据列值对数据进行分组, 根据数据值大小分成 高中低
pd.cut(x=df['面积'],bins=[19,70,100,720])
2. 不同的分组区间设置组名
# 设置组名
pd.cut(x=df['面积'],bins=[19,70,100,720],labels=['小户型','中户型','大户型'])
3.设置边界值,默认True左开右闭 False左闭右开
# 设置边界值,默认True左开右闭 False左闭右开
pd.cut(x=df['面积'],bins=[19,70,100,720],right=False)
4. include_lowest: 是否包含第一组中的起始边界值 默认False不包含 True包含
# include_lowest: 是否包含第一组中的起始边界值 默认False不包含 True包含
pd.cut(x=df['面积'],bins=[19,70,100,720],include_lowest=True)
5. 全部参数设置
# 全部参数设置
df['户型大小']=pd.cut(x=df['面积'],bins=[19,70,100,720],labels=['小户型','中户型','大户型'],right=False,include_lowest=True)
df
7. Dataframe合并
很多情况需要将多个df合并为一个新的df,常用方法如下
df1.append(df2)
纵向合并数据集pd.concat([df1, df2, ...])
横向或纵向合并数据集,df1和df2可以没有任何关系, 根据行索引和列名相同合并df1.merge(df2)
横向合并, df1和df2要有关联的列, 类似SQL中的表关联操作df1.join(df2)
横向合并,df1和df2要有相同的索引值才能关联
导包,加载数据:
import pandas as pd
import numpy as np
df1 = pd.DataFrame([[1, 2, 3], [1, 10, 20], [5, 6, 7], [3, 9, 0], [8, 0, 3]], columns=['x1', 'x2', 'x3'])
df2 = pd.DataFrame([[1, 2], [1, 10], [1, 3], [4, 6], [3, 9]], columns=['x1', 'x4'])
print(df1)
print(df2)
7.1 append函数纵向追加合并df
df.append()`函数纵向连接其他df重置索引返回新的df
- append(): 根据列名匹配,将两个df进行纵向合并, 列名匹配失败的用NaN填充 类似于sql的union all
df.append(other=, ignore_index=)
- other: 要合并的df
- ignore_index: 是否重置合并后的df索引, 默认False
- 两个df进行纵向合并,不重置索引
# 根据列名匹配,将两个df进行纵向合并, 列名匹配失败的用NaN填充
df1.append(other=df2)
- 两个df进行纵向合并,重置索引
设置
ignore_index=True
# 重置合并后的df索引
df1.append(other=df2,ignore_index=True)
# 等价于
df1.append(df2).reset_index(drop=True)
7.2 concat函数纵向横向连接多个数据集
- pd.concat()`函数纵向连接多个数据集,N个df从上到下一个摞一个:
- 不使用
join='inner'
参数,数据会堆叠在一起,列名相同的数据会合并到一列,合并后不存在的数据会用NaN填充- 使用
join='inner'
参数,只保留数据中的共有部分pd.concat(axis=1)
函数横向连接多个数据集,N个df从左到右一个挨着一个:
- 匹配各自行索引,缺失值用NaN表示
- 使用
join='inner'
参数,只保留索引匹配的结果
语法格式;
- concat(): 根据索引或列名匹配, 将两个df进行横向或纵向合并, 索引或列名不同,用NaN填充
pd.concat([df1, df2, ...], axis=, join=, ignore_index=)
- axis: 0->纵向合并 默认 ,1->1横向合并
- join: inner->交集, outer->并集,默认
- 纵向合并
# 根据索引或列名匹配, 将两个df进行横向或纵向合并, 索引或列名不同,用NaN填充
# axis: 0->纵向合并
pd.concat([df1,df2])
- 纵向合并重置索引
# 纵向合并重置索引
pd.concat([df1,df2],ignore_index=True)
- 纵向合并交集
df1 有x1,x2,x3 三列
df2.有 x1.x4
两列列名相同的有x1,因此交集只保留x1的列
# 纵向合并交集
pd.concat([df1,df2],join='inner')
- axis: 1->横向合并
横向合并根据索引值进行匹配
# axis: 1->横向合并
pd.concat([df1,df2],axis=1)
- 横向合并重置索引
# 横向合并重置索引
pd.concat([df1,df2],axis=1,ignore_index=True)
- 横向合并交集
根据索引值进行匹配
# 横向合并交集
pd.concat([df1,df2],axis=1,join='inner')
- 并集
# 并集
pd.concat([df1,df2],join='outer')
7.3 merge合并指定关联列的多个数据集
merge()函数是用于将两个DataFrame按照一个或多个键(列)连接起来的工具,这在数据整合和清洗中非常常见。merge()函数提供了很大的灵活性,允许你以不同的方式连接数据,如内连接、左连接、右连接和全外连接。
写法一:
pd.merge(left=, right=, on=, left_on=, right_on=, how=)
写法二
df.merge(right=,on=, left_on=, right_on=, how=)
- left:左边的DataFrame,通常作为主键的基底。
- right:右边的DataFrame,将与左边的DataFrame进行连接。
- on:用于连接的列名,当左右两边DataFrame的列名相同时使用。如果两边的列名不同,但需要基于同一列进行连接,则应使用
left_on
和right_on
。 - left_on:左边DataFrame用于连接的列名。当左右两边的连接列名不同时,需要显式指定。
- right_on:右边DataFrame用于连接的列名。
- how:指定连接类型,可以是以下之一:
'inner'
:内连接,只保留两个表中连接键共同的部分,这是默认的连接方式。'left'
:左连接,保留左边DataFrame的所有记录,右边的记录如果没有匹配则用NaN填充。'right'
:右连接,保留右边DataFrame的所有记录,左边的记录如果没有匹配则用NaN填充。'outer'
:全外连接,保留两个表中的所有记录,没有匹配的记录用NaN填充。
- x1列关联,默认内关联
pd.merge(left=df1,right=df2,on='x1')
第二种写法:
df1.merge(df2)
- left 左连接
#left 左连接
df1.merge(right=df2,on='x1',how='left')
第二种写法:
#left 左连接
df1.merge(right=df2,on='x1',how='left')
- 左右两个df的关联的列名不同, 使用left_on right_on
# 左右两个df的关联的列名不同, 使用left_on right_on
# select * from a join b on a.字段名=b.字段名
df1.merge(right=df2, left_on='x1', right_on='x4')
总结:
df3 = pd.merge(df1, df2, how='left', on='x1')
df4 = pd.merge(df1, df2, how='right', on='x1')
df5 = pd.merge(df1, df2, how='inner', on='x1')
df6 = pd.merge(df1, df2, how='outer', on='x1')
print(df3) # 下图左1
print(df4) # 下图右上
print(df5) # 下图右中
print(df6) # 下图右下
7.4 df.join横向合并索引值相同的多个数据集
join横向合并索引值相同的多个数据集;通过lsuffix
和rsuffix
两个参数分别指定左表和右表相同的列名后缀,how参数的用法与merge函数的how参数用法一致
- join: 横向合并, 根据一个df的索引值和另外一个df的索引值或列值匹配, 匹配失败的用NaN填充
df.join(other=, on=, how=, lsuffix=, rsuffix=)
- other: 要合并的df
- on: 可选, df1的列名值和要合并的df的索引值进行关联; 不写两个df的索引值进行关联
- how: 关联方式 left左连接默认 right inner outer
- lsuffix: 如果两个df有相同的列名, 必须要设置此参数, 给相同列名添加后缀 _x
- rsuffix 如果两个df有相同的列名, 必须要设置此参数, 给相同列名添加后缀 _y
- 写了on,根据df1的x1列和df2的索引值关联
# 写了on,根据df1的x1列和df2的索引值关联
df1.join(other=df2,on='x1',how='inner',lsuffix='_x',rsuffix='_y')
- 不写on,默认索引值关联
# 不写on,默认索引值关联
df1.join(other=df2,how='inner',lsuffix='_x',rsuffix='_y')
8. Dataframe变形
在Pandas中,DataFrame的“变形”通常指的是改变数据的结构或布局,以适应数据分析的不同需求。这涉及到数据透视、堆叠(stacking)、解堆叠(unstacking)、熔化(melting)和重塑(reshaping)等操作。这些操作可以极大地提高数据的可读性和分析效率。
主要的变形操作包括:
-
数据透视(Pivoting):
使用pivot()
或pivot_table()
函数,可以将DataFrame从长格式转换为宽格式,或反之亦然。这通常涉及到将某列的值转换为列名,将另一列的值转换为行名,而将第三列的值转换为单元格值。 -
堆叠(Stacking):
stack()
方法将最外层的列变成行,适用于多级列索引,可以将宽格式的数据转换成长格式。 -
解堆叠(Unstacking):
unstack()
方法是stack()
的逆操作,它将行转换回列,特别适用于将长格式数据转换回宽格式。 -
熔化(Melting):
使用melt()
函数,可以将宽格式的数据转换成长格式,即将多个列的值转换为单一列,同时将列名转换为另一个列。 -
重塑(Reshaping):
除了上述特定的变形操作,还可以使用apply()
、map()
、applymap()
等方法来重塑DataFrame,这些方法可以应用函数到DataFrame的元素、行或列上,从而改变其结构。
很多情况需要对原数据集进行一些操作,最终导致数据集的形状发生改变(表格的长宽发生变化),这一类操作称之为df变形
变形: 通过df的方法, 将长df转换成宽df或宽df转换成长df
- df.T
- stack & unstack
- melt
- 透视表pivot
- pd.pivot_table
加载数据:
import pandas as pd
import numpy as np
# 加载数据
df1 = pd.DataFrame([[1, 2, 3],
[1, 10, 20],
[5, 6, 7],
[3, 9, 0],
[8, 0, 3]], columns=['x1', 'x2', 'x3'])
df2 = pd.DataFrame([[1, 2],
[1, 10],
[1, 3],
[4, 6],
[3, 9]], columns=['x1', 'x4'])
print(df1)
print(df2)
8.1 df.T行列转置
df1.T
8.2 stack()和unstack()变形
- 数据的层次化结构有两种,一种是表格,一种是“花括号”,
表格形式->dataframe
花括号形式->多列分组结果
- stack函数就是把表格形式(Dataframe对象)变为花括号形式(Seriers对象)
- unstack函数是stack逆操作,把花括号形式(Seriers对象)变为表格Dataframe对象
构建数据:
# 构造示例数据集
df3 = pd.DataFrame([[1, 2, 3], [4, 5, 6]], columns=['store1', 'store2', 'store3'], index=['street1', 'street2'])
# 查看数据集
df3
8.2.1 表格变花括号结构
# 表格变花括号结构
df3.stack()
# 查看索引
df3.stack().index
8.2.2 花括号变表格
# 花括号变表格
s3=df3.stack()
s3.unstack()
8.2.3 表格和花括号互换
- 花括号形式的结构数据
df = pd.read_csv('../data/LJdata.csv')
temp_df = df.groupby(by=['区域', '户型'])[['面积','价格']].mean()
temp_df # 花括号形式的结构数据
- 表格形式
temp_df.unstack()
8.3 melt方法宽变长将列名变为列值
pd.melt()函数,又称为数据融合函数,将指定的一个或多个列名变成一个列的值;如下图所示,可以将宽df变为长df
melt: 将宽表格数据转换成长表格数据
- pd.melt(frame=, id_vars=, value_vars=, var_name=, value_name=)
- df.melt(id_vars=, value_vars=, var_name=, value_name=)
- id_vars: 指定不需要变形的列
- value_vars:指定需要变形的列, 如果不和id_vars参数结合使用,其余列会被删除
- var_name: 修改存储变形列的列名的新列名字 variable(默认名)
- value_name:修改存储变形列的列值的新列名字 value(默认名)
加载数据:
# 加载数据
df = pd.read_csv('../data/music.csv')
df
- 宽表格数据转换成长表格数据,保留不变形的artist和track列
长数据的行数 = 宽数据集变形列的列数*宽数据集行数据
长数据的行数 = 变形的数据值个数
# 宽表格数据转换成长表格数据,保留不变形的artist和track列
# 长数据的行数 = 宽数据集变形列的列数*宽数据集行数据
# 长数据的行数 = 变形的数据值个数
pd.melt(frame=df,id_vars=['artist','track'])
- 指定变形的列,删除其他的列
- value_vars:指定需要变形的列, 如果不和id_vars结合使用, 其余列会被删除
- 将变形列的列名存储到新列variable中, 将变形列的列值存储到新列value中
# value_vars:指定需要变形的列, 如果不和id_vars结合使用, 其余列会被删除
# 将变形列的列名存储到新列variable中, 将变形列的列值存储到新列value中
df.melt(value_vars=['wk1','wk2'])
- 宽表格数据转换成长表格数据,保留不变形的artist和track列
# 宽表格数据转换成长表格数据,保留不变形的artist和track列
df.melt(id_vars=['artist','track'],value_vars=['wk1','wk2'])
- 修改存储变形列的列名的新列名字
var_name: 修改存储变形列的列名的新列名字 variable(默认名)
value_name:修改存储变形列的列值的新列名字 value(默认名)
# var_name: 修改存储变形列的列名的新列名字 variable(默认名)
# value_name:修改存储变形列的列值的新列名字 value(默认名)
df.melt(id_vars=['artist','track'],value_vars=['wk1','wk2'],var_name='week',value_name='score')
9. 透视表
数据透视表就是基于原数据表、按照一定规则呈现汇总数据,转换各个维度去观察数据;和excel的透视表在数据呈现上功能相同
df.pivot_table(
index=‘列名1’,
columns=‘列名2’,
values=‘列名3’,
aggfunc=‘内置聚合函数名’,
margins=True # 默认是False, 如果为True,就在最后一行和最后一列,按行按列分别执行aggfunc参数规定的聚合函数
)
- 使用说明:以列名1作为索引,根据列名2进行分组,对列名3使用pandas内置的聚合函数进行计算,返回新的df对象
- 参数说明:
- index:返回df的行索引,并依据其做分组;传入原始数据的列名
- columns:返回df的列索引;传入原始数据的列名,根据该列做分组
- values: 要做聚合操作的原始数据的列名
- aggfunc:内置聚合函数名字符串
pd.pivot_table(data=, index=, columns=, values=, aggfunc=, margins=)
df = pd.read_csv('../data/LJdata.csv')
df.pivot_table(index=['区域'], columns=['户型'], values=['价格'], aggfunc={'价格':'mean'}, margins=True)
df.pivot_table(index=['区域'], columns=['户型'], values=['价格','面积'], aggfunc={'价格':'mean','面积':'max'}, margins=True)
10. 小结
10.1 分组和分箱
-
分组对象
gs = df.groupby(['列1', '列2'])
按照列1、列2的值对数据集进行分组,返回分组对象gs.first()
返回每组的第一条数据gs.last()
返回每组的最后一条数据gs.grouper.result_index
获取全部组名gs.get_group((组名))
按照
-
分组聚合
-
分组后直接聚合
df.groupby(['列名1', '列名2']).聚合函数()
-
分组后指定单列或多列聚合
df.groupby(['列名1', '列名2'])['指定列'].聚合函数()
-
分组后使用多个聚合函数
df.groupby(['列名1', '列名2'])[['指定列1', '指定列2']].agg(['max', 'min'])
-
分组后对多列分别使用不同的聚合函数
df.groupby(['列名1', '列名2']).agg({ '指定列1':'mean', '指定列2':'sum', '指定列3':'mean' })
-
分组后使用自定义聚合函数
def foo(s): # 参数s 是分组之后指定的每一列 s_mean = s.sum() / s.size return s_mean df.groupby(['列名1', '列名2'])[['指定列1', '指定列2']].agg(foo)
-
-
分组转换
-
分组后指定列数据转换
df.groupby(['列名1', '列名2'])[['指定列1', '指定列2']].transform('pandas内置聚合函数的函数名')
-
分组后使用自定义函数进行转换聚合
def foo(x, y): return x + y df.groupby('列名1')['列名2'].transform(foo, y=3)
-
-
分组聚合和分组转换的区别:二者返回结果的长度不同
- 分组转换返回结果的数据数量对应df的所有行,一一对应
- 分组聚合返回的结果数据仅对应分组的个数
-
分组过滤
# 匿名函数入参就是groupby分组之后的每一组数据或是每组选中的一列数据,返回False的数据会被过滤掉 df.groupby(['列名1',...]).filter( lambda x: dosomething returun True or False )
-
数据离散化(分箱)用来把一组数据分割成若干个离散的区间。比如有一组年龄数据,可以使用
pandas.cut
将年龄数据分割成不同的年龄段并打上标签。上述过程又叫做分箱。- 参数x 指定离散化(分箱)依据的列,Seriers对象
- 参数bins 分为几组,int类型,也可以传入分组区间的列表
- 参数labels 每组的标签名称,按数值由小到大的顺序
- 参数right 默认True:左开右闭;False:左闭右开
- 参数include_lowest 默认False:不包含第一个分组的起始值;True:包含
10.2 合并和变形
-
合并数据集
-
纵向追加合并
df1.append(df2, ignore_index=True)
- 参数ignore_index默认为False, 如果为True, 则重置为自增索引
-
pd.concat函数纵向横向连接多个数据集
# 纵向连接,全部数据都保留 pd.concat([df1, df2]) # 纵向连接,只保留共有数据 pd.concat([df1, df2], join='inner') # 横向连接,全部数据都保留 pd.concat([df1,df2], axis=1) # 横向连接,保留索引值匹配的数据 pd.concat([df1,df2], join='inner', axis=1)
-
df.merge合并指定关联列的多个数据集
df1.merge(df2, on='列名', how='固定值') # 参数on='列名',表示基于那一列进行合并操作 # 参数how='固定值',表示合并后如何处理行索引,固定参数具体如下: # how='left' 对应SQL中的left join,保留左侧表df1中的所有数据 # how='right' 对应SQL中的right join,保留右侧表df2中的所有数据 # how='inner' 对应SQL中的inner,只保留左右两侧df1和df2都有的数据 # how='outer' 对应SQL中的join,保留左右两侧侧表df1和df2中的所有数据
-
df.join横向合并索引值相同的多个数据集;通过
lsuffix
和rsuffix
两个参数分别指定左表和右表相同的列名后缀,how参数的用法与merge函数的how参数用法一致df1.join( df2, lsuffix='df1的列名后缀', rsuffix='df2的列名后缀', how='outer' )
-
合并df的四个函数总结
df1.append(df2)
纵向合并数据集pd.concat([df1,df2])
横向或纵向合并数据集,df1和df2可以没有任何关系df1.merge(df2)
横向合并, df1和df2要有关联的列, 类似SQL中的表关联操作df1.join(df2)
横向合并,df1和df2要有相同的索引值才能关联
-
-
df变形
-
df.T 行变列、列变行
-
df.stack()把df变为树状花括号形式(Seriers对象);df.unstack()是df.stack()的逆操作
-
pd.melt()函数,将指定的一个或多个列名变成新df的一个列的值,原列值变成新df的另一个列的值
df.melt( id_vars=['列名'], # 不变形的所有列 value_vars=['列名'], # 要变形的所有列:把多个列变成一个新列;同时所有对应的值变成第二个新列的值 var_name='新列名', # 新列的列名 value_name='新列名' # 第二个新列的列名 )
-
df.pivot_table透视表:按照一定规则提取并展示汇总数据,方便我们转换各个维度去观察数据
# 以列名1作为索引 # 根据列名2进行分组 # 对列名3使用pandas内置的聚合函数进行计算 # 返回新的df对象 df.pivot_table( index='列名1', columns='列名2', values='列名3', aggfunc='内置聚合函数名', margins=True # 默认是False, 如果为True,就在最后一行和最后一列,按行按列分别执行aggfunc参数规定的聚合函数 ) # index:返回df的行索引,并依据其做分组;传入原始数据的列名 # columns:返回df的列索引;传入原始数据的列名,根据该列做分组 # values: 要做聚合操作的原始数据的列名 # aggfunc:内置聚合函数名字
-