2015-07-14 49 views
5

Trong Python, tôi có một loạt ngày được tạo (hoặc đọc từ tệp CSV) bằng cách sử dụng gấu trúc và tôi muốn thêm một năm vào mỗi ngày. Tôi có thể làm cho nó hoạt động bằng cách sử dụng gấu trúc nhưng không sử dụng gumpy. Tôi đang làm gì sai? Hay nó là một con bọ hoặc gấu trúc hay vạm vỡ?lỗi numpy và pandas timedelta

Cảm ơn!

import numpy as np 
import pandas as pd 
from pandas.tseries.offsets import DateOffset 

# Generate range of dates using pandas. 
dates = pd.date_range('1980-01-01', '2015-01-01') 

# Add one year using pandas. 
dates2 = dates + DateOffset(years=1) 

# Convert result to numpy. THIS WORKS! 
dates2_np = dates2.values 

# Convert original dates to numpy array. 
dates_np = dates.values 

# Add one year using numpy. THIS FAILS! 
dates3 = dates_np + np.timedelta64(1, 'Y') 

# TypeError: Cannot get a common metadata divisor for NumPy datetime metadata [ns] and [Y] because they have incompatible nonlinear base time units 

Trả lời

5

Thêm np.timedelta64(1, 'Y') tới một mảng của dtype datetime64[ns] không làm việc vì một năm không tương ứng với một số cố định của nano giây. Đôi khi một năm là 365 ngày, đôi khi 366 ngày, đôi khi thậm chí còn có thêm một bước nhảy vọt thứ hai. (Lưu ý thêm vài giây nhuận, chẳng hạn như một giây xảy ra vào ngày 2015-06-30 23:59:60, không thể đại diện là NumPy datetime64s.)

Cách dễ nhất tôi biết để thêm một năm vào một số NumPy datetime64[ns] là để phá vỡ nó thành bộ phận cấu thành, chẳng hạn như năm, tháng và ngày, thực hiện các tính toán trên mảng số nguyên, và sau đó recompose mảng datetime64:

def year(dates): 
    "Return an array of the years given an array of datetime64s" 
    return dates.astype('M8[Y]').astype('i8') + 1970 

def month(dates): 
    "Return an array of the months given an array of datetime64s" 
    return dates.astype('M8[M]').astype('i8') % 12 + 1 

def day(dates): 
    "Return an array of the days of the month given an array of datetime64s" 
    return (dates - dates.astype('M8[M]'))/np.timedelta64(1, 'D') + 1 

def combine64(years, months=1, days=1, weeks=None, hours=None, minutes=None, 
       seconds=None, milliseconds=None, microseconds=None, nanoseconds=None): 
    years = np.asarray(years) - 1970 
    months = np.asarray(months) - 1 
    days = np.asarray(days) - 1 
    types = ('<M8[Y]', '<m8[M]', '<m8[D]', '<m8[W]', '<m8[h]', 
      '<m8[m]', '<m8[s]', '<m8[ms]', '<m8[us]', '<m8[ns]') 
    vals = (years, months, days, weeks, hours, minutes, seconds, 
      milliseconds, microseconds, nanoseconds) 
    return sum(np.asarray(v, dtype=t) for t, v in zip(types, vals) 
       if v is not None) 

# break the datetime64 array into constituent parts 
years, months, days = [f(dates_np) for f in (year, month, day)] 
# recompose the datetime64 array after adding 1 to the years 
dates3 = combine64(years+1, months, days) 

sản lượng

In [185]: dates3 
Out[185]: 
array(['1981-01-01', '1981-01-02', '1981-01-03', ..., '2015-12-30', 
     '2015-12-31', '2016-01-01'], dtype='datetime64[D]') 

Mặc dù xuất hiện để được như vậy nhiều mã, nó thực sự nhanh hơn việc thêm DateOff tập hợp 1 năm:

In [206]: %timeit dates + DateOffset(years=1) 
1 loops, best of 3: 285 ms per loop 

In [207]: %%timeit 
    .....: years, months, days = [f(dates_np) for f in (year, month, day)] 
    .....: combine64(years+1, months, days) 
    .....: 
100 loops, best of 3: 2.65 ms per loop 

Tất nhiên, pd.tseries.offsets cung cấp một vỏ trang toàn bộ offsets mà không có đối tác dễ dàng khi làm việc với datetime64s NumPy.

+0

Tôi ngạc nhiên trước tốc độ và chi tiết của câu trả lời này! Bởi vì tôi đọc dữ liệu của mình bằng cách sử dụng gấu trúc, tôi thấy dễ dàng hơn khi tiếp tục sử dụng DateOffset của gấu trúc để chuyển đổi ngày trước khi tôi tính toán bằng cách sử dụng gọn gàng. Nhưng tôi đã nghĩ về việc thực hiện một chuyển đổi như bạn đề nghị, vì vậy bây giờ tôi có mã nguồn đó nếu tôi cần nó. Cảm ơn! – questiondude

1

Đây là những gì nó nói trong NumPy documentation:

Có hai đơn vị Timedelta ('Y', năm và 'M', tháng) mà được đối xử đặc biệt, bởi vì bao nhiêu thời gian chúng đại diện cho những thay đổi tùy thuộc vào thời điểm chúng được sử dụng. Mặc dù đơn vị thời gian trong ngày tương đương với 24 giờ, không có cách nào để chuyển đổi đơn vị tháng thành ngày, bởi vì các tháng khác nhau có số ngày khác nhau.

ngày và tuần dường như làm việc mặc dù:

dates4 = dates_np + np.timedelta64(1, 'D') 
dates5 = dates_np + np.timedelta64(1, 'W') 
+0

Vâng, tôi cũng đã đọc điều đó trong tài liệu. Nó không rõ ràng lên sự nhầm lẫn của tôi, mặc dù :-) – questiondude