【问题标题】:Python: Calculate how many days are overlap between 2 dates by id in a dataframePython:通过数据框中的 id 计算 2 个日期之间重叠的天数
【发布时间】:2021-10-13 22:45:26
【问题描述】:

我需要知道根据每个 student_id 在不同日期范围内重叠了多少天。

到目前为止我的解决方案是:

# example data frame

start_dates = pd.date_range('2021-02-24', periods=4, freq='D')
end_dates = pd.date_range('2021-02-24', periods=4, freq='M')

data = {'id':['123456', '123456', '789101', '903456'],
        'starts_on':start_dates,
       'ends_on':end_dates}
 
df = pd.DataFrame(data)

Output:
    id  starts_on   ends_on
0   123456  2021-02-24  2021-02-28
1   123456  2021-02-25  2021-03-31
2   789101  2021-02-26  2021-04-30
3   903456  2021-02-27  2021-05-31

如您所见,第一行和第二行具有相同的 id 并且日期是重叠的(第二个日期比另一个日期晚一天开始并更晚结束,因此它有 4 天的重叠)。我需要一种方法来为更大的数据框执行此过程。

到目前为止,我最好的解决方案是一种计算两天之间重叠天数的方法,但我不知道如何在我的数据帧行上迭代它,因为考虑到 id 必须相同,然后比较日期查看每个 id 的重叠天数:

Range = namedtuple('Range', ['start', 'end'])

r1 = Range(start=datetime(2021, 2, 24), end=datetime(2021, 2, 28))
r2 = Range(start=datetime(2021, 2, 25), end=datetime(2021, 3, 31))
latest_start = max(r1.start, r2.start)
earliest_end = min(r1.end, r2.end)
delta = (earliest_end - latest_start).days + 1
overlap = max(0, delta)
overlap

Output:
4

【问题讨论】:

  • 你可以使用 groupby df.groupby('id').apply(lambda x: (x['ends_on']- x['starts_on'].shift(-1)).dt.days+1).max()
  • 嗨@Nagakiran,非常感谢您的帮助!还有一个问题,如何在我的数据框中使用这个 groupby 的结果创建一个新列?
  • 您可以简单地转换数据,并将结果分配给新列,我只是添加到答案

标签: python pandas dataframe date


【解决方案1】:

您可以尝试按 ID 分组并使用 shift 来获取最近的开始并用 end 减去,

df.groupby('id').apply(lambda x: (x['ends_on']- x['starts_on'].shift(-1)).dt.days+1).max()

#编辑 1

res = df.groupby('id').apply(lambda x: (x['ends_on']- x['starts_on'].shift(-1)).dt.days.add(1).max())
df.set_index('id').assign(newcol=res)

出来:

id  starts_on   ends_on overlap newcol
0   123456  2021-02-24  2021-02-28  NaN 4.0
1   123456  2021-02-25  2021-03-31  NaN 4.0
2   789101  2021-02-26  2021-04-30  NaN NaN
3   903456  2021-02-27  2021-05-31  NaN NaN

【讨论】:

    【解决方案2】:

    如果您只有每个 id 有 2 个日期范围的情况,那么您可以使用简单的 groupby 来完成工作。

    首先,通过修改设置代码确保日期是数据框中的实际日期类型:

    start_dates = pd.date_range('2021-02-24', periods=4, freq='D').date
    end_dates = pd.date_range('2021-02-24', periods=4, freq='M').date
    

    然后您可以按 id 分组并获取最长开始日期和最短结束日期,以找出 id 的最小可能重叠。

    # we need a function to handle the special case when there's only 1 row per id
    def overlap(df):
      if df.shape[0] == 1:
        return 0
      else:
        return (df.ends_on.min() - df.starts_on.max()).days + 1
    
    
    (
      df
      .groupby(["id"])
      .apply(overlap)
    )
    

    结果是:

    id
    123456    4
    789101    0
    903456    0
    dtype: int64
    

    【讨论】:

      猜你喜欢
      • 2019-03-26
      • 1970-01-01
      • 2014-09-19
      • 2012-07-24
      • 2014-08-07
      • 1970-01-01
      • 2012-12-07
      • 1970-01-01
      相关资源
      最近更新 更多