[英]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
我想创建三列:
天数差异:
这必须以这样的方式创建,如果第一个日期和相应行的差异大于 30 属于同一 CID,则将“NAT”或 0 分配给下一行(重置),然后减去日期此行用于以下值
如果 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_diff
和A
两列的数据days_diff
。 它被施加到通过柱分组CID
的子dataframes df
。days_diff
result
(列days_diff
填充NaT
,列A
填充None
),并将天差的起始值start
设置为组中的第一天。Date
的值和布尔值next_MID_is_na
表示下一行中MID
列的值是否为NaN
(通过.shift(1).isna()
)。days_diff
列的规则:
MID
-row -> day-difference 为NaN
。start
重置为当天。A
列days_diff
计算后:当days_diff
为NaN
时days_diff
result.days_diff.isna()
为True
( == 1
), days_diff
为False
( == 0
)。 因此,累积总和 ( .cumsum()
) 给出了所需的结果。groupby-apply
生成列days_diff
和A
最后的列B
的计算之后:选择RefID
值,其中值A
更改(通过.where(df.A != df.A.shift(1))
),然后向前填充剩余的NaN
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.