引言
pandas庫擁有著豐富的方法操控數(shù)據(jù),這是他的一大優(yōu)勢狞换,但有時候污呼,因為龐大的功能裕坊,你總會碰到一些不了解功能和用法的函數(shù)。如果你的大腦保持著Excel處理數(shù)據(jù)的思維慣性燕酷,在切換到pandas解決類似問題時就會遇到困難[1]籍凝。transform
就是這樣一個函數(shù)。我已經(jīng)使用pandas有一段時間了苗缩,但是還沒有機會使用它饵蒂,所我最近花了點時間去了解下他的用法,以及他能干些什么酱讶。這篇文章通過一個例子來演示transform
如何在匯總數(shù)據(jù)時提示效率的退盯。
什么是transform?
對于transform
介紹的最好的是jake VanderPlas的書Python Data Science Handbook,就像書中提到的,transform
函數(shù)是用來配合groupby
操作的渊迁。這里假定大多數(shù)讀者都可能都經(jīng)常使用groupby
中的aggregate
,filter
或者apply
來匯總數(shù)據(jù)慰照。但是transform
跟這些相比理解起來有點小小困難,特別是對那些Excel用戶來說琉朽。這里并不是說transform
概念復雜毒租,而是需要一個思路上的轉換。jake將他的書已jupyter notebook形式發(fā)布,通過閱讀可以了解下為什么transform
'非常特別箱叁。
aggregation操作返回壓縮版本的數(shù)據(jù)墅垮,transformation可以返回經(jīng)過完整數(shù)據(jù)經(jīng)過轉換的版本。經(jīng)過轉換耕漱,輸出的數(shù)據(jù)和輸入的數(shù)據(jù)結構相同
With that basic definition, I will go through another example that can explain how this is useful in other instances outside of centering data.
problem set
在這個例子中噩斟,我們將會虛構一個銷售數(shù)據(jù):點我下載,為了節(jié)約篇幅,這里只保留12行孤个。
account | name | order | sku | quantity | unit price | ext price | |
---|---|---|---|---|---|---|---|
0 | 383080 | Will LLC | 10001 | B1-20000 | 7 | 33.69 | 235.83 |
1 | 383080 | Will LLC | 10001 | S1-27722 | 11 | 21.12 | 232.32 |
2 | 383080 | Will LLC | 10001 | B1-86481 | 3 | 35.99 | 107.97 |
3 | 412290 | Jerde-Hilpert | 10005 | S1-06532 | 48 | 55.82 | 2679.36 |
4 | 412290 | Jerde-Hilpert | 10005 | S1-82801 | 21 | 13.62 | 286.02 |
5 | 412290 | Jerde-Hilpert | 10005 | S1-06532 | 9 | 92.55 | 832.95 |
6 | 412290 | Jerde-Hilpert | 10005 | S1-47412 | 44 | 78.91 | 3472.04 |
7 | 412290 | Jerde-Hilpert | 10005 | S1-27722 | 36 | 25.42 | 915.12 |
8 | 218895 | Kulas Inc | 10006 | S1-27722 | 32 | 95.66 | 3061.12 |
9 | 218895 | Kulas Inc | 10006 | B1-33087 | 23 | 22.55 | 518.65 |
10 | 218895 | Kulas Inc | 10006 | B1-33364 | 3 | 72.30 | 216.90 |
11 | 218895 | Kulas Inc | 10006 | B1-20000 | -1 | 72.18 | -72.18 |
如果所見剃允,表中有三個訂單(10001, 10005 and 10006) ,每個訂單包含多個產(chǎn)品齐鲤。
現(xiàn)在我們想通過以上數(shù)據(jù)知道:每個產(chǎn)品占總訂單百分比
例如斥废,加入我們知道訂單10001總計金額是576.12,那么這個訂單下面每個產(chǎn)品的價值比例依次是。
- B1-20000 = $235.83 or 40.9%
- S1-27722 = $232.32 or 40.3%
- B1-86481 = $107.97 or 18.7%
通常要計算這些信息给郊,并且添加到原表中應該如何實現(xiàn)呢牡肉?先計算每個訂單的總價,然后將這些數(shù)據(jù)置回明細表淆九,得到百分比统锤。在Excel中,你可以通過分類匯總計算值炭庙。
第一種方法-合并
如果你非常熟悉pandas,你可能會先進行分組饲窿,得到一個新的DataFrame,然后進行合并焕蹄,經(jīng)過系列步驟得到最終結果逾雄,你可能通常是這樣擦做的
導入模塊,讀取數(shù)據(jù)
import pandas as pd
df = pd.read_excel("sales_transactions.xlsx")
然后腻脏,你會通過groupby根據(jù)訂單號進行分組鸦泳,然后使用sum
函數(shù)對價格進行匯總。
df.groupby('order')["ext price"].sum()
order
10001 576.12
10005 8185.49
10006 3724.49
Name: ext price, dtype: float64
下面這張圖演示了進行groupby
操作時發(fā)生了什么永品。
最關鍵的部分是鼎姐,如何將分組后的計算結果拼接到原始數(shù)據(jù)中钾麸,本能的想法是利用聚合數(shù)據(jù)創(chuàng)建一個新的
dataframe
掉弛,然后通過merge
執(zhí)行右連接拼接到原始數(shù)據(jù)。
order_total = df.groupby('order')["extprice"].sum().rename("Order_Total").reset_index()
df_1 = df.merge(order_total)
#merge的時候省略了一些細節(jié)喂走,因為有共同字段Order,所以自動對齊谋作,實際上相當于df.merge(order_total,on ='order',how = left)
df_1["Percent_of_Order"] = df_1["ext price"] / df_1["Order_Total"]
account | name | order | sku | quantity | unit price | ext price | order total | Order_Total | Percent_of_Order | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 383080 | Will LLC | 10001 | B1-20000 | 7 | 33.69 | 235.83 | 576.12 | 576.12 | 0.409342 |
1 | 383080 | Will LLC | 10001 | S1-27722 | 11 | 21.12 | 232.32 | 576.12 | 576.12 | 0.403249 |
2 | 383080 | Will LLC | 10001 | B1-86481 | 3 | 35.99 | 107.97 | 576.12 | 576.12 | 0.187409 |
3 | 412290 | Jerde-Hilpert | 10005 | S1-06532 | 48 | 55.82 | 2679.36 | 8185.49 | 8185.49 | 0.327330 |
4 | 412290 | Jerde-Hilpert | 10005 | S1-82801 | 21 | 13.62 | 286.02 | 8185.49 | 8185.49 | 0.034942 |
5 | 412290 | Jerde-Hilpert | 10005 | S1-06532 | 9 | 92.55 | 832.95 | 8185.49 | 8185.49 | 0.101759 |
6 | 412290 | Jerde-Hilpert | 10005 | S1-47412 | 44 | 78.91 | 3472.04 | 8185.49 | 8185.49 | 0.424170 |
7 | 412290 | Jerde-Hilpert | 10005 | S1-27722 | 36 | 25.42 | 915.12 | 8185.49 | 8185.49 | 0.111798 |
8 | 218895 | Kulas Inc | 10006 | S1-27722 | 32 | 95.66 | 3061.12 | 3724.49 | 3724.49 | 0.821890 |
9 | 218895 | Kulas Inc | 10006 | B1-33087 | 23 | 22.55 | 518.65 | 3724.49 | 3724.49 | 0.139254 |
10 | 218895 | Kulas Inc | 10006 | B1-33364 | 3 | 72.30 | 216.90 | 3724.49 | 3724.49 | 0.058236 |
11 | 218895 | Kulas Inc | 10006 | B1-20000 | -1 | 72.18 | -72.18 | 3724.49 | 3724.49 | -0.019380 |
這樣當然沒問題芋肠,但是要經(jīng)過很多中介步驟。
第二種方法:使用Transform
使用之前的數(shù)據(jù)遵蚜,我們看看transform
和groupby
能得到什么
df.groupby('order')["ext price"].transform('sum')
0 576.12
1 576.12
2 576.12
3 8185.49
4 8185.49
5 8185.49
6 8185.49
7 8185.49
8 3724.49
9 3724.49
10 3724.49
11 3724.49
dtype: float64
你可以看到帖池,單純的groupby
進行sum
聚合得到的數(shù)據(jù)尺寸和transform
不同。普通聚合函數(shù)返回聚合以后的結果吭净,而transform
返回的計算結果保留的原始數(shù)據(jù)的索引睡汹,這就是transform
的獨特性。
借此寂殉,我們可以不用費什么腦子囚巴,兩部結算處結果
df["Order_Total"] = df.groupby('order')["ext price"].transform('sum')
df["Percent_of_Order"] = df["ext price"] / df["Order_Total"]
account | name | order | sku | quantity | unit price | ext price | order total | Order_Total | Percent_of_Order | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 383080 | Will LLC | 10001 | B1-20000 | 7 | 33.69 | 235.83 | 576.12 | 576.12 | 0.409342 |
1 | 383080 | Will LLC | 10001 | S1-27722 | 11 | 21.12 | 232.32 | 576.12 | 576.12 | 0.403249 |
2 | 383080 | Will LLC | 10001 | B1-86481 | 3 | 35.99 | 107.97 | 576.12 | 576.12 | 0.187409 |
3 | 412290 | Jerde-Hilpert | 10005 | S1-06532 | 48 | 55.82 | 2679.36 | 8185.49 | 8185.49 | 0.327330 |
4 | 412290 | Jerde-Hilpert | 10005 | S1-82801 | 21 | 13.62 | 286.02 | 8185.49 | 8185.49 | 0.034942 |
5 | 412290 | Jerde-Hilpert | 10005 | S1-06532 | 9 | 92.55 | 832.95 | 8185.49 | 8185.49 | 0.101759 |
6 | 412290 | Jerde-Hilpert | 10005 | S1-47412 | 44 | 78.91 | 3472.04 | 8185.49 | 8185.49 | 0.424170 |
7 | 412290 | Jerde-Hilpert | 10005 | S1-27722 | 36 | 25.42 | 915.12 | 8185.49 | 8185.49 | 0.111798 |
8 | 218895 | Kulas Inc | 10006 | S1-27722 | 32 | 95.66 | 3061.12 | 3724.49 | 3724.49 | 0.821890 |
9 | 218895 | Kulas Inc | 10006 | B1-33087 | 23 | 22.55 | 518.65 | 3724.49 | 3724.49 | 0.139254 |
10 | 218895 | Kulas Inc | 10006 | B1-33364 | 3 | 72.30 | 216.90 | 3724.49 | 3724.49 | 0.058236 |
11 | 218895 | Kulas Inc | 10006 | B1-20000 | -1 | 72.18 | -72.18 | 3724.49 | 3724.49 | -0.019380 |
如果你不需要中間字段(匯總字段),可以一步得出百分比
df["Percent_of_Order"] = df["ext price"] / df.groupby('order')["ext price"].transform('sum')
下圖演示了transform
的工作邏輯,可以對照下之前groupby
通過上面的例子友扰,我相信你也認為
transform
功能非常強大彤叉。
譯者討論
以前我解決這類問題的思路是先groupby
,然后通過自己寫的lambda函數(shù)查找到結果在apply到新列中,通過第一個例子村怪,才知道m(xù)erge原來是這樣用的秽浇,缺少sql的思維真是害死人。
-
這段翻譯可能謬誤比較大 ?