Como você interpola de uma matriz contendo objects datetime?

Eu estou procurando uma function análoga ao np.interp que pode trabalhar com objects de datetime e datetime .

Por exemplo:

 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) 

O ideal seria retornar 5.5 , mas numpy gera TypeError: array cannot be safely cast to required type . Existe um bom caminho pythonic em torno disso?

Você pode convertê-los em timestamps (editados para refletir o uso de calendar.timegm para evitar armadilhas relacionadas a fuso horário).

 # 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 numpy.interp() espera que arr1 e arr2 sejam seqüências 1D de floats, ou seja, você deve converter a seqüência de objects datetime em uma sequência 1D de floats se você quiser usar np.interp() .

Se os dados de input usarem o mesmo deslocamento UTC para todos os objects de data e hora, você poderá obter um ponto flutuante subtraindo uma data de referência de todos os valores. É verdade que sua input é UTC (o deslocamento é sempre zero):

 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 

Se você tem / precisa de precisão de sub-segundo em seus timestamps, aqui está uma versão ligeiramente editada da resposta do rchang (basicamente apenas um método toTimestamp diferente)

 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 

Não posso dizer nada sobre problemas de fuso horário, pois não testei isso com outros fusos horários.

Estou fornecendo isso como um complemento à resposta do @rchang para aqueles que querem fazer tudo isso no Pandas. Essa function usa uma série de pandas contendo datas e retorna uma nova série com os valores convertidos em ‘number of days’ após uma data especificada.

 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) 

Não tenho certeza se vai funcionar com o tempo ou se é imune às armadilhas de fuso horário mencionadas acima. Mas eu acho que desde que você forneça uma data de início no mesmo fuso horário, que é subtraído de todos os valores de timestamp, você deve estar bem.

Aqui está como eu usei:

 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() 

Parece funcionar …

insira a descrição da imagem aqui