文章目录
- groupby()方法
- 通过列名进行分组
- 通过Series对象进行分组
- Series对象与原数据的行索引长度相等
- Series对象与原数据的行索引长度不等
- 通过字典进行分组
- 按照columns轴的方向进行分组
- 按照index轴的方向进行分组
- 通过函数进行分组
groupby()方法
groupby(
self,
by=None,
axis=0,
level=None,
as_index: bool = True,
sort: bool = True,
group_keys: bool = True,
squeeze: bool = False,
observed: bool = False,
)
部分参数表示的含义如下:
- by:用于确定进行分组的依据
- axis:表示分组轴的方向,可以为0或1,默认为0
- level:如果某个轴是一个MultiIndex对象(索引层次结构),则会按特定级别或多个级别分组
- as_index:表示聚合后的数据是否以组标签作为索引的DataFrame对象输出,接受布尔值,默认为True
- sort:表示是否对分组标签进行排序,接受布尔值,默认为True
通过groupby()方法执行分组操作,会返回一个GroupBy对象,该对象实际上并没有进行任何计算,只是包含一些而关于分组键的中间数据而已。
一般,使用Series调用groupby()方法返回的是SeriesGroupBy对象,而使用DataFrame调用groupby()方法返回的是DataFrameBy对象。
在进行分组时,通过指定by参数来确定分组标准,常用的分组方式主要有四种:
- 列表或数组,其长度必须与待分组的轴一样
- DataFrame对象中某列的名称
- 字典或Series对象,给出待分组轴上的值与分组名称之间的对应关系
- 函数,用于处理轴索引或索引中的各个标签
通过列名进行分组
代码:
import numpy as np
import pandas as pddf = pd.DataFrame({"key": ['C', 'B', 'C', 'A', 'B', 'B', 'A', 'C', 'A'],"Data": [2, 4, 6, 8, 10, 1, 14, 16, 18]})
print(df)
group_obj = df.groupby(by='key')
print("df.groupby(by='key'):\n", group_obj)
输出结果:
key Data
0 C 2
1 B 4
2 C 6
3 A 8
4 B 10
5 B 1
6 A 14
7 C 16
8 A 18
df.groupby(by='key'):<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000002018919F2B0>
从输出结果可以看出,DataFrame经过分组之后得到了一个DataFrameGroupBy对象,该对象是一个可迭代的对象,即只有在真正需要的时候才会执行计算(惰性计算)
如果要查看每个分组的具体内容,应该使用for循环遍历DataFrameGroupBy对象。
代码:
for i in group_obj:print(i)
输出结果:
('A', key Data
3 A 8
6 A 14
8 A 18)
('B', key Data
1 B 4
4 B 10
5 B 1)
('C', key Data
0 C 2
2 C 6
7 C 16)
通过Series对象进行分组
Series对象与原数据的行索引长度相等
将Series对象传给by参数,作为分组键拆分DataFrame对象
代码:
df1 = pd.DataFrame({'key1': ['A', 'A', 'B', 'B', 'A'],'kye2': ['one', 'two', 'one', 'two', 'one'],'data1': [2, 3, 4, 6, 8],'data2': [3, 5, 6, 3, 7]})
print(df1)se = pd.Series(['a', 'b', 'c', 'a', 'b'])
group_obj1 = df1.groupby(by=se)
for i in group_obj1:print(i)
输出结果:
key1 kye2 data1 data2
0 A one 2 3
1 A two 3 5
2 B one 4 6
3 B two 6 3
4 A one 8 7('a', key1 kye2 data1 data2
0 A one 2 3
3 B two 6 3)
('b', key1 kye2 data1 data2
1 A two 3 5
4 A one 8 7)
('c', key1 kye2 data1 data2
2 B one 4 6)
从输出结果可以看出,se将df1对象分成a,b,c三组,其中索引0和3对应的两行为a组数据,索引1和4对应的两行为b组数据,索引2对应的一行为c组数据。
Series对象与原数据的行索引长度不等
代码:
se1 = pd.Series(['a', 'b', 'a'])
group_obj2 = df1.groupby(se1)
for i in group_obj2:print("group_obj2:\n", i)
输出结果:
('a', key1 kye2 data1 data2
0 A one 2 3
2 B one 4 6)
('b', key1 kye2 data1 data2
1 A two 3 5)
由于se1只有三行数据,所以它只需要对df对象的前三行数据进行分组,即第一行第三行分为一组,最后一行分为一组,而不会将全部的数据进行分组
通过字典进行分组
用字典对DataFrame进行分组时,需要确定轴的方向及字典中的映射关系,即字典中的键为列名,字典的值为自定义的分组名。
按照columns轴的方向进行分组
代码:
df2 = DataFrame({'a': [1, 2, 4, 8, 3],'b': [9, 6, 3, 7, 5],'c': [2, 3, 4, 6, 8],'d': [3, 5, 6, 3, 7]})
mapping = {'a': '第一组', 'b': '第二组', 'c': '第三组', 'd': '第一组'}
print(df2)
by_columns = df2.groupby(by=mapping, axis=1)
print("by_columns:")
for i in by_columns:print(i)
输出结果:
a b c d
0 1 9 2 3
1 2 6 3 5
2 4 3 4 6
3 8 7 6 3
4 3 5 8 7
by_columns:
('第一组', a d
0 1 3
1 2 5
2 4 6
3 8 3
4 3 7)
('第三组', c
0 2
1 3
2 4
3 6
4 8)
('第二组', b
0 9
1 6
2 3
3 7
4 5)
拆分df2时,将a列、d列数据映射到第一组;将b列映射到第二组,将d列数据映射到第三组。
按照index轴的方向进行分组
代码
mapping1 = {0: '第一组', 1: '第二组', 2: '第三组', 3: '第二组', 4: '第一组'}
by_index = df2.groupby(mapping1, axis=0)
print("by_index:")
for i in by_index:print(i)
输出结果:
by_index:
('第一组', a b c d
0 1 9 2 3
4 3 5 8 7)
('第三组', a b c d
2 4 3 4 6)
('第二组', a b c d
1 2 6 3 5
3 8 7 6 3)
拆分df2时,将0行、4行数据映射到第一组;将1行、3行映射到第二组,将2行数据映射到第三组。
通过函数进行分组
使用函数作为分组键会更加灵活,任何一个被当作分组键的函数都会在各个索引值上被调用一次,返回的值会被用作分组名称。
代码:
df2 = DataFrame({'a': [1, 2, 4, 8, 3],'b': [9, 6, 3, 7, 5],'c': [2, 3, 4, 6, 8],'d': [3, 5, 6, 3, 7]},index=['Bob', 'Alice', 'Job', 'Jack', 'Helen'])
group_obj3 = df2.groupby(by=len)
print("group_obj3")
for i in group_obj3:print(i)
输出结果:
group_obj3
(3, a b c d
Bob 1 9 2 3
Job 4 3 4 6)
(4, a b c d
Jack 8 7 6 3)
(5, a b c d
Alice 2 6 3 5
Helen 3 5 8 7)
在调用groupby()方法时传入了内置函数len(),表明len()函数会对行索引一列执行求长度的操作,以行索引名称的长度进行分组,则长度相同的行索引名称会分成一组。