关于python:从numpy datetime64获取年,月或日

Get year, month or day from numpy datetime64

我有一个datetime64类型的数组:

1
dates = np.datetime64(['2010-10-17', '2011-05-13',"2012-01-15"])

有没有比遍历每个元素以获得年的np.array更好的方法:

1
2
3
years = f(dates)
#output:
array([2010, 2011, 2012], dtype=int8) #or dtype = string

我正在使用稳定的numpy版本1.6.2。


我发现以下技巧可以使速度达到上述熊猫方法的2倍至4倍(即pd.DatetimeIndex(dates).year等)。我发现[dt.year for dt in dates.astype(object)]的速度类似于pandas方法。这些技巧也可以直接应用于任何形状的ndarray(2D,3D等)

1
2
3
4
dates = np.arange(np.datetime64('2000-01-01'), np.datetime64('2010-01-01'))
years = dates.astype('datetime64[Y]').astype(int) + 1970
months = dates.astype('datetime64[M]').astype(int) % 12 + 1
days = dates - dates.astype('datetime64[M]') + 1


由于日期时间在numpy中不稳定,因此我将使用pandas:

1
2
3
4
5
6
In [52]: import pandas as pd

In [53]: dates = pd.DatetimeIndex(['2010-10-17', '2011-05-13',"2012-01-15"])

In [54]: dates.year
Out[54]: array([2010, 2011, 2012], dtype=int32)

熊猫内部使用numpy datetime,但似乎可以避免numpy到目前为止的不足。


应该有一个更简单的方法来执行此操作,但是,根据您要执行的操作,最好的方法可能是将其转换为常规的Python datetime对象:

1
2
3
4
5
datetime64Obj = np.datetime64('2002-07-04T02:55:41-0700')
print datetime64Obj.astype(object).year
# 2002
print datetime64Obj.astype(object).day
# 4

根据以下评论,这似乎仅适用于Python 2.7.x和Python 3.6+


这就是我的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import numpy as np

def dt2cal(dt):
   """
    Convert array of datetime64 to a calendar array of year, month, day, hour,
    minute, seconds, microsecond with these quantites indexed on the last axis.

    Parameters
    ----------
    dt : datetime64 array (...)
        numpy.ndarray of datetimes of arbitrary shape

    Returns
    -------
    cal : uint32 array (..., 7)
        calendar array with last axis representing year, month, day, hour,
        minute, second, microsecond
   """


    # allocate output
    out = np.empty(dt.shape + (7,), dtype="u4")
    # decompose calendar floors
    Y, M, D, h, m, s = [dt.astype(f"M8[{x}]") for x in"YMDhms"]
    out[..., 0] = Y + 1970 # Gregorian Year
    out[..., 1] = (M - Y) + 1 # month
    out[..., 2] = (D - M) + 1 # dat
    out[..., 3] = (dt - D).astype("m8[h]") # hour
    out[..., 4] = (dt - h).astype("m8[m]") # minute
    out[..., 5] = (dt - m).astype("m8[s]") # second
    out[..., 6] = (dt - s).astype("m8[us]") # microsecond
    return out

它可以跨任意输入维度进行矢量化处理,速度快,直观,可以在numpy v1.15.4上运行,并且不使用熊猫。

我真的希望numpy支持此功能,在应用程序开发中始终需要它。当我不得不像这样滚动自己的东西时,我总是会非常紧张,我总是觉得自己缺少了一个优势。


使用numpy版本1.10.4和pandas版本0.17.1,

1
2
dates = np.array(['2010-10-17', '2011-05-13', '2012-01-15'], dtype=np.datetime64)
pd.to_datetime(dates).year

我得到您想要的东西:

1
array([2010, 2011, 2012], dtype=int32)


使用dates.tolist()转换为本地日期时间对象,然后只需访问year。例:

1
2
3
>>> dates = np.array(['2010-10-17', '2011-05-13', '2012-01-15'], dtype='datetime64')
>>> [x.year for x in dates.tolist()]
[2010, 2011, 2012]

这基本上与https://stackoverflow.com/a/35281829/2192272中公开的想法相同,但使用的语法更简单。

用python 3.6 / numpy 1.18测试。


另一种可能性是:

1
np.datetime64(dates,'Y') - returns - numpy.datetime64('2010')

要么

1
np.datetime64(dates,'Y').astype(int)+1970 - returns - 2010

但仅适用于标量值,不会采用数组


Anon的答案对我非常有用,但我只需要修改days的语句

从:

1
days = dates - dates.astype('datetime64[M]') + 1

至:

1
days = dates.astype('datetime64[D]') - dates.astype('datetime64[M]') + 1


如果您升级到numpy 1.7(日期时间仍被标记为实验性),则应可以进行以下操作。

1
dates/np.timedelta64(1,'Y')


不幸的是,目前还没有直接的方法,但是有两种间接的方法:

1
[dt.year for dt in dates.astype(object)]

要么

1
[datetime.datetime.strptime(repr(d),"%Y-%m-%d %H:%M:%S").year for d in dates]

两者均受此处示例的启发。

这两个对我来说都适用于Numpy 1.6.1。您可能需要对第二个更谨慎,因为datetime64的repr()可能在小数点后有一个小数部分。