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 是 狗 [是旺旺 , 狗旺旺 ]
"""
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的效果