我正在寻找一个类似于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)
理想情况下,会返回5.5
,但numpy
会引发TypeError: array cannot be safely cast to required type
。这周围有一种不错的pythonic方式吗?
答案 0 :(得分:9)
您可以将它们转换为时间戳(编辑后反映使用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
答案 1 :(得分:2)
numpy.interp()
function期望arr1
和arr2
是浮点数的1D序列,即如果要使用,则应将datetime
个对象的序列转换为1D浮点序列np.interp()
。
如果输入数据对所有日期时间对象使用相同的UTC偏移量,则可以通过从所有值中减去参考日期来获得浮点数。如果your input is 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
答案 2 :(得分:1)
如果您的时间戳中需要/秒以内,则这里是rchang的answer的略作编辑的版本(基本上只是一种不同的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
关于时区问题,我无话可说,因为我没有在其他时区进行测试。
答案 3 :(得分:0)
我为@rchang的回答提供补充,以供那些希望在熊猫中做到这一点的人使用。此函数采用包含日期的熊猫系列,并返回一个新系列,其值将在指定日期后转换为“天数”。
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()
似乎可行...