Pandas:快速将可变月份数添加到时间戳列

Ben*_*uhn 5 python datetime numpy pandas

这是设置:

我有两个(整数索引)列,startmonth_delta. start有时间戳(它的内部类型是np.datetime64[ns])并且month_delta是整数。

我想很快产生包括在每个日期时间的列start,在几个月内完成相应数量的偏移month_delta。我该怎么做呢?

我尝试过但不起作用的事情:

  • apply 太慢了。
  • 您不能将一系列DateOffset对象添加到一系列datetime64[ns]dtype(或 a DatetimeIndex)。
  • 您也不能使用 Seriestimedelta64对象;Pandas 默默地将基于月份的 timedeltas 转换为大约 30 天长的基于纳秒的 timedeltas。(哎呀!没有默默失败是怎么回事?)

目前,我正在迭代所有不同的值,month_delta并在我创建tshift的 a 的相关部分执行该数量的操作DatetimeIndex,但这是一个可怕的混杂:

new_dates = pd.Series(pd.Timestamp.now(), index=start.index)
date_index = pd.DatetimeIndex(start)
for i in xrange(month_delta.max()):
    mask = (month_delta == i)
    cur_dates = pd.Series(index=date_index[mask]).tshift(i, freq='M').index
    new_dates[mask] = cur_dates
Run Code Online (Sandbox Code Playgroud)

糟糕!有什么建议?

unu*_*tbu 3

这是一种方法(通过将 NumPy datetime64s 与 timedelta64s 添加),无需调用apply

import pandas as pd
import numpy as np
np.random.seed(1)

def combine64(years, months=1, days=1, weeks=None, hours=None, minutes=None,
              seconds=None, milliseconds=None, microseconds=None, nanoseconds=None):
    years = np.asarray(years) - 1970
    months = np.asarray(months) - 1
    days = np.asarray(days) - 1
    types = ('<M8[Y]', '<m8[M]', '<m8[D]', '<m8[W]', '<m8[h]',
             '<m8[m]', '<m8[s]', '<m8[ms]', '<m8[us]', '<m8[ns]')
    vals = (years, months, days, weeks, hours, minutes, seconds,
            milliseconds, microseconds, nanoseconds)
    return sum(np.asarray(v, dtype=t) for t, v in zip(types, vals)
               if v is not None)

def year(dates):
    "Return an array of the years given an array of datetime64s"
    return dates.astype('M8[Y]').astype('i8') + 1970

def month(dates):
    "Return an array of the months given an array of datetime64s"
    return dates.astype('M8[M]').astype('i8') % 12 + 1

def day(dates):
    "Return an array of the days of the month given an array of datetime64s"
    return (dates - dates.astype('M8[M]')) / np.timedelta64(1, 'D') + 1

N = 10
df = pd.DataFrame({
   'start': pd.date_range('2000-1-25', periods=N, freq='D'),
   'months': np.random.randint(12, size=N)})
start = df['start'].values
df['new_date'] = combine64(year(start), months=month(start) + df['months'], 
                           days=day(start))

print(df)
Run Code Online (Sandbox Code Playgroud)

产量

   months      start   new_date
0       5 2000-01-25 2000-06-25
1      11 2000-01-26 2000-12-26
2       8 2000-01-27 2000-09-27
3       9 2000-01-28 2000-10-28
4      11 2000-01-29 2000-12-29
5       5 2000-01-30 2000-06-30
6       0 2000-01-31 2000-01-31
7       0 2000-02-01 2000-02-01
8       1 2000-02-02 2000-03-02
9       7 2000-02-03 2000-09-03
Run Code Online (Sandbox Code Playgroud)

  • 目前对矢量日期操作的支持非常薄弱。 (2认同)