Skip to main content
 首页 » 编程设计

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

2025年05月04日9mq0036

我想将 pandas DateTimeIndex 转换为 excel 日期(自 12/30/1899 以来的天数)。我尝试在采用 datetime64s 并返回 excel 日期的函数上使用 numpy.vectorize。我对 numpy vectorize 的行为方式感到惊讶 - 在第一次调用时,一个查看返回类型的测试调用,vectorize 按照提供的方式传入 datetime64。在随后的调用中,它传入 datetime64 的内部存储类型——在我的例子中是 long。在内部,_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)  

请您参考如下方法:

Datetimes 和 timedeltas 需要使用底层数据来处理(你只需执行 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的 View

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