好的,所以這是一個很難描述的問題。
我正在為一項研究整理一份合規性報告,其中團隊需要知道每個用戶是否在 8 天中的 7 天中至少每月執行一次特定任務。
所以我需要一種方法:
- 對于給定的用戶和給定的月份,在該月份中搜索 8 天,其中 8 天中至少有 7 天被標記為“真”
- 回傳 1 表示滿足要求,0 表示不滿足要求。
下面是一個資料結構的例子:
import pandas as pd
ids = 1
req_met = ['TRUE', 'TRUE', 'FALSE', 'FALSE', 'TRUE', 'TRUE', 'TRUE', 'FALSE', 'TRUE', 'TRUE', 'TRUE', 'TRUE', 'FALSE', 'FALSE', 'FALSE', 'FALSE', 'TRUE', 'TRUE', 'TRUE', 'FALSE']
date = ['2018-01-01', '2018-01-03', '2018-01-04', '2018-01-05', '2018-01-06', '2018-01-07', '2018-01-08', '2018-01-09', '2018-01-10', '2018-01-11',
'2018-01-12', '2018-01-13', '2018-01-14', '2018-01-15', '2018-01-16', '2018-01-17', '2018-01-18', '2018-01-19', '2018-01-21', '2018-01-23']
df = pd.DataFrame({'id':ids,
'Date':date,
'req_met':req_met})
print(df)
id Date req_met
0 1 2018-01-01 TRUE
1 1 2018-01-03 TRUE
2 1 2018-01-04 FALSE
3 1 2018-01-05 FALSE
4 1 2018-01-06 TRUE
5 1 2018-01-07 TRUE
6 1 2018-01-08 TRUE
7 1 2018-01-09 FALSE
8 1 2018-01-10 TRUE
9 1 2018-01-11 TRUE
10 1 2018-01-12 TRUE
11 1 2018-01-13 TRUE
12 1 2018-01-14 FALSE
13 1 2018-01-15 FALSE
14 1 2018-01-16 FALSE
15 1 2018-01-17 FALSE
16 1 2018-01-18 TRUE
17 1 2018-01-19 TRUE
18 1 2018-01-21 TRUE
19 1 2018-01-23 FALSE
對于此用戶,回傳的答案將是“1”,因為他們確實有 8 天的時間段,其中 7 天是“真”(2018-01-06 到 2018-01-13)。您可以看到日期范圍并不總是連續的,這增加了復雜性。
我想要的輸出將是最有效的函式,它可以獲取這些資料并回傳“1”(滿足要求)或“0”(不滿足要求)
在此先感謝您的幫助。
uj5u.com熱心網友回復:
首先將型別轉換為booland datetime:
df['req_met'] = df['req_met'].replace({'TRUE':True, 'FALSE':False})
df['Date'] = pd.to_datetime(df.Date)
如果缺少日期并且我們假設用戶當天沒有記錄任何活動,我們需要插入缺少的日期:
df = (df.set_index('Date')
.groupby('id').req_met
.resample('D').sum()
.reset_index()
)
df['Month'] = df.Date.dt.strftime("%Y-%m")
請注意,resample每個id用戶使用它來確保每個用戶的連續日歷天數。然后使用rolling方法:
df_result = (df.groupby(['id','Month'])
.rolling(8)['req_met'].sum().ge(7)
.groupby(['id','Month'])
.agg({('req_met','max')})
.reset_index()
)
結果是:
id Month req_met
0 1 2018-01 True
請注意groupby使用了兩次。您可以通過逐步運行代碼來檢查計算以完全理解邏輯。
uj5u.com熱心網友回復:
編輯:我的錯,我誤讀了您對我的問題的回答,并認為您確認 8 天的視窗需要是連續的。由于情況并非如此,@ipj 的回答非常有效。
我會把這個留給未來想要類似但連續視窗的讀者。
舊答案,當我錯誤地認為對于任何給定的 8 天視窗時,日期需要是連續的
首先,我將連接幾個具有不同id值的副本:
df1 = pd.DataFrame({'id':ids, 'Date': date, 'req_met': req_met})
df2 = df1.copy()
df2.id = 2
df3 = df1.copy()
df3.id = 3
df = pd.concat([df1, df2, df3]).reset_index(drop=True)
df.Date = pd.to_datetime(df.Date)
現在,為不是連續日期的行創建一個掩碼(從此答案修改):
>>> mask = (df.Date.diff(-1).dt.days == -1) | (df.Date.diff().dt.days == 1)
現在你可以做一個滾動總和:
>>> (df[mask].groupby("id").req_met.rolling(8).sum() >= 7).groupby("id").sum()
id
1 1
2 1
3 1
Name: req_met, dtype: int64
這三個1只是因為我只是將原始資料幀復制了三次,但這應該適用于您擁有的任何實際資料幀。如果您的資料尚未按日期分組,則您需要將其添加到groupby.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/313696.html
上一篇:給定一個帶有UTC時間戳列和時區列的Pandas資料幀,生成一個本地時間戳列
下一篇:將時間從日期時間行轉換為列
