Python 从numpy datetime64获取年、月或日

Python 从numpy datetime64获取年、月或日,python,datetime,numpy,Python,Datetime,Numpy,我有一个datetime64类型的数组: dates = np.datetime64(['2010-10-17', '2011-05-13', "2012-01-15"]) 有没有比通过循环每个元素来获得np.array年数更好的方法 years = f(dates) #output: array([2010, 2011, 2012], dtype=int8) #or dtype = string 我使用的是稳定的numpy版本1.6.2。如果您升级到numpy 1.7(其中datetime

我有一个datetime64类型的数组:

dates = np.datetime64(['2010-10-17', '2011-05-13', "2012-01-15"])
有没有比通过循环每个元素来获得np.array年数更好的方法

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

我使用的是稳定的numpy版本1.6.2。

如果您升级到numpy 1.7(其中datetime仍然标记为实验版),以下应该可以工作

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

由于datetime在numpy不稳定,因此我将使用pandas:

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)

Pandas在内部使用numpy datetime,但似乎避免了numpy迄今为止的不足。

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

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

两者都是从例子中得到启发的


这两种方法在Numpy 1.6.1上都适用。您可能需要更加小心地使用第二种方法,因为datetime64的repr()可能在小数点后有一个小数部分。

我发现与上述pandas方法相比,以下技巧可以使速度提高2到4倍(即
pd.DatetimeIndex(dates).year
等)。
[dt.year for dt in dates.astype(object)]
的速度与pandas方法类似。此外,这些技巧还可以直接应用于任何形状(2D、3D等)的NDArray


应该有一种更简单的方法来实现这一点,但是,根据您的尝试,最好的方法可能是转换为常规:


根据下面的评论,这似乎只适用于使用numpy版本1.10.4和pandas版本0.17.1的Python 2.7.x和Python 3.6+

dates = np.array(['2010-10-17', '2011-05-13', '2012-01-15'], dtype=np.datetime64)
pd.to_datetime(dates).year
我得到了你想要的:

array([2010, 2011, 2012], dtype=int32)
对我来说效果很好,但我只需要修改
天的语句

发件人:

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


days=dates.astype('datetime64[D]')-dates.astype('datetime64[M]')+1
另一种可能性是:

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

但只对标量值有效,不接受数组。我就是这样做的

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支持这个功能,它在应用程序开发中一直是必需的。当我不得不像这样滚动我自己的东西时,我总是非常紧张,我总是觉得我错过了一个边缘案例。

使用
dates.tolist()
转换为本机datetime对象,然后只需访问
year
。例如:

