pandas中的groupby、transform以及pivot_table


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的效果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM