簡體   English   中英

Groupby Pandas ,根據日期差異計算多列

[英]Groupby Pandas , calculate multiple columns based on date difference

我有一個如下所示的熊貓數據框:

CID RefID   Date        Group   MID 
100     1   1/01/2021       A                       
100     2   3/01/2021       A                       
100     3   4/01/2021       A   101             
100     4   15/01/2021      A                           
100     5   18/01/2021      A                   
200     6   3/03/2021       B                       
200     7   4/04/2021       B                       
200     8   9/04/2021       B   102             
200     9   25/04/2021      B                       
300     10  26/04/2021      C                       
300     11  27/05/2021      C           
300     12  28/05/2021      C   103 

我想創建三列:

天數差異:

  1. 這必須以這樣的方式創建,如果第一個日期和相應行的差異大於 30 屬於同一 CID,則將“NAT”或 0 分配給下一行(重置),然后減去日期此行用於以下值

  2. 如果 MIDis 不為 null 且屬於同一 CID 組,則將“NAT”或 0 分配給下一行(重置),然后用該行減去以下值的日期

否則,只需獲取屬於相應行的相同 CID 的第一行的日期差異 b/w

答:這取決於 days_diff 列,該列就像一個計數器,只有在同一 CID 發生另一個 NAT 時才會更改/遞增,並為每個 CID 重置自身。

B:此列取決於 A 列,如果 A 中的值保持不變,則不會更改,否則會增加

解釋起來有點復雜,請參閱下面的輸出以供參考。 我已經使用.groupby() .diff().shift()方法來創建多個虛擬列,以便計算並仍在處理它,請讓我知道最好的方法來解決這個問題,謝謝

我的預期輸出:

CID RefID   Date        Group   MID     days_diff       A   B
100     1   1/01/2021       A           NAT             1   1
100     2   3/01/2021       A           2 days          1   1
100     3   4/01/2021       A   101     3 days          1   1
100     4   15/01/2021      A           NAT             2   4
100     5   18/01/2021      A           3 days          2   4
200     6   3/03/2021       B           NAT             1   6
200     7   4/04/2021       B           NAT             2   7
200     8   9/04/2021       B   102     5 days          2   7
200     9   25/04/2021      B           NAT             3   9
300     10  26/04/2021      C           NAT             1   10
300     11  27/05/2021      C           NAT             2   11
300     12  28/05/2021      C   103     1 day           2   11

你可以這樣做:

def days_diff(sdf):
    result = pd.DataFrame(
        {"days_diff": pd.NaT, "A": None}, index=sdf.index
    )
    start = sdf.at[sdf.index[0], "Date"]
    for index, day, next_MID_is_na in zip(
        sdf.index[1:], sdf.Date[1:], sdf.MID.shift(1).isna()[1:]
    ):
        diff = (day - start).days
        if diff <= 30 and next_MID_is_na:
            result.at[index, "days_diff"] = diff
        else:
            start = day
    result.A = result.days_diff.isna().cumsum()
    return result

df[["days_diff", "A"]] = df[["CID", "Date", "MID"]].groupby("CID").apply(days_diff)
df["B"] = df.RefID.where(df.A != df.A.shift(1)).ffill()

df創建的結果

from io import StringIO
data = StringIO(
'''
CID RefID   Date        Group   MID 
100     1   1/01/2021       A                       
100     2   3/01/2021       A                       
100     3   4/01/2021       A   101             
100     4   15/01/2021      A                           
100     5   18/01/2021      A                   
200     6   3/03/2021       B                       
200     7   4/04/2021       B                       
200     8   9/04/2021       B   102             
200     9   25/04/2021      B                       
300     10  26/04/2021      C                       
300     11  27/05/2021      C           
300     12  28/05/2021      C   103
''')
df = pd.read_csv(data, delim_whitespace=True)
df.Date = pd.to_datetime(df.Date, format="%d/%m/%Y")

    CID  RefID       Date Group    MID days_diff  A     B
0   100      1 2021-01-01     A    NaN       NaT  1   1.0
1   100      2 2021-01-03     A    NaN         2  1   1.0
2   100      3 2021-01-04     A  101.0         3  1   1.0
3   100      4 2021-01-15     A    NaN       NaT  2   4.0
4   100      5 2021-01-18     A    NaN         3  2   4.0
5   200      6 2021-03-03     B    NaN       NaT  1   6.0
6   200      7 2021-04-04     B    NaN       NaT  2   7.0
7   200      8 2021-04-09     B  102.0         5  2   7.0
8   200      9 2021-04-25     B    NaN       NaT  3   9.0
9   300     10 2021-04-26     C    NaN       NaT  1  10.0
10  300     11 2021-05-27     C    NaN       NaT  2  11.0
11  300     12 2021-05-28     C  103.0         1  2  11.0

幾個解釋:

  • 函數days_diff生成一個包含days_diffA兩列的數據days_diff 它被施加到通過柱分組CID的子dataframes df
  • 第一步:初始化結果數據days_diff result (列days_diff填充NaT ,列A填充None ),並將天差的起始值start設置為組中的第一天。
  • 之后基本上循環遍歷第一個索引之后的子數據幀,從而獲取索引、列Date的值和布爾值next_MID_is_na表示下一行中MID列的值是否為NaN (通過.shift(1).isna() )。
  • 在循環的每一步中:
    1. 計算當天與開始日的差值。
    2. 檢查days_diff列的規則:
      • 如果當前和開始日期的差異 <= 30 天,並且下一個MID -row -> day-difference 為NaN
      • 否則 -> 將start重置為當天。
  • 完成列Adays_diff計算后:當days_diffNaNdays_diff result.days_diff.isna()True ( == 1 ), days_diffFalse ( == 0 )。 因此,累積總和 ( .cumsum() ) 給出了所需的結果。
  • groupby-apply生成列days_diffA最后的列B的計算之后:選擇RefID值,其中值A更改(通過.where(df.A != df.A.shift(1)) ),然后向前填充剩余的NaN

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM