Pandas date_range - 减去numpy timedelta给出奇怪的结果,时间变得不是0:00:00

时间:2018-04-06 20:58:31

标签: python pandas numpy datetime timedelta

我正在尝试使用pandas date_range功能生成一组日期。然后我想迭代这个范围并从每个日期减去几个月(确切的月数在循环中确定)以获得新的日期。

当我这样做时,我得到了一些非常奇怪的结果。

MVP:

#get date range
dates = pd.date_range(start = '1/1/2013', end='1/1/2018', freq=str(test_size)+'MS', closed='left', normalize=True)
#take first date as example
date = dates[0]
date
Timestamp('2013-01-01 00:00:00', freq='3MS')

到目前为止一切顺利。

现在让我们说我想从这个日期回来一个月。我定义numpy timedelta(它支持定义的月份,而pandas的timedelta不支持):

#get timedelta of 1 month
deltaGap = np.timedelta64(1,'M')
#subtract one month from date
date - deltaGap
Timestamp('2012-12-01 13:30:54', freq='3MS')

为什么这样?为什么我得到13:30:54的时间组件而不是午夜。

此外,如果我减去超过1个月,那么转变变得如此之大,以至于我失去了一整天:

#let's say I want to subtract both 2 years and then 1 month
deltaTrain = np.timedelta64(2,'Y')
#subtract 2 years and then subtract 1 month 
date - deltaTrain - deltaGap
Timestamp('2010-12-02 01:52:30', freq='3MS')

2 个答案:

答案 0 :(得分:3)

我在使用timedelta时遇到了类似的问题,我最终使用的解决方案是使用relativedelta中的dateutil,这是专门为此类应用程序构建的考虑到所有的日历怪异,如闰年,工作日等...)。例如:

from dateutil.relativedelta import relativedelta

date = dates[0]

>>> date
Timestamp('2013-01-01 00:00:00', freq='10MS')

deltaGap = relativedelta(months=1)

>>> date-deltaGap
Timestamp('2012-12-01 00:00:00', freq='10MS')

deltaGap = relativedelta(years=2, months=1)

>>> date-deltaGap
Timestamp('2010-12-01 00:00:00', freq='10MS')

有关relativedelta

的更多信息,请查看documentation

numpy.timedelta64

的问题

我认为docs的这两部分显示np.timedelta的问题:

  

有两个Timedelta单位('Y',年和'M',几个月)被特别处理,因为它们代表的时间根据使用时间而变化。虽然timedelta日单位相当于24小时,但无法将月份单位转换为天数,因为不同月份的天数不同。

  

跨度的长度是64位整数乘以日期或单位长度的范围。例如,'W'(周)的时间跨度恰好是'D'(日)的时间跨度的7倍,'D'(日)的时间跨度恰好是时间跨度的24倍'h'(小时)。

因此,timedeltas适用于数小时,数周,数月,数天,因为这些是不可变的时间跨度。但是,月份和年份的长度是可变的(想想闰年),因此要考虑到这一点,numpy需要某种“平均”(我猜)。一个numpy“年”似乎是一年,5小时,49分钟和12秒,而一个numpy“月”似乎是30天,10小时,29分钟和6秒。

# Adding one numpy month adds 30 days + 10:29:06:
deltaGap = np.timedelta64(1,'M')
date+deltaGap
# Timestamp('2013-01-31 10:29:06', freq='10MS')

# Adding one numpy year adds 1 year + 05:49:12:
deltaGap = np.timedelta64(1,'Y')
date+deltaGap
# Timestamp('2014-01-01 05:49:12', freq='10MS')

这不是那么容易使用,这就是为什么我会去relativedelta,这对我来说更直观(

)。

答案 1 :(得分:1)

您可以尝试使用pd.DateOffset,主要用于在日期格式上应用偏移逻辑(月,年,小时)。

# get random dates
dates = pd.date_range(start = '1/1/2013', freq='H',periods=100,closed='left', normalize=True)

#take first date as example
date = dates[0]

# subtract a month
dates[0] - pd.DateOffset(months=1)
Timestamp('2012-12-01 00:00:00')

# to apply this on all dates
new_dates = list(map(lambda x: x - pd.DateOffset(months=1), dates))