首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何使用pandas.date_range()生成一个在end参数后面没有时间戳的范围?

如何使用pandas.date_range()生成一个在end参数后面没有时间戳的范围?
EN

Stack Overflow用户
提问于 2015-03-20 23:38:53
回答 2查看 19K关注 0票数 4

我正在用python和熊猫一起工作。我在外部数据源中查询一组天内的唯一用户(例如,每30天或每2天或每7天的唯一用户)。查询需要一个期间开始、一个期间结束和一个间隔(天数)。

例如,要获取1月1日的唯一用户,参数为:

  • start: 2015-01-01
  • end: 2015-01-01
  • interval: 1

1月1日至1月3日(含3天):

  • start: 2015-01-01
  • end: 2015-01-03
  • interval: 3

有时我也需要多个句号。在所有情况下,期间可以在结束日期之后结束,但永远不会在结束日期之后开始。

例如,1月1日到1月1日的30天的唯一性:

2015-01-01

  • end: 2015-01-01

  • interval:

  • start: 30

理想情况下,我应该使用pandas.period_range(),但是因为它不接受freq参数中的多个,所以我转向了pandas.date_range()。我迭代了日期范围内的时间戳,如下所示:

代码语言:javascript
复制
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参数之后时,它会产生不必要的循环和不想要的查询,而我希望避免这些查询。

问题是像这样的调用:

代码语言:javascript
复制
pandas.date_range("2015-01-01", "2015-01-03", freq="3D")

返回:

代码语言:javascript
复制
<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天)短或长时,不会发生这种情况:

代码语言:javascript
复制
>>> 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=值,以观察不同的输出:

代码语言:javascript
复制
>>> 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个元素的范围。

代码语言:javascript
复制
>>> pandas.date_range("2015-01-01", "2015-01-01", freq="10D", closed="left")
<class 'pandas.tseries.index.DatetimeIndex'>
Length: 0, Freq: 10D, Timezone: None

我期望:

代码语言:javascript
复制
<class 'pandas.tseries.index.DatetimeIndex'>
[2015-01-01]
Length: 1, Freq: 10D, Timezone: None

只有当freq的乘数为0(即"0D","0H","0W")时,我才会看到结果为空。这已经引发了一个错误,所以在practice date_range()中应该始终至少返回它的起始值。如果end参数出现在频率结束之前,则该范围将仅包含一个时间戳。

EN

回答 2

Stack Overflow用户

发布于 2018-04-28 23:44:05

我认为您的interval语义有点混乱,pandas在这里做了一些合理的事情。

考虑你的最后一个例子:

代码语言:javascript
复制
>>> pandas.date_range("2015-01-01", "2015-01-01", freq="10D", closed="left")

你写下你想要的东西:

代码语言:javascript
复制
<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天间隔是什么意思?

如果您希望间隔索引自动扩展到包含开始日期和间隔长度的结束日期,我认为您需要编写一个函数来完成此任务。

代码语言:javascript
复制
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)

结果:

代码语言:javascript
复制
# Example from question
>>> pandas.date_range("2015-01-01", "2015-01-01", freq="10D", closed="left")
DatetimeIndex([], dtype='datetime64[ns]', freq='10D')

上面的函数:

代码语言:javascript
复制
>>> nonempty_date_range("2015-01-01", "2015-01-01", freq="10D", closed="left")
DatetimeIndex(['2015-01-01'], dtype='datetime64[ns]', freq='10D')
票数 1
EN

Stack Overflow用户

发布于 2015-07-26 00:28:37

您可以设置多个date_range并使用pandas.DatetimeIndex.union将所有datetime合并

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29170403

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档