如何从包含日期时间对象的数组中进行插值?
How do you interpolate from an array containing datetime objects?
我正在寻找一个类似于 np.interp
的函数,它可以处理 datetime
个对象。
例如:
import datetime, numpy as np
arr1 = np.array([datetime.datetime(2008,1,d) for d in range(1,10)])
arr2 = np.arange(1,10)
np.interp(datetime.datetime(2008,1,5,12),arr1,arr2)
理想情况下 return 5.5
,但 numpy
加注 TypeError: array cannot be safely cast to required type
。有没有很好的 pythonic 方法解决这个问题?
您可以将它们转换为时间戳(已编辑以反映 calendar.timegm
的使用以避免与时区相关的陷阱)。
# Python 2.7
import datetime, numpy as np
import calendar
def toTimestamp(d):
return calendar.timegm(d.timetuple())
arr1 = np.array([toTimestamp(datetime.datetime(2008,1,d)) for d in range(1,10)])
arr2 = np.arange(1,10)
result = np.interp(toTimestamp(datetime.datetime(2008,1,5,12)),arr1,arr2)
print result # Prints 5.5
numpy.interp()
function 期望 arr1
和 arr2
是浮点数的一维序列,即,如果需要,您应该将 datetime
对象的序列转换为浮点数的一维序列使用 np.interp()
.
如果输入数据对所有日期时间对象使用相同的 UTC 偏移量,那么您可以通过从所有值中减去参考日期来获得浮点数。如果 为真(偏移量始终为零):
from datetime import datetime
import numpy as np
arr1 = np.array([datetime(2008, 1, d) for d in range(1, 10)])
arr2 = np.arange(1, 10)
def to_float(d, epoch=arr1[0]):
return (d - epoch).total_seconds()
f = np.interp(to_float(datetime(2008,1,5,12)), map(to_float, arr1), arr2)
print f # -> 5.5
我提供这个作为对@rchang 对那些想要在 Pandas 中完成所有这些的人的回答的补充。此函数采用包含日期的 pandas 系列和 returns 一个新系列,其值在指定日期后转换为 'number of days'。
def convert_dates_to_days(dates, start_date=None, name='Day'):
"""Converts a series of dates to a series of float values that
represent days since start_date.
"""
if start_date:
ts0 = pd.Timestamp(start_date).timestamp()
else:
ts0 = 0
return ((dates.apply(pd.Timestamp.timestamp) -
ts0)/(24*3600)).rename(name)
不确定它是否适用于时间,或者它是否不受上述时区陷阱的影响。但我认为只要您提供同一时区的开始日期,从所有时间戳值中减去该日期,就可以了。
以下是我的使用方法:
from scipy.interpolate import interp1d
data = pd.DataFrame({
'Date': pd.date_range('2018-01-01', '2018-01-22', freq='7D'),
'Value': np.random.randn(4)
})
x = convert_dates_to_days(data.Date, start_date='2018-01-01')
y = data.Value
f2 = interp1d(x, y, kind='cubic')
all_dates = pd.Series(pd.date_range('2018-01-01', '2018-01-22'))
x_all = convert_dates_to_days(all_dates, start_date='2018-01-01')
plt.plot(all_dates, f2(x_all), '-')
data.set_index('Date')['Value'].plot(style='o')
plt.grid()
plt.savefig("interp_demo.png")
plt.show()
似乎有效...
如果您的时间戳 have/need 亚秒级精度,这里是 rchang's 的略微编辑版本(基本上只是一种不同的 toTimestamp
方法)
import datetime, numpy as np
def toTimestamp(d):
return d.timestamp()
arr1 = np.array([toTimestamp(datetime.datetime(2000,1,2,3,4,5) + datetime.timedelta(0,d)) for d in np.linspace(0,1,9)])
arr2 = np.arange(1,10) # 1, 2, ..., 9
result = np.interp(toTimestamp(datetime.datetime(2000,1,2,3,4,5,678901)),arr1,arr2)
print(result) # Prints 6.431207656860352
关于时区问题我不能说什么,因为我还没有用其他时区测试过。
我正在寻找一个类似于 np.interp
的函数,它可以处理 datetime
个对象。
例如:
import datetime, numpy as np
arr1 = np.array([datetime.datetime(2008,1,d) for d in range(1,10)])
arr2 = np.arange(1,10)
np.interp(datetime.datetime(2008,1,5,12),arr1,arr2)
理想情况下 return 5.5
,但 numpy
加注 TypeError: array cannot be safely cast to required type
。有没有很好的 pythonic 方法解决这个问题?
您可以将它们转换为时间戳(已编辑以反映 calendar.timegm
的使用以避免与时区相关的陷阱)。
# Python 2.7
import datetime, numpy as np
import calendar
def toTimestamp(d):
return calendar.timegm(d.timetuple())
arr1 = np.array([toTimestamp(datetime.datetime(2008,1,d)) for d in range(1,10)])
arr2 = np.arange(1,10)
result = np.interp(toTimestamp(datetime.datetime(2008,1,5,12)),arr1,arr2)
print result # Prints 5.5
numpy.interp()
function 期望 arr1
和 arr2
是浮点数的一维序列,即,如果需要,您应该将 datetime
对象的序列转换为浮点数的一维序列使用 np.interp()
.
如果输入数据对所有日期时间对象使用相同的 UTC 偏移量,那么您可以通过从所有值中减去参考日期来获得浮点数。如果
from datetime import datetime
import numpy as np
arr1 = np.array([datetime(2008, 1, d) for d in range(1, 10)])
arr2 = np.arange(1, 10)
def to_float(d, epoch=arr1[0]):
return (d - epoch).total_seconds()
f = np.interp(to_float(datetime(2008,1,5,12)), map(to_float, arr1), arr2)
print f # -> 5.5
我提供这个作为对@rchang 对那些想要在 Pandas 中完成所有这些的人的回答的补充。此函数采用包含日期的 pandas 系列和 returns 一个新系列,其值在指定日期后转换为 'number of days'。
def convert_dates_to_days(dates, start_date=None, name='Day'):
"""Converts a series of dates to a series of float values that
represent days since start_date.
"""
if start_date:
ts0 = pd.Timestamp(start_date).timestamp()
else:
ts0 = 0
return ((dates.apply(pd.Timestamp.timestamp) -
ts0)/(24*3600)).rename(name)
不确定它是否适用于时间,或者它是否不受上述时区陷阱的影响。但我认为只要您提供同一时区的开始日期,从所有时间戳值中减去该日期,就可以了。
以下是我的使用方法:
from scipy.interpolate import interp1d
data = pd.DataFrame({
'Date': pd.date_range('2018-01-01', '2018-01-22', freq='7D'),
'Value': np.random.randn(4)
})
x = convert_dates_to_days(data.Date, start_date='2018-01-01')
y = data.Value
f2 = interp1d(x, y, kind='cubic')
all_dates = pd.Series(pd.date_range('2018-01-01', '2018-01-22'))
x_all = convert_dates_to_days(all_dates, start_date='2018-01-01')
plt.plot(all_dates, f2(x_all), '-')
data.set_index('Date')['Value'].plot(style='o')
plt.grid()
plt.savefig("interp_demo.png")
plt.show()
似乎有效...
如果您的时间戳 have/need 亚秒级精度,这里是 rchang's toTimestamp
方法)
import datetime, numpy as np
def toTimestamp(d):
return d.timestamp()
arr1 = np.array([toTimestamp(datetime.datetime(2000,1,2,3,4,5) + datetime.timedelta(0,d)) for d in np.linspace(0,1,9)])
arr2 = np.arange(1,10) # 1, 2, ..., 9
result = np.interp(toTimestamp(datetime.datetime(2000,1,2,3,4,5,678901)),arr1,arr2)
print(result) # Prints 6.431207656860352
关于时区问题我不能说什么,因为我还没有用其他时区测试过。