【问题标题】:Count the number of days from consecutive timeperiods (Python, datetime)计算连续时间段的天数(Python,日期时间)
【发布时间】:2021-02-04 14:13:38
【问题描述】:

我想计算连续期间的天数。

在下面的df中我有四列:

  • 标识;代表一个人。
  • 期间;一个数字,其中最低的是第一个周期,最高的是最新的。
  • in_date;期间开始的日期。
  • out_date;期限结束的日期。

我想构建一个执行以下操作的通用函数:

  • 计算连续周期的天数。如果两个时期之间的天数小于 90,则认为它们是连续的。

  • 如果 id 的最后一个时期的 out_date 为 2013 年,我只想计算天数。如果最后一个时期的“out_date”为 2014 年或 2012 年,我想忽略该 ID。

  • 我想在结果变量中包含周期之间的天数。

我的问题是,因为我对 Python 还很陌生,所以我无法想出一个好主意如何计算周期之间的天数并对连续周期进行分类。任何帮助将不胜感激。

import pandas as pd
import numpy as np
import datetime

data = {'id':[1, 1, 1, 2, 2, 2, 2, 3, 3, 3],
        'period':[1, 2, 3, 1, 3, 5, 6, 2, 3, 4],
       'in_date': ['2011-02-15','2011-11-10','2012-10-13',
                   '2010-04-03','2012-02-17','2012-08-15','2014-01-04','2010-06-01','2012-03-29','2012-09-12'],
       'out_date': ['2011-05-21','2012-10-11','2013-10-25',
                    '2012-02-16','2012-02-19','2013-11-23','2014-12-18','2011-08-21','2012-09-11','2013-01-10']}
df = pd.DataFrame(data)

df['in_date'] = pd.to_datetime(df['in_date'])
df['out_date'] = pd.to_datetime(df['out_date'])
df['n_days'] = df['out_date'] - df['in_date']

预期输出:

【问题讨论】:

  • 我发布了一个答案,但我会注意到,当我为它编写代码时,我的第一个 id 没有得到 745,所以我要么误解了,要么上面的值不正确。
  • @Rick M - 这是我的错误。非常感谢您的努力!看起来不错!今天我将在我的真实世界数据集上尝试您的解决方案。

标签: python pandas datetime


【解决方案1】:

首先,将n_days转换为数值,并确保df排序:

df['n_days'] = (df['out_date'] - df['in_date']).dt.days
df = df.sort_values(['id','period'])

添加一列计算期间之间的天数:

df['days_since_last'] = (df['in_date'] - df['out_date'].shift(1)).dt.days

...并确保这些值不会在不同的 id 值之间交叉:

id_changed = (df['id'].shift(1) != df['id'])
df.loc[id_changed, 'days_since_last'] = np.nan

定义一个条件,指出间隔天数太高:

days_cut = (df['days_since_last'] >= 90)

获取数据框的一个子集,它可以是新的id 或有效的连续天数。为这些有效运行中的每一个分配一个唯一值“运行”(稍后用于分组):

tmp = df[days_cut | id_changed ].copy()
tmp['run'] = range(len(tmp))

将其合并回主数据框并向前填充run,以便显示连续周期的有效运行位置:

df = pd.merge(df, tmp[['id','period','run']], on=['id','period'], how='left')
df['run'] = df['run'].fillna(method='ffill')

这就是当时的样子。您可以看到,对于每个 id,都有连续运行的 run 值:

print(df)
   id  period    in_date   out_date  n_days  days_since_last  run
0   1       1 2011-02-15 2011-05-21      95              NaN  0.0
1   1       2 2011-11-10 2012-10-11     336            173.0  1.0
2   1       3 2012-10-13 2013-10-25     377              2.0  1.0
3   2       1 2010-04-03 2012-02-16     684              NaN  2.0
4   2       3 2012-02-17 2012-02-19       2              1.0  2.0
5   2       5 2012-08-15 2013-11-23     465            178.0  3.0
6   2       6 2014-01-04 2014-12-18     348             42.0  3.0
7   3       2 2010-06-01 2011-08-21     446              NaN  4.0
8   3       3 2012-03-29 2012-09-11     166            221.0  5.0
9   3       4 2012-09-12 2013-01-10     120              1.0  5.0

通过汇总n_days 列来提取每个run 的连续天数。 .agg 还跟踪运行中的最大日期,因此我们只能保留在 2013 年结束的运行:

consecutive_days = df.groupby(['id','run']).agg( {'n_days' : np.sum, 'out_date' : np.max } )
consecutive_days = consecutive_days[(consecutive_days['out_date'].dt.year == 2013)]

consecutive_days = consecutive_days.drop(columns=['out_date']).rename(columns={'n_days' : 'consecutive_days'})

最后,将其合并回原始数据框并删除多余的列:

df = pd.merge(df, consecutive_days, on='id', how='left')
df = df.drop(columns=['days_since_last','run'])

print(df)
   id  period    in_date   out_date  n_days  consecutive_days
0   1       1 2011-02-15 2011-05-21      95             713.0
1   1       2 2011-11-10 2012-10-11     336             713.0
2   1       3 2012-10-13 2013-10-25     377             713.0
3   2       1 2010-04-03 2012-02-16     684               NaN
4   2       3 2012-02-17 2012-02-19       2               NaN
5   2       5 2012-08-15 2013-11-23     465               NaN
6   2       6 2014-01-04 2014-12-18     348               NaN
7   3       2 2010-06-01 2011-08-21     446             286.0
8   3       3 2012-03-29 2012-09-11     166             286.0
9   3       4 2012-09-12 2013-01-10     120             286.0

【讨论】:

  • 一个简化可能是在开始时过滤掉 out_date=2013 的那些。 df['last_value'] =df.groupby('id')['in_date'].transform('last') 然后 df = df[df['last_value]=2013]
猜你喜欢
  • 1970-01-01
  • 2016-12-31
  • 1970-01-01
  • 1970-01-01
  • 2022-11-25
  • 2020-05-02
  • 2014-02-18
  • 1970-01-01
  • 2014-09-24
相关资源
最近更新 更多