我想弄清楚如何计算两个事件之间的天数

问题描述 投票:0回答:5

我有一个事件列表。每个案例(案例 ID)最终都会经历事件(事件 A、事件 B)。我有包含各个事件的时间戳的列。我正在尝试使用 Python 根据以下内容查找事件 A 和事件 B 之间的日期。然而,有些案例不止一次经历事件 a,我需要时间流逝以最近的日期为基础。在下面的示例中,案例 ID 1 的最晚日期为 23 年 1 月 20 日,忽略了此案例 ID 之前两次出现的事件 A。

|案例编号|事件|日期| ——————————————————- |1|A|1/1/23| |1|A|1/3/23| |1|A|1/20/23| |1|B|2/1/23| |8|A|1/2/23| |100|A|23/3/1| |100|B|23/3/2| |35|A|2/13/23| |35|B|2/27/23| |6|A|2/14/23| |33|A|2/26/23| |2|A|23/3/4| |2|B|4/30/23|

我试过按重复项排序,但我使用 Python 不如使用 SQL 舒服,而且我无法使用 SQL。还试图避免手动删除重复项。 我期望的输出如下所示: |caseID|busdaysbweventAB|

python pandas days
5个回答
0
投票

您可以使用:

# Convert to datetime64 if needed
df['DATE'] = pd.to_datetime(df['DATE'])

# Pandas part: reshape your dataframe
out = df.sort_values('DATE').pivot_table(index='CaseID', columns='EVENT', values='DATE', aggfunc='last')
m = out.notna().all(axis=1)

# Numpy part: compute business day
arr = out[m].values.astype('datetime64[D]')
out.loc[m, 'bdays'] = np.busday_count(arr[:, 0], arr[:, 1])

输出:

>>> out
EVENT           A          B  bdays
CaseID                             
1      2023-01-20 2023-02-01    8.0
2      2023-03-04 2023-04-30   40.0
6      2023-02-14        NaT    NaN
8      2023-01-02        NaT    NaN
33     2023-02-26        NaT    NaN
100    2023-03-01 2023-03-02    1.0

0
投票

您的输入数据采用竖线分隔的 CSV 文件格式。它非常简单,因此不需要任何模块导入来处理它。

建立一个以 CaseID 为关键字的字典。每个关联值都应该是一个可以同时具有“A”和“B”键的字典。日期应该在与这些键关联的列表中。

您需要解析日期以找到最大值(最近的)然后做一些算术。

给定具有以下内容的输入文件 foo.csv:

|CaseID|EVENT|DATE|
|1|A|1/1/23|
|1|A|1/3/23|
|1|A|1/20/23|
|1|B|2/1/23|
|8|A|1/2/23|
|100|A|3/1/23|
|100|B|3/2/23|
|6|A|2/14/23|
|33|A|2/26/23|
|2|A|3/4/23|
|2|B|4/30/23|

...代码可能如下所示:

from datetime import datetime

def parse(d):
    return datetime.strptime(d, '%m/%d/%y')

mydict = dict()

with open('foo.csv') as data:
    next(data) # skip column headers
    for line in data:
        _, case, event, date, *_ = line.split('|')
        _date = parse(date)
        if case in mydict:
            mydict[case].setdefault(event, []).append(_date)
        else:
            mydict[case] = {event: [_date]}

for k, v in mydict.items():
    if 'A' in v and 'B' in v:
        maxa = max(v['A'])
        maxb = max(v['B'])
        print('CaseID', k, abs((maxa-maxb).days))

输出:

CaseID 1 12
CaseID 100 1
CaseID 2 57

0
投票

假设数据如所示(即 caseID 值和 DATE 已排序 - 否则您可以在进一步处理之前进行排序)然后 首先将CSV数据读入pandas DataFrame;然后使用:

#convert date strings to datetime format
df['DATE'] = pd.to_datetime(df['DATE'], dayfirst = False)
#drop duplicated A rows
df = df.drop_duplicates(subset = ['CaseID', 'EVENT'], keep = 'last')
#calculate difference of days
df['days'] = df.groupby('CaseID')['DATE'].diff().dt.days
#and finally lose the case without an A and a B event
df = df.dropna()

结果:

    CaseID EVENT       DATE  days
3        1     B 2023-02-01  12.0
6      100     B 2023-03-02   1.0
10       2     B 2023-04-30  57.0

0
投票

另一种方法是按事件和 id 分组,获取最大日期,再次按 id 分组并使用 apply 获取日期之间的差异。

from io import StringIO

import pandas as pd

table = """
CaseID,EVENT,DATE
1,A,1/1/23
1,A,1/3/23
1,A,1/20/23
1,B,2/1/23
8,A,1/2/23
100,A,3/1/23
100,B,3/2/23
6,A,2/14/23
33,A,2/26/23
2,A,3/4/23
2,B,4/30/23
"""

df = pd.read_csv(StringIO(table), sep=',')
df['DATE'] = pd.to_datetime(df['DATE'])
d = df.groupby(['CaseID', 'EVENT']).max().reset_index().groupby('CaseID').aggregate({'DATE': lambda x: x.diff().to_numpy()[-1]})

输出:

          DATE
CaseID        
1      12 days
2      57 days
6          NaT
8          NaT
33         NaT
100     1 days

0
投票
案例编号 活动 日期
1 A 1/1/23
1 A 1/3/23
1 A 1/20/23
1 2/1/23
8 A 1/2/23
100 A 3/1/23
100 3/2/23
35 A 2/13/23
35 2/27/23
6 A 2/14/23
33 A 2/26/23
2 A 3/4/23
2 4/30/23

import pandas as pd


def get_time_lapsed(df, case_id, event, date):
    df = df.sort_values(by=[case_id, date])
    df["time_lapsed"] = df.groupby(case_id)[date].diff()
    return df
def test_get_time_lapsed():
    df = pd.DataFrame(
        {
            "CaseID": [1, 1, 1, 1, 8, 100, 100, 35, 35, 6, 33, 2, 2],
            "EVENT": ["A", "A", "A", "B", "A", "A", "B", "A", "B", "A", "A", "A", "B"],
            "DATE": [
                "1/1/23",
                "1/3/23",
                "1/20/23",
                "2/1/23",
                "1/2/23",
                "3/1/23",
                "3/2/23",
                "2/13/23",
                "2/27/23",
                "2/14/23",
                "2/26/23",
                "3/4/23",
                "4/30/23",
            ],
        }
    )
    df["DATE"] = pd.to_datetime(df["DATE"])
    df = get_time_lapsed(df, "CaseID", "EVENT", "DATE")
    print(df)

    CaseID EVENT       DATE time_lapsed
0        1     A 2023-01-01         NaT
1        1     A 2023-01-03      2 days
2        1     A 2023-01-20     17 days
3        1     B 2023-02-01     12 days
11       2     A 2023-03-04         NaT
12       2     B 2023-04-30     57 days
9        6     A 2023-02-14         NaT
4        8     A 2023-01-02         NaT
10      33     A 2023-02-26         NaT
7       35     A 2023-02-13         NaT
8       35     B 2023-02-27     14 days
5      100     A 2023-03-01         NaT
6      100     B 2023-03-02      1 days

© www.soinside.com 2019 - 2024. All rights reserved.