提问人:Chris Linke 提问时间:5/16/2023 最后编辑:MattDMoChris Linke 更新时间:5/16/2023 访问量:56
Python 代码来比较匹配 ID 中的日期?
Python code to compare dates within matching IDs?
问:
我的表中有以下数据:
编号 | 订单日期 | 出院日期 |
---|---|---|
001 | 1/2/2023 | 1/2/2023 |
001 | 2/27/2023 | |
002 | 2/14/2023 | 2/15/2023 |
002 | 3/29/2023 | 4/1/2023 |
002 | 7/2/2023 | |
003 | 4/1/2023 | |
003 | 5/15/2023 |
我想添加一个列,该列为任何“出院日期”返回“是”,其中“订单日期”为 30 天,它可以是匹配 ID 的任何订单日期。它应该看起来像这样:
编号 | 订单日期 | 出院日期 | 30天回顾 |
---|---|---|---|
001 | 1/2/2023 | 1/2/2023 | 是的 |
001 | 2/27/2023 | 不 | |
002 | 2/14/2023 | 2/15/2023 | 是的 |
002 | 3/29/2023 | 4/1/2023 | 是的 |
002 | 4/18/2023 | 是的 | |
003 | 4/1/2023 | 不 | |
003 | 5/15/2023 | 不 |
我试过:
df['30 day review'] = 'No'
for match_id in df['ID'].unique():
rows = df[df['ID'] == match_id]
if any(rows['Order Date'] <= rows rows['Discharge Date'] + pd.DateOffset(days=30)):
df.loc[df['ID'] == match_id, '30 day review'] = 'Yes'
但这给了我一个“是”,对于给定匹配 ID 作为一个组的每一行,而不是将该行出货日期与该 ID 组中的所有可用订单日期进行比较。例如,在我上面的表格中,它将返回 ID 001 中的所有 Yes,而不是在第 1 行中返回 Yes,在第 2 行中返回 No
答:
1赞
mozway
5/16/2023
#1
用:ffill
df['30 Day Review'] = (
pd.to_datetime(df['Order Date'], dayfirst=False)
.groupby(df['ID']).ffill()
.rsub(pd.to_datetime(df['Discharge Date'], dayfirst=False))
.le('30D')
)
铌。仅当值已排序且“出院
日期”始终晚于组中前一行的“订单日期
”时,此解决方案才有效。有关独立于行顺序的可靠解决方案,请参阅带有 merge_asof
的第二种方法。
输出:
ID Order Date Discharge Date 30 Day Review
0 1 1/2/2023 1/2/2023 True
1 1 NaN 2/27/2023 False
2 2 2/14/2023 2/15/2023 True
3 2 3/29/2023 4/1/2023 True
4 2 NaN 7/2/2023 False
5 3 NaN 4/1/2023 False
6 3 NaN 5/15/2023 False
为/:Yes
No
df['30 Day Review'] = np.where(
pd.to_datetime(df['Order Date'], dayfirst=False)
.groupby(df['ID']).ffill()
.rsub(pd.to_datetime(df['Discharge Date'], dayfirst=False))
.le('30D'),
'Yes', 'No'
)
输出:
ID Order Date Discharge Date 30 Day Review
0 1 1/2/2023 1/2/2023 Yes
1 1 NaN 2/27/2023 No
2 2 2/14/2023 2/15/2023 Yes
3 2 3/29/2023 4/1/2023 Yes
4 2 NaN 7/2/2023 No
5 3 NaN 4/1/2023 No
6 3 NaN 5/15/2023 No
使用merge_asof
:
m = pd.merge_asof(
df[['ID']].assign(discharge=pd.to_datetime(df['Discharge Date'], dayfirst=False))
.reset_index().sort_values(by='discharge'),
df[['ID']].assign(order=pd.to_datetime(df['Order Date'], dayfirst=False))
.sort_values(by='order').dropna(subset='order'),
by='ID', left_on='discharge', right_on='order',
tolerance=pd.Timedelta('30D')
).set_index('index')['order'].notna().reindex(df.index)
df['30 Day Review'] = np.where(m, 'Yes', 'No')
输出:
ID Order Date Discharge Date 30 Day Review
0 1 1/2/2023 1/2/2023 Yes
1 1 NaN 2/27/2023 No
2 2 2/14/2023 2/15/2023 Yes
3 2 3/29/2023 4/1/2023 Yes
4 2 NaN 4/18/2023 Yes
5 3 NaN 4/1/2023 No
6 3 NaN 5/15/2023 No
评论
0赞
Chris Linke
5/16/2023
我尝试了 merge_asof() 方法,但得到了一个 TypeError:Index(...) 必须使用某种集合调用,“order”被传递了
0赞
Chris Linke
5/16/2023
我能够通过在dropna(subset=['order'])周围添加右括号[]来使merge_asof代码工作。不是 100% 为什么需要这样做,但很高兴让它发挥作用。
0赞
mozway
5/16/2023
@ChrisLinke是的,这是一个 pandas 版本问题,旧版本需要括号,而不是最新版本;)
0赞
Rawson
5/16/2023
#2
您可以使用 ,它允许您根据条件返回一个值或另一个值:numpy.where()
import pandas as pd
import numpy as np
l1 = ["001", "001", "002", "002", "002", "003", "003"]
l2 = ["1/2/2023", None, "2/14/2023", "3/29/2023", None, None, None]
l3 = ["1/2/2023", "2/27/2023", "2/15/2023", "4/1/2023", "7/2/2023", "4/1/2023", "5/15/2023"]
df = pd.DataFrame({"ID": l1, "Order Date": l2, "Discharge Date": l3})
df["Order Date"] = pd.to_datetime(df["Order Date"])
df["Discharge Date"] = pd.to_datetime(df["Discharge Date"])
# group by ID and forward fill all order dates, then fill any that are still "none" as 1/1/1900
# then if the difference between these and the discharge date (in days) is greater than 30
# return "No", else "Yes"
df["30-day review"] = np.where(
(df["Discharge Date"] - df.groupby("ID")["Order Date"].ffill().fillna(
pd.Timestamp(1900,1,1))).dt.days > 30,
"No", # if greater than 30 days difference
"Yes") # if less than or equal to 30 days difference
df
Out[]:
# ID Order Date Discharge Date 30-day review
#0 001 2023-01-02 2023-01-02 Yes
#1 001 NaT 2023-02-27 No
#2 002 2023-02-14 2023-02-15 Yes
#3 002 2023-03-29 2023-04-01 Yes
#4 002 NaT 2023-07-02 No
#5 003 NaT 2023-04-01 No
#6 003 NaT 2023-05-15 No
评论
0赞
Rawson
5/16/2023
@mozway的另一个答案几乎完全相同,但计算的语法略有不同。
0赞
mozway
5/16/2023
我实际上认为这种方法并不可靠,我添加了一个更好的替代方案,它应该始终有效。
评论