【问题标题】:How to check if date ranges are overlapping in a pandas dataframe according to a categorical column?如何根据分类列检查熊猫数据框中的日期范围是否重叠?
【发布时间】:2021-11-22 16:52:06
【问题描述】:

让我们以这个示例数据框为例:

df = pd.DataFrame({'ID':[1,1,2,2,3],'Date_min':["2021-01-01","2021-01-20","2021-01-28","2021-01-01","2021-01-02"],'Date_max':["2021-01-23","2021-12-01","2021-09-01","2021-01-15","2021-01-09"]})
df["Date_min"] = df["Date_min"].astype('datetime64')
df["Date_max"] = df["Date_max"].astype('datetime64')

   ID   Date_min   Date_max
0   1 2021-01-01 2021-01-23
1   1 2021-01-20 2021-12-01
2   2 2021-01-28 2021-09-01
3   2 2021-01-01 2021-01-15
4   3 2021-01-02 2021-01-09

我想检查每个ID 是否有重叠的日期范围。我可以使用如下的循环解决方案,但它效率不高,因此对于真正的大数据帧来说相当慢:

L_output = []
for index, row in df.iterrows() :
    if len(df[(df["ID"]==row["ID"]) & (df["Date_min"]<= row["Date_min"]) & 
              (df["Date_max"]>= row["Date_min"])].index)>1:
        print("overlapping date ranges for ID %d" %row["ID"])
        L_output.append(row["ID"])

Output :

overlapping date ranges for ID 1

您是否知道一种更好的方法来检查 ID 1 是否有重叠的日期范围?

预期输出:

[1]

【问题讨论】:

    标签: python pandas dataframe date


    【解决方案1】:

    试试:

    1. 创建一个“日期”列,其中包含每行从“Date_min”到“Date_max”的日期列表
    2. explode“日期”列
    3. 获取重复的行
    df["Dates"] = df.apply(lambda row: pd.date_range(row["Date_min"], row["Date_max"]), axis=1)
    df = df.explode("Dates").drop(["Date_min", "Date_max"], axis=1)
    
    #if you want all the ID and Dates that are duplicated/overlap
    >>> df[df.duplicated()]
       ID      Dates
    1   1 2021-01-20
    1   1 2021-01-21
    1   1 2021-01-22
    1   1 2021-01-23
    
    #if you just want a count of overlapping dates per ID
    >>> df.groupby("ID").agg(lambda x: x.duplicated().sum())
        Dates
    ID       
    1       4
    2       0
    3       0
    

    【讨论】:

      【解决方案2】:

      您可以将日期时间对象转换为时间戳。然后,构造 pd.Interval 对象并在每个 ID 的所有可能间隔组合的生成器上迭代:

      from itertools import combinations
      import pandas as pd
      
      def group_has_overlap(group):
          timestamps = group[["Date_min", "Date_max"]].values.tolist()
          for t1, t2 in combinations(timestamps, 2):
              i1 = pd.Interval(t1[0], t1[1])
              i2 = pd.Interval(t2[0], t2[1])
              if i1.overlaps(i2):
                  return True
          return False
      
      for ID, group in df.groupby("ID"):
          print(ID, group_has_overlap(group))   
      
      

      输出是:

      1 True
      2 False
      3 False
      

      【讨论】:

        【解决方案3】:

        将索引设置为间隔索引,并使用 groupby 获取重叠 ID:

        (df.set_index(pd.IntervalIndex
                        .from_arrays(df.Date_min, 
                                     df.Date_max, 
                                     closed='both'))
           .groupby('ID')
           .apply(lambda df: df.index.is_overlapping)
        ) 
        ID
        1     True
        2    False
        3    False
        dtype: bool
        

        【讨论】:

          猜你喜欢
          • 2019-07-07
          • 2018-09-04
          • 1970-01-01
          • 2022-01-23
          • 1970-01-01
          • 2021-02-25
          • 1970-01-01
          • 2021-09-22
          • 2016-05-08
          相关资源
          最近更新 更多