给定开始日期和结束日期,最有效的方式是在两者之间生成所有周?

时间:2018-01-06 20:54:27

标签: python pandas pyspark

我有两列,' start_date'和' end_date',这可能是一个广泛的日期,从一天(日期之间没有差异)到相隔18个月。我正在使用的API仅需要7天之间的日期,因此,我希望每7天将用户提供的日期范围解析为唯一行(并且不超过提供的结束日期)。

我用udf成功实现了这一点,但我很好奇是否有一种更有效的方式我没有想到。这是我开始使用的数据框:

foo   start_date   end_date
foo1  2017-08-01   2017-09-01

我把它变成了这个:

foo   start_date   end_date
foo1  2017-08-01   2017-08-07
foo1  2017-08-08   2017-08-14
foo1  2017-08-15   2017-08-21
foo1  2017-08-22   2017-08-28
foo1  2017-08-29   2017-09-01

这是我的代码。它可以工作,并且对于我的数据来说很好,因为我一次只能分成大约40行......但是这个解决方案感觉异常混乱。我很好奇是否有更有效的方法。

def list_of_weeks(start,end):
  if start == end:
    return start
  else:
    start, end = datetime.strptime(start, '%Y-%m-%d'), datetime.strptime(end, '%Y-%m-%d')
    dates = [start]
    curr_date = start
    end = end - timedelta(7)
    while curr_date <= end:
      curr_date += timedelta(7)
      dates.append(curr_date)
    dates = ','.join([x.strftime('%Y-%m-%d') for x in dates])
    return dates

end = df.select('end_date').collect()[0][0]
end = datetime.strptime(end, '%Y-%m-%d')

list_of_weeks_udf = udf(list_of_weeks)
df = (df.withColumn('start_date', split(list_of_weeks_udf('start_date','end_date'), ','))
            .withColumn('start_date', explode('start_date'))
            .withColumn('start_date', to_date('start_date'))
            .withColumn('end_date', date_add('start_date', 6))
            .withColumn('end_date', when(col('end_date')>end, end.strftime('%Y-%m-%d')).otherwise(col('end_date'))))

3 个答案:

答案 0 :(得分:1)

这不能回答整个问题,这是一个在给定开始和结束日期的情况下生成列的简单方法。

import pandas as pd
start = pd.date_range(start="2017-8-01", end="2017-9-1", freq="7D")
end = start + pd.Timedelta(weeks=1)

答案 1 :(得分:0)

这是使用pandas' date_range

import pandas

start, end = '2017-08-01', '2017-09-01'
d1 = pandas.date_range(start=start, end=end, freq='7D')
d2 = d1.shift(6, freq='d')
# fix end date (make sure latest end_date it doesn't go over end_date)
d2 = list(d2)[:-1] + [min(d2[-1], pandas.Timestamp(end))]

df = pandas.DataFrame(data=dict(foo=['foo1']*len(d1), start_date=d1, end_date=d2), 
    columns=('foo', 'start_date', 'end_date'))

print(df.to_string(index=False))

打印:

foo start_date   end_date
foo1 2017-08-01 2017-08-07
foo1 2017-08-08 2017-08-14
foo1 2017-08-15 2017-08-21
foo1 2017-08-22 2017-08-28
foo1 2017-08-29 2017-09-01

顺便说一句,由于index=False,理由似乎略有偏差,请参阅this open pandas bug

答案 2 :(得分:0)

v=(df.end_date-df.start_date).dt.days[0]//7
s2=s1[1:].shift(-1,freq='D').append(pd.Index(df.end_date))
s1=pd.date_range(start=df.start_date[0],periods=v+1,freq='7D')  
pd.DataFrame({'foo':df.foo.repeat(v+1),'start_date':s1,'end_date':s2})
Out[241]: 
    end_date   foo start_date
0 2017-08-07  foo1 2017-08-01
0 2017-08-14  foo1 2017-08-08
0 2017-08-21  foo1 2017-08-15
0 2017-08-28  foo1 2017-08-22
0 2017-09-01  foo1 2017-08-29