Pandas 数据框中基于 id 列的多个日期之间的差异

difference between multiple dates based on id column in a Pandas dataframe

我的实际案例如下,在一家商店中,我想知道第一次访问和第二次访问之间、第二次访问和第三次访问之间的访问时间(以天为单位)...

我有一个包含 2 列的 python 数据集(每个客户的访问 ID 和访问日期)

data = {'Id': ['A', 'B','A','B','A','A'],
'Date': ['01/03/2022', '03/03/2022', '05/03/2022', '07/03/2022', '09/03/2022','11/03/2022']
}

我的问题:对于已经来过4次的客户,第一次到第二次到访的间隔天数是多少?第 2 次和第 3 次访问之间的相同问题...

您可以先将它们转换为 pd.Timestamp 对象,然后按

对 ID 和日期进行排序
df['Date'] = pd.to_datetime(df['Date'], dayfirst=True)
df = df.sort_values(['Id', 'Date'])

然后,您可以简单地计算时间戳的差异,乘以是否为同一用户的布尔掩码:

df['Date Since Last Visit'] = (df['Date'] - df['Date'].shift(1)) * (df['Id'] == df['Id'].shift())
df['Date Since Last Visit'] = df['Date Since Last Visit'].fillna(pd.Timedelta(0))

这会给你 timedelta 对象,你可以看到它已经过了多少天。

您的输出将是:


    Id  Date        Date Since Last Visit
0   A   2022-03-01  0 days
2   A   2022-03-05  4 days
4   A   2022-03-09  4 days
5   A   2022-03-11  2 days
1   B   2022-03-03  0 days
3   B   2022-03-07  4 days

或者只过滤掉以下之后的首次访问:

df['Date Since Last Visit'] = df['Date'] - df['Date'].shift(1)
df = df[df['Id'] == df['Id'].shift()]

这给你:

    Id  Date        Date Since Last Visit
2   A   2022-03-05  4 days
4   A   2022-03-09  4 days
5   A   2022-03-11  2 days
3   B   2022-03-07  4 days

您期望的输出不清楚,但让我们计算一个 2D table,其中客户作为索引,访问作为列:

# convert to datetime (assuming DD/MM/YYYY)
df['Date'] = pd.to_datetime(df['Date'], dayfirst=True)

# setting up group
g = df.groupby('Id')['Date']

df2 = (df
 .sort_values(by='Id')      # ensure the dates are ordered
 .assign(visit=g.cumcount().add(1),      # visit number
         nb_visits=g.transform('count'), # total number of visits
         diff=g.diff()                   # difference between successive visits
         )
 .query('nb_visits >= 4')   # filter to keep customers with at least 4 visits
 .pivot(index='Id', columns='visit', values='diff')  # reshape to 2D
)

输出:

这给出了每位客户自上次访问以来的天数(如果访问次数超过 3 次)

visit   1      2      3      4
Id                            
A     NaT 4 days 4 days 2 days

注意。您可以在此处删除第一列,因为它始终未定义 (NaT)