我正在用python和熊猫一起工作。我在外部数据源中查询一组天内的唯一用户(例如,每30天或每2天或每7天的唯一用户)。查询需要一个期间开始、一个期间结束和一个间隔(天数)。
例如,要获取1月1日的唯一用户,参数为:
1月1日至1月3日(含3天):
有时我也需要多个句号。在所有情况下,期间可以在结束日期之后结束,但永远不会在结束日期之后开始。
例如,1月1日到1月1日的30天的唯一性:
2015-01-01
理想情况下,我应该使用pandas.period_range()
,但是因为它不接受freq
参数中的多个,所以我转向了pandas.date_range()
。我迭代了日期范围内的时间戳,如下所示:
import pandas
start_date = "2015-01-01"
end_date = "2015-01-03"
interval = 3
for timestamp in pandas.date_range(start_date , end_date , freq=str(interval)+"D"):
period_start = timesteamp.date()
period_end = period_start + datetime.timedelta(days=interval)
# query with period_start, period_end, interval
因此,当pandas生成的范围的最后一个元素在end参数之后时,它会产生不必要的循环和不想要的查询,而我希望避免这些查询。
问题是像这样的调用:
pandas.date_range("2015-01-01", "2015-01-03", freq="3D")
返回:
<class 'pandas.tseries.index.DatetimeIndex'>
[2015-01-01, 2015-01-04]
Length: 2, Freq: 3D, Timezone: None
最后一个元素2015-01-04在结束限制2015-01-03之后。当频率比实际周期(在本例中为2天或4天)短或长时,不会发生这种情况:
>>> pandas.date_range("2015-01-01", "2015-01-03", freq="2D")
<class 'pandas.tseries.index.DatetimeIndex'>
[2015-01-01, 2015-01-03]
Length: 2, Freq: 2D, Timezone: None
>>> pandas.date_range("2015-01-01", "2015-01-03", freq="4D")
<class 'pandas.tseries.index.DatetimeIndex'>
[2015-01-01]
Length: 1, Freq: 4D, Timezone: None
我试图理解close参数,但它的描述对我来说有点晦涩难懂。这三个值("right“、"left”、None)似乎都没有给出我想要的结果。
我测试了3个可能的closed=
值,以观察不同的输出:
>>> pandas.date_range("2015-01-01", "2015-01-03", freq="3D", closed="left")
<class 'pandas.tseries.index.DatetimeIndex'>
[2015-01-01]
Length: 1, Freq: 3D, Timezone: None
这似乎是预期的结果。但是在freq
比开始和结束之间的时间长的情况下,它返回一个包含0个元素的范围。
>>> pandas.date_range("2015-01-01", "2015-01-01", freq="10D", closed="left")
<class 'pandas.tseries.index.DatetimeIndex'>
Length: 0, Freq: 10D, Timezone: None
我期望:
<class 'pandas.tseries.index.DatetimeIndex'>
[2015-01-01]
Length: 1, Freq: 10D, Timezone: None
只有当freq
的乘数为0(即"0D","0H","0W")时,我才会看到结果为空。这已经引发了一个错误,所以在practice date_range()
中应该始终至少返回它的起始值。如果end参数出现在频率结束之前,则该范围将仅包含一个时间戳。
发布于 2018-04-28 23:44:05
我认为您的interval语义有点混乱,pandas在这里做了一些合理的事情。
考虑你的最后一个例子:
>>> pandas.date_range("2015-01-01", "2015-01-01", freq="10D", closed="left")
你写下你想要的东西:
<class 'pandas.tseries.index.DatetimeIndex'>
[2015-01-01]
Length: 1, Freq: 10D, Timezone: None
考虑一个日期,比如2015-01-04
。一方面,这将是此DatetimeIndex中的第一个(唯一)间隔。另一方面,此日期将在您提供的结束日期之后,这似乎与原始date_range
调用中指定的时间间隔相矛盾。
或者换句话说,从1月1日到1月2日的30天间隔是什么意思?
如果您希望间隔索引自动扩展到包含开始日期和间隔长度的结束日期,我认为您需要编写一个函数来完成此任务。
def nonempty_date_range(start, end, freq, closed=None):
""" Return a pandas.DatetimeIndex containing at least one interval. In some cases, the interval will extend beyond 'end'. """
start = pandas.to_datetime(start)
end = pandas.to_datetime(end)
length = pandas.to_timedelta(freq)
end = max(end, start + length)
return pandas.date_range(start=start, end=end, freq=freq, closed=closed)
结果:
# Example from question
>>> pandas.date_range("2015-01-01", "2015-01-01", freq="10D", closed="left")
DatetimeIndex([], dtype='datetime64[ns]', freq='10D')
上面的函数:
>>> nonempty_date_range("2015-01-01", "2015-01-01", freq="10D", closed="left")
DatetimeIndex(['2015-01-01'], dtype='datetime64[ns]', freq='10D')
发布于 2015-07-26 00:28:37
您可以设置多个date_range并使用pandas.DatetimeIndex.union将所有datetime合并
https://stackoverflow.com/questions/29170403
复制相似问题