首页 > 解决方案 > 根据给定日期提取时间间隔的开始和结束

问题描述

对于df带有日期的列(都是过去的),我需要用给定日期周围的开始日期和结束日期替换两列。对于每一df行,有两列包含当前(相对于今天2021-4-9)的开始日期和结束日期,可以是以下两个确切的六个月间隔中的任何一个:

2020-11-15  2021-5-15
2021-2-15   2021-8-15

示例:如果过去的某一天是1995-06-01,则具有间隔的列将需要包含1995-05-15 1995-11-151995-02-15 1995-08-15取决于当前间隔中的月份。

有:

df = pd.DataFrame({'date': ['2016-6-10', '1995-6-1', '2013-10-12'],
                   'current_start_date': ['2020-11-15', '2020-11-15', '2021-2-15'],
                   'current_end_date': ['2021-5-15', '2021-5-15', '2021-8-15']})

df[['date', 'current_start_date', 'current_end_date']] = df[['date', 'current_start_date', 'current_end_date']].apply(pd.to_datetime)

需要:

df = pd.DataFrame({'date': ['2016-6-10', '1995-6-1', '2013-10-12'],
                   'original_start_date': ['2016-5-15', '1995-5-15', '2013-8-15'],
                    'original_end_date': ['2016-11-15', '1995-11-15', '2014-2-15']})

df[['date', 'original_start_date', 'original_end_date']] = df[['date', 'original_start_date', 'original_end_date']].apply(pd.to_datetime)

标签: python-3.xpandas

解决方案


这可以用np.sort()和向量化为 3 行np.where()

  1. sort开始/结束日期对(重置为同一年以仅考虑月/日)
  2. where发生date在开始日期之前,交换开始/结束日期并减少开始年份
  3. where发生date在结束日期之后,交换开始/结束日期并增加结束年份
date = lambda Y, m: pd.to_datetime(Y.astype(str) + m.astype(str).str.zfill(2) + '15')
    
#1 sort start/end date pairs (axis=0)
df[['current_start_date', 'current_end_date']] = pd.DataFrame(np.sort([
    date(df.date.dt.year, df.current_start_date.dt.month),
    date(df.date.dt.year, df.current_end_date.dt.month),
], axis=0).T)

#2 where date occurs before start date, swap and decrement start year
df['original_start_date'], df['original_end_date'] = np.where(df.date < df.current_start_date,
    [df.current_end_date - pd.DateOffset(years=1), df.current_start_date],
    [df.current_start_date, df.current_end_date])

#3 where date occurs after end date, swap and increment end year
df['original_start_date'], df['original_end_date'] = np.where(df.date > df.current_end_date,
    [df.current_end_date, df.current_start_date + pd.DateOffset(years=1)],
    [df.original_start_date, df.original_end_date])

df = df.drop(columns=['current_start_date', 'current_end_date'])

#         date  original_start_date  original_end_date
# 0 2016-06-10           2016-05-15         2016-11-15
# 1 1995-06-01           1995-05-15         1995-11-15
# 2 2013-10-12           2013-08-15         2014-02-15
# 3 1998-12-01           1998-11-15         1999-05-15
# 4 1998-01-01           1997-11-15         1998-05-15
# 5 1998-05-14           1997-11-15         1998-05-15
# 6 1998-05-16           1998-05-15         1998-11-15
# 7 1990-11-15           1990-05-15         1990-11-15

这比df.apply()

df.apply() 与 np.where()


推荐阅读