日期=np.数组(['2010-10-17','2011-05-13','2012-01-15',dtype='datetime64') >>>[x.year for x in dates.tolist()] [2010, 2011, 2012] 这基本上与中公开的想法相同,但使用更简单的语法

使用python 3.6/numpy 1.18进行测试。

np.datetime64
转换为浮点年份 在这个解决方案中,您可以逐步了解如何处理
np.datetime64
数据类型

在以下情况下,dt64的类型为
np.datetime64
(甚至是该类型的numpy.ndarray):

  • year=dt64.astype('M8[Y])
    只包含年份。如果您想要这样的浮点数组,请执行
    1970+year.astype(float)
  • 您可以通过
    days=(dt64-year)访问的天数(自1月1日起)。astype('timedelta64[D]”)
  • 您还可以推断一年是否为闰年(比较一年中的天数)

输出

2011-11-11 as float: 2011.8602739726027

dates:       ['1970-01-01' '2014-01-01' '2020-12-31' '2019-12-31' '2010-04-28']
float_dates: [1970.         2014.         2020.99726776 2019.99726027 2010.32054795]

这显然已经很晚了,但我从其中一个答案中受益匪浅,所以在这里分享我的观点



这给了我一个月的错误结果,numpy 1.7.1和pandas 0.12.0。但是,
Series(dates).apply(lambda x:x.month)
似乎可以工作。对于相同的版本,这里没有问题。如果你真的得到了错误的结果,你应该打开一个pandas问题。哦,我实际上使用了
pd.DatetimeIndex(np.datetime64(['2010-10-17','2011-05-13','2012-01-15'))
将datetime64对象转换成pandas可以解析的字符串。@sebix:为什么?Pandas理解Datetime64。您可以使用列表操作在整个数组上执行此操作:
[dtime64Array.astype(object)]
此代码有效,但如果我给它一个不同的np.Datetime64(来自数据帧的日期),它的计算结果将是long,而不是datetime。。。即使我显式使用astype(datetime.datetime),它的计算结果也是long。。。奇怪的…。@approwest先生,我对此不确定。也许值得写一个更详细的版本来展示双重行为的例子。然后将其作为一个新问题提交,并在此处链接。这在python 3.5中不起作用-
AttributeError:'int'对象没有属性'year'
。我也不知道为什么is应该在2.7中工作,为什么
.astype(object)
转换成
datetime.datetime
?我刚刚在python-3.6.3中测试了它,它可以工作:
将numpy作为np导入;打印(np.datetime64('2002-07-04T02:55:41-0700').aType(object.year)
注意,从1.9开始,此方法不起作用。此除法用于将时间跨度转换为浮点数年。它不会提取日期的年份属性。这是一个很好的解决方案。如果在numpy中有这样简单的东西,那就太好了。谢谢你给了我一个答案,而不是说“你不应该使用,改用”。这很有效,而且对
datetime
无法处理的日期也有效:
d=np.datetime64('-200003-10-01')。astype('datetime64[Y]')。astype(int)+1970
产生
-2000003
以获取整数,而不是
timedelta64[D]
在上面的
天的示例中,使用:
(dates-dates.astype('datetime64[M]')。astype(int)+1
这在python 3.5、numpy 1.11中不起作用,出于同样的原因,我对这个答案的评论应该变成对你提到的Anon答案的评论(或编辑)。你写“f(日期)”是什么意思。“f()”做什么?为这个
pd添加了一个功能请求。to_datetime
可能是一个非常慢的优秀函数。可能真的
days = dates - dates.astype('datetime64[M]') + 1
days = dates.astype('datetime64[D]') - dates.astype('datetime64[M]') + 1
np.datetime64(dates,'Y') - returns - numpy.datetime64('2010')
np.datetime64(dates,'Y').astype(int)+1970 - returns - 2010
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
import numpy as np
import pandas as pd

def dt64_to_float(dt64):
    """Converts numpy.datetime64 to year as float.

    Rounded to days

    Parameters
    ----------
    dt64 : np.datetime64 or np.ndarray(dtype='datetime64[X]')
        date data

    Returns
    -------
    float or np.ndarray(dtype=float)
        Year in floating point representation
    """

    year = dt64.astype('M8[Y]')
    # print('year:', year)
    days = (dt64 - year).astype('timedelta64[D]')
    # print('days:', days)
    year_next = year + np.timedelta64(1, 'Y')
    # print('year_next:', year_next)
    days_of_year = (year_next.astype('M8[D]') - year.astype('M8[D]')
                    ).astype('timedelta64[D]')
    # print('days_of_year:', days_of_year)
    dt_float = 1970 + year.astype(float) + days / (days_of_year)
    # print('dt_float:', dt_float)
    return dt_float

if __name__ == "__main__":

    dt_str = '2011-11-11'
    dt64 = np.datetime64(dt_str)
    print(dt_str, 'as float:', dt64_to_float(dt64))
    print()

    dates = np.array([
        '1970-01-01', '2014-01-01', '2020-12-31', '2019-12-31', '2010-04-28'],
        dtype='datetime64[D]')
    float_dates = dt64_to_float(dates)


    print('dates:      ', dates)
    print('float_dates:', float_dates)
2011-11-11 as float: 2011.8602739726027

dates:       ['1970-01-01' '2014-01-01' '2020-12-31' '2019-12-31' '2010-04-28']
float_dates: [1970.         2014.         2020.99726776 2019.99726027 2010.32054795]