我有一个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。
答案 0 :(得分:34)
由于日期时间在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到目前为止的短缺。
答案 1 :(得分:22)
我发现以下技巧与上述的熊猫方法(即pd.DatetimeIndex(dates).year
等)相比,速度提高了2倍和4倍。我发现[dt.year for dt in dates.astype(object)]
的速度与熊猫方法类似。这些技巧也可以直接应用于任何形状的ndarray(2D,3D等)
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
答案 2 :(得分:7)
应该有一种更简单的方法,但是,根据您尝试做的事情,最佳路线可能是转换为常规Python datetime object:
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 +
答案 3 :(得分:4)
使用dates.tolist()
转换为本地日期时间对象,然后只需访问year
。示例:
>>> 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测试。
答案 4 :(得分:2)
使用numpy版本1.10.4和pandas版本0.17.1,
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)
答案 5 :(得分:1)
如果您升级到numpy 1.7(其中datetime仍标记为试验版),则以下内容应该有效。
dates/np.timedelta64(1,'Y')
答案 6 :(得分:0)
不幸的是,没有直接的方法可以做到这一点,但有几种间接方式:
[dt.year for dt in dates.astype(object)]
或
[datetime.datetime.strptime(repr(d), "%Y-%m-%d %H:%M:%S").year for d in dates]
受到示例here的启发。
这两项都适用于Numpy 1.6.1。您可能需要对第二个更加小心,因为datetime64的repr()可能在小数点后面有一小部分。
答案 7 :(得分:0)
Anon's answer对我很有用,但我只需修改days
的声明
从:
days = dates - dates.astype('datetime64[M]') + 1
为:
days = dates.astype('datetime64[D]') - dates.astype('datetime64[M]') + 1
答案 8 :(得分:0)
另一种可能性是:
np.datetime64(dates,'Y') - returns - numpy.datetime64('2010')
或
np.datetime64(dates,'Y').astype(int)+1970 - returns - 2010
但仅适用于标量值,不会采用数组
答案 9 :(得分:0)
这就是我的方法。
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支持此功能,在应用程序开发中始终需要它。当我不得不像这样滚动自己的东西时,我总是会非常紧张,我总是觉得自己缺少了一个边缘保护套。
答案 10 :(得分:0)
np.datetime64
转换为浮点年在此解决方案中,您可以逐步了解如何处理 np.datetime64
数据类型。
在下面的 dt64 是 np.datetime64
类型(甚至是那种类型的 numpy.ndarray):
year = dt64.astype('M8[Y]')
只包含年份。如果您想要一个浮点数组,请执行 1970 + year.astype(float)
。days = (dt64 - year).astype('timedelta64[D]')
访问的日期(自 1 月 1 日起)days_of_year
)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]
答案 11 :(得分:0)
这显然已经很晚了,但我从其中一个答案中受益,所以在这里分享我的一点。
answer? 的 Anon 非常正确 - 使用 numpy 方法的速度非常快,而不是首先将它们转换为 pandas 日期时间序列然后获取日期。尽管 numpy 转换后结果的偏移和转换有点破旧,但可以为此编写一个更清晰的助手,如下所示:-
def from_numpy_datetime_extract(date: np.datetime64, extract_attribute: str = None):
_YEAR_OFFSET = 1970
_MONTH_OFFSET = 1
_MONTH_FACTOR = 12
_DAY_FACTOR = 24*60*60*1e9
_DAY_OFFSET = 1
if extract_attribute == 'year':
return date.astype('datetime64[Y]').astype(int) + _YEAR_OFFSET
elif extract_attribute == 'month':
return date.astype('datetime64[M]').astype(int)%_MONTH_FACTOR + _MONTH_OFFSET
elif extract_attribute == 'day':
return ((date - date.astype('datetime64[M]'))/_DAY_FACTOR).astype(int) + _DAY_OFFSET
else:
raise ValueError("extract_attribute should be either of 'year', 'month' or 'day'")
解决问题 dates = np.array(['2010-10-17', '2011-05-13', "2012-01-15"], dtype = 'datetime64')
:-
%timeit -r10 -n1000 [from_numpy_datetime_extract(x, "year") for x in dates]
# 14.3 µs ± 4.03 µs per loop (mean ± std. dev. of 10 runs, 1000 loops each)
%timeit -r10 -n1000 pd.to_datetime(dates).year.tolist()
# 304 µs ± 32.2 µs per loop (mean ± std. dev. of 10 runs, 1000 loops each)