我有一個資料框,記錄了我的每個樂高套裝盒中包含的不同樂高積木。對于每個套裝盒,總是有許多不同的常規件,但有時盒中還包含一些額外的備用件。所以資料框有一個布爾列來區分該條件。
現在我想總結資料集,所以每個樂高套裝(groupby set_id)只得到一行,其中有一個新列,用于顯示該套裝框中的總件數(“數量”的總和)。
我的問題是,我還需要兩個額外的列,用于根據 True/False 列計算其中有多少是“常規”的,有多少是“備用”的。
有沒有辦法通過創建一個額外的資料框和一個 .agg() 呼叫來計算這三個總和列?
而不是創建 3 個資料框和合并列,這是我目前的方法:
import pandas as pd
import random
random.seed(1)
# creating sample data:
nrows=15
df = pd.DataFrame([], columns=["set_id","part_id","quantity","is_spare"])
df["set_id"]=["ABC"[random.randint(0,2)] for r in range(0,nrows)]
df["part_id"] = [random.randint(1000,8000) for n in range(0,nrows)]
df["quantity"] = [random.randint(1,10) for n in range(0,nrows)]
df["is_spare"]=[random.random()>0.75 for r in range(0,nrows)]
print(df)
# grouping into a new dfsummary dataframe: HOW TO DO IT IN JUST ONE STEP ?
# aggregate sum of ALL pieces:
dfsummary = df.groupby("set_id", as_index=False) \
.agg(num_pieces=("quantity","sum"))
# aggregate sum of "normal" pieces:
dfsummary2 = df.loc[df["is_spare"]==False].groupby("set_id", as_index=False) \
.agg(normal_pieces=("quantity","sum"))
# aggregate sum of "spare" pieces:
dfsummary3 = df.loc[df["is_spare"]==True].groupby("set_id", as_index=False) \
.agg(spare_pieces=("quantity","sum"))
# Putting all aggregate columns together:
dfsummary = dfsummary \
.merge(dfsummary2,on="set_id",how="left") \
.merge(dfsummary3,on="set_id",how="left")
print(dfsummary)
原始資料:
set_id part_id quantity is_spare
0 A 4545 1 False
1 C 5976 1 False
2 A 7244 9 False
3 B 7284 1 False
4 A 1017 7 False
5 B 6700 4 True
6 B 4648 7 False
7 B 3181 1 False
8 C 6910 9 False
9 B 7568 4 True
10 A 2874 8 True
11 A 5842 8 False
12 B 1837 9 False
13 A 3600 4 False
14 B 1250 6 False
匯總資料:
set_id num_pieces normal_pieces spare_pieces
0 A 37 29 8.0
1 B 32 24 8.0
2 C 10 10 NaN
我看到了這個Stackoverflow 問題,但我的情況有所不同,因為 sum() 函式僅適用于目標列的某些行,具體取決于其他列的 True/False 值。
uj5u.com熱心網友回復:
您可以在一行中完成。訣竅是創建一個臨時列,其中數量為負數spare_pieces和正數normal_pieces:
out = df.assign(qty=df['is_spare'].replace({True: -1, False: 1}) * df['quantity']) \
.groupby('set_id')['qty'] \
.agg(num_pieces=lambda x: sum(abs(x)),
normal_pieces=lambda x: sum(x[x > 0]),
sparse_pieces=lambda x: abs(sum(x[x < 0]))) \
.reset_index()
輸出:
>>> out
set_id num_pieces normal_pieces sparse_pieces
0 A 37 29 8
1 B 32 24 8
2 C 10 10 0
>>> df['is_spare'].replace({True: -1, False: 1}) * df['quantity'])
0 1 # normal_pieces
1 1
2 9
3 1
4 7
5 -4 # spare_pieces
6 7
7 1
8 9
9 -4
10 -8
11 8
12 9
13 4
14 6
dtype: int64
uj5u.com熱心網友回復:
一種選擇是執行 groupby 和 unstack:
(df
.groupby(['set_id', 'is_spare'])
.quantity
.sum()
.unstack('is_spare')
.rename(columns={False:'normal_pieces', True:'spare_pieces'})
.assign(num_pieces = lambda df: df.sum(axis = 'columns'))
.rename_axis(columns=None)
.reset_index()
)
set_id normal_pieces spare_pieces num_pieces
0 A 29.0 8.0 37.0
1 B 24.0 8.0 32.0
2 C 10.0 NaN 10.0
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/402323.html
標籤:
