我有两列,' 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'))))
答案 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