[英]Cumulative count at a group level Python
我有一個 pandas dataframe 像這樣:
df = pd.DataFrame([
['A', 1234, 20120201],
['A', 1134, 20120201],
['A', 1011, 20120201],
['A', 1123, 20121004],
['A', 1111, 20121004],
['A', 1224, 20121105],
['B', 1156, 20120403],
['B', 2345, 20120504],
['B', 4567, 20120504],
['B', 8796, 20120606]
], columns = ['company', 'invoice', 'date'])
目的是創建一個名為“TotalPaidInvoices”的新列,該列計算每條記錄之前支付的發票數量。
我嘗試了以下
df['date'] = pd.to_datetime(df['date'])
df = df.sort_values(['company', 'date'], ascending=[True, True]).reset_index(drop=True)
df['totalpaidinvoices']= df[(df['date'] != df['date'].shift(1))].groupby(['company']).cumcount()
df['totalpaidinvoices']= df.groupby('company')['totalpaidinvoices'].fillna(method='ffill')
但我得到的不是發票數量,而是當前記錄之前的公司數量 - 日期組合。
Output:
df = pd.DataFrame(
[
['A', 1234, 20120201, 0.0],
['A', 1134, 20120201, 0.0],
['A', 1011, 20120201, 0.0],
['A', 1123, 20121004, 1.0],
['A', 1111, 20121004, 1.0],
['A', 1224, 20121105, 2.0],
['B', 1156, 20120403, 0.0],
['B', 2345, 20120504, 1.0],
['B', 4567, 20120504, 1.0],
['B', 8796, 20120606, 2.0]
], columns = ['company', 'invoice', 'date', 'totalpaidinvoices'])
預期 output:
df = pd.DataFrame(
[
['A', 1234, 20120201, 0.0],
['A', 1134, 20120201, 0.0],
['A', 1011, 20120201, 0.0],
['A', 1123, 20121004, 3.0],
['A', 1111, 20121004, 3.0],
['A', 1224, 20121105, 5.0],
['B', 1156, 20120403, 0.0],
['B', 2345, 20120504, 1.0],
['B', 4567, 20120504, 1.0],
['B', 8796, 20120606, 3.0]
], columns = ['company', 'invoice', 'date', 'totalpaidinvoices'])
有什么建議可以解決嗎?
首先,讓我們統計一下每家公司每天支付的發票數量:
tmp1 = df.groupby(['company', 'date']).size().rename('totalpaidinvoices')
然后對於每家公司,我們需要計算在當前期間之前支付了多少張發票。 這是cumsum
的工作:
tmp2 = tmp1.groupby('company').apply(lambda s: s.cumsum() - s)
最后,將計算與原始 dataframe 合並:
df.merge(tmp2, left_on=['company', 'date'], right_index=True)
如果您更喜歡方法鏈接:
result = (
df.groupby(['company', 'date'])
.size()
.groupby('company')
.apply(lambda s: s.cumsum() - s)
.to_frame('totalpaidinvoices')
.merge(df, how='right', left_index=True, right_on=['company', 'date'])
)
如果您的數據已排序,您可以嘗試:
df = df.merge(
df.groupby(["company", "date"])
.size()
.groupby(level=0)
.apply(lambda x: x.shift(1).fillna(0).cumsum())
.reset_index(),
on=["date", "company"],
).rename(columns={0: "totalpaidinvoices"})
print(df)
印刷:
company invoice date totalpaidinvoices
0 A 1234 20120201 0.0
1 A 1134 20120201 0.0
2 A 1011 20120201 0.0
3 A 1123 20121004 3.0
4 A 1111 20121004 3.0
5 A 1224 20121105 5.0
6 B 1156 20120403 0.0
7 B 2345 20120504 1.0
8 B 4567 20120504 1.0
9 B 8796 20120606 3.0
我以為我從cumcount
切換到 boolean 索引太復雜了,但是根據其他答案,這似乎實際上是最簡潔(並且可能有效)的解決方案:
for company in df.company.unique():
df.loc[df.company==company, 'total_paid_invoices'] = df.date.apply(
lambda x: df.loc[(df.date<x)&(df.company==company)].shape[0]
)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.