groupby
import pandas as pd
df = pd.DataFrame({
"a": ['a', 'b', 'a', 'a', 'b'],
"b": [1, 2, 3, 2, 1],
"c": [3, 1, 5, 1, 7],
"d": ["我", "是", "一", "条", "狗"]
})
# groupby可以同时by多个字段,组合成一个列表
# 如果只by一个字段,那么除了列表之外、也可以只写一个字符串,即by="a"
print(df.groupby(by=["a"])) # <pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001A7B31F8700>
# 此时得到的是一个DataFrameGroupBy对象,我们可以对这个对象执行聚合操作
# 比如sum、count、mean等等
print(df.groupby(by="a").sum())
"""
b c
a
a 6 9
b 3 8
"""
print(df.groupby(by="a").count())
"""
b c d
a
a 3 3 3
b 2 2 2
"""
# 我们对于sum这种来讲,显然是需要数值类型的,因此pandas会自动选择数值类型的列进行聚合
# 但是对count这种就没有要求了,会选择所有的列
# 但是我们发现,在聚合的时候,参数by指定的列会变成索引,那么如何让它们不变成索引呢
print(df.groupby(by="a", as_index=False).sum())
"""
a b c
0 a 6 9
1 b 3 8
"""
# 通过参数as_index=False即可,让by指定的列不作为索引
# 另外聚合的时候,我们也可以这么做
print(df.groupby(by="a", as_index=False).agg("sum"))
"""
a b c
0 a 6 9
1 b 3 8
"""
# df.groupby(by="a", as_index=False).agg("sum") 和 df.groupby(by="a", as_index=False).sum()是等价的
# 同理:df.groupby().agg("count")、df.groupby().agg("mean")等等也是一样的
# 只要df.groupby().xxx()可以调用的,都可以通过df.groupby().agg("xxx")调用
# 另外最重要的一点是,agg里面还可以指定函数,比如:sum、np.sum
print(df.groupby(by="a", as_index=False).agg(sum))
"""
a b c
0 a 6 9
1 b 3 8
"""
# 当然我们自定义的函数也是可以的
print(df.groupby(by="a", as_index=False).agg(lambda x: sum(x)))
"""
a b c
0 a 6 9
1 b 3 8
"""
print(df.groupby(by="a", as_index=False).agg(lambda x: str(sum(x)) + "略略略"))
"""
a b c
0 a 6略略略 9略略略
1 b 3略略略 8略略略
"""
# 但是我们看到,pandas默认是对所有的列进行的聚合,可不可以指定某些列呢?
# 答案是可以的,直接在groupby后面通过列表来指定即可,可以指定['b', 'c'],也可以指定[['b', 'c']]
print(df.groupby(by="a")["b", "c"].agg(lambda x: sum(x)))
"""
b c
a
a 6 9
b 3 8
"""
# 但是只选择一个列进行聚合,那么要写成[['b']],否则得到的是一个Series对象
# 因为如果多个列,那么肯定是DataFrame,但是一个列,我们还想要DataFrame的话,那么就要写成[['b']]的形式
print(df.groupby(by="a")[["b"]].agg(lambda x: sum(x)))
"""
b
a
a 6
b 3
"""
# 除此之外我们还可以在agg里面指定要聚合的列
print(df.groupby(by="a").agg({"b": "sum", "d": ' '.join}))
"""
b d
a
a 6 我 一 条
b 3 是 狗
"""
# 你以为就这么完了,我们还可以对某列同时执行多个操作
print(df.groupby(by="a").agg({"b": ["sum", lambda x: str(sum(x)) + "yoyoyo~"],
"c": "mean",
"d": [' '.join, lambda x: [_ + "旺旺 " for _ in x]]
}
)
)
"""
b c d
sum <lambda_0> mean join <lambda_0>
a
a 6 6yoyoyo~ 3 我 一 条 [我旺旺 , 一旺旺 , 条旺旺 ]
b 3 3yoyoyo~ 4 是 狗 [是旺旺 , 狗旺旺 ]
"""
# 我们看到有二级表头,b对应的有sum和<lambda_0>,命名是pandas内部的决策,如果是我们使用def定义的函数,那么就是函数名
# 匿名函数,所以就叫lambda
# c对应的有mean,d对应的有join和lambda
# 最后再演示一下如何把二级表头变成一级表头,具体原理可以去网上搜索
group = df.groupby(by="a").agg({"b": ["sum", lambda x: str(sum(x)) + "yoyoyo~"],
"c": "mean",
"d": [' '.join, lambda x: [_ + "旺旺 " for _ in x]]
}
)
columns1 = group.columns.get_level_values(0)
columns2 = group.columns.get_level_values(1)
group.columns = columns1 + "_" + columns2
print(group)
"""
b_sum b_<lambda_0> c_mean d_join d_<lambda_0>
a
a 6 6yoyoyo~ 3 我 一 条 [我旺旺 , 一旺旺 , 条旺旺 ]
b 3 3yoyoyo~ 4 是 狗 [是旺旺 , 狗旺旺 ]
"""
transform
import pandas as pd
df = pd.DataFrame({
"x": ['a', 'b', 'a', 'a', 'b'],
"y": [1, 2, 3, 2, 1],
"z": [3, 1, 5, 1, 7],
})
# transform依旧依赖于groupby
print(df.groupby(by=["x"], as_index=False).agg("sum"))
"""
x y z
0 a 6 9
1 b 3 8
"""
print(df.groupby(by=["x"], as_index=False).transform("sum"))
"""
y z
0 6 9
1 3 8
2 6 9
3 6 9
4 3 8
"""
# 我们看到如果是groupby后面直接通过agg进行聚合的话,那么行的数量会变少,因为聚合了嘛。而且by指定的列就不会有重复了
# 但如果是通过transform的话,那么行是不会减少的,原来是多少行结果还是多少行,并且自动把by指定的列给去掉了。
# 可以这么理解,我们用普通的聚合作为比喻:
"""
如果是agg("sum")的话,by="x"这一列只有a和b,说明原来的"x"这个列只有a和b两种数据。可能数量很多,但种类只有a和b两种
聚合之后,a对应y中的6,对应z中的9
那么transform("sum")就相当于把原来x列中所有元素为a的,对应的y中的元素全部换成6,对应的z中的元素全部换成9
聚合之后,b对应y中的3,对应z中的8
那么transform("sum")就相当于把原来x列中所有元素为b的,对应的y中的元素全部换成3,对应的z中的元素全部换成8
可能逻辑有点不好说,那么再来举个例子
x y
a 2
b 1
a 3
agg("sum"):
x y
a 5
b 1
transform("sum")
y
5
1
5
因为聚合之后,a对应5,b对应1
那么就把原来a对应的y中的元素全部换成5,b对应的y中元素全部换成1
"""
# 如果想要指定某些列该怎么办呢?显然和刚才介绍的一样
print(df.groupby(by=["x"], as_index=False)[["y"]].transform("sum"))
"""
y
0 6
1 3
2 6
3 6
4 3
"""
# 并且如果我们使用transform之后还需要by后面指定的列、这里是"x",那么直接手动添加即可,因为顺序是不变的,假设transform之后的结果赋值给变量trans,那么直接通过trans["x"] = df["x"]就行了。
# 到此结束了,可以看到transform的操作就没有agg那么丰富了
pivot_table
import pandas as pd
df = pd.DataFrame({
"x": ['a', 'b', 'a', 'a', 'b'],
"y": [1, 2, 3, 2, 1],
"z": [3, 1, 5, 1, 7],
})
# 通过pivot_table,这个方法是pd下面的
# 指定df、index(相当于groupby中的参数by)、values(要聚合的列)、aggfunc(聚合函数)得到结果和groupby是一样的
# 如果不想作为索引,需要再手动调用reset_index()
print(pd.pivot_table(df, index=["x"], values=["y", "z"], aggfunc="sum"))
"""
y z
x
a 6 9
b 3 8
"""
# aggfunc里面也可以指定多个操作
print(pd.pivot_table(df, index="x", values=["y"], aggfunc=["sum", "count"]))
"""
sum count
y y
x
a 6 3
b 3 2
"""
# 不指定values,那么则是对所有的列进行聚合
print(pd.pivot_table(df, index=["x"], aggfunc="sum"))
"""
y z
x
a 6 9
b 3 8
"""
# 也可以对不同的列使用不同的聚合函数
print(pd.pivot_table(df, index=["x"], aggfunc={"y": ["count", "sum"], "z": "sum"}))
"""
y z
count sum sum
x
a 3 6 9
b 2 3 8
"""
# 我们看到可以通过pivot_table实现groupby的agg操作
# 但是pivot_table支持的操作并不止这些,里面还有其它参数,比如:columns,这是一个很重要的参数
# 具体怎么使用可以网上搜索,我们这里只用它实现groupby的效果
如果觉得文章对您有所帮助,可以请囊中羞涩的作者喝杯柠檬水,万分感谢,愿每一个来到这里的人都生活愉快,幸福美满。