在numpy 1.7.1中,datetime64和vectorize之间是否存在不良交互作用?

3
我想将一个Pandas的DateTimeIndex转换为Excel日期(自1899年12月30日起经过的天数)。我尝试使用numpy.vectorize来调用一个以datetime64类型为参数并返回Excel日期的函数。但是,我对numpy.vectorize的行为感到惊讶——在第一次调用时,它会传递原始的datetime64类型以查看返回类型。在后续调用中,它会传递datetime64的内部存储类型——在我的情况下是一个长整型。在内部,_get_ufunc_and_otypes会调用:
inputs = [asarray(_a).flat[0] for _a in args]
outputs = func(*inputs)

_vectorize_call 函数执行以下操作:

inputs = [array(_a, copy=False, subok=True, dtype=object) 
                  for _a in args]            

outputs = ufunc(*inputs)

事实证明,我可以使用内部的numpy数组计算来做到这一点((x-day0)/ 1day)。但是这种行为似乎很奇怪(在向量化函数时更改类型)。
以下是我的示例代码:
import numpy

DATETIME64_ONE_DAY   = numpy.timedelta64(1,'D')
DATETIME64_DATE_ZERO = numpy.datetime64('1899-12-30T00:00:00.000000000')

def excelDateToDatetime64(x):
   return DATETIME64_DATE_ZERO + numpy.timedelta64(int(x),'D')

def datetime64ToExcelDate(x):
   print type(x)
   return (x - DATETIME64_DATE_ZERO) / DATETIME64_ONE_DAY

excelDateToDatetime64_Array = numpy.vectorize(excelDateToDatetime64)
datetime64ToExcelDate_Array = numpy.vectorize(datetime64ToExcelDate)

excelDates = numpy.array([ 41407.0, 41408.0, 41409.0, 41410.0, 41411.0, 41414.0 ])
datetimes  = excelDateToDatetime64_Array(excelDates)
excelDates2 = datetime64ToExcelDate(datetimes)


print excelDates2  # Works fine

# TypeError: ufunc subtract cannot use operands with types dtype('int64') and dtype('<M8[ns]')
# You can see from the print that the type coming in is inconsistent
excelDates2 = datetime64ToExcelDate_Array(datetimes) 
1个回答

1
日期时间和时间差需要使用底层数据进行处理(只需使用arr.view('i8')获取,这些是np.int64)。以其基础值定义您的常量。
In [94]: DATETIME_DATE_ZERO_VIEW = DATETIME64_DATE_ZERO.view('i8')

In [95]: DATETIME_DATE_ZERO_VIEW
Out[95]: -2209161600000000000

In [96]: DATETIME64_ONE_DAY_VALUE = DATETIME64_ONE_DAY.astype('m8[ns]').item()

In [97]: DATETIME64_ONE_DAY_VALUE
Out[97]: 86400000000000L

In [106]: def vect(x):
   .....:     return (x-DATETIME_DATE_ZERO_VIEW)/DATETIME64_ONE_DAY_VALUE
   .....: 

In [107]: f = np.vectorize(vect)

传递一个基础 np.int64 的视图。
In [109]: f(datetimes.view('i8'))
Out[109]: array([41407, 41408, 41409, 41410, 41411, 41414])

Pandas方法

In [98]: Series(datetimes).apply(lambda x: (x.value-DATETIME_DATE_ZERO_VIEW)/DATETIME64_ONE_DAY_VALUE)
Out[98]: 
0    41407
1    41408
2    41409
3    41410
4    41411
5    41414
dtype: int64

可以了 - 非常感谢。但是,我写的代码行为仍然让我感到奇怪(特别是第一次调用传递了datetime64,而后续调用得到了底层的np.int64)。 - DaveBlob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接