Найдите ближайшую строку DataFrame до заданного времени в Pandas

У меня есть Pandas dataframe, который индексируется DatetimeIndex:

<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 53732 entries, 1993-01-07 12:23:58 to 2012-12-02 20:06:23
Data columns:
Date(dd-mm-yy)_Time(hh-mm-ss)       53732  non-null values
Julian_Day                          53732  non-null values
AOT_870                             53732  non-null values
440-870Angstrom                     53732  non-null values
440-675Angstrom                     53732  non-null values
500-870Angstrom                     53732  non-null values
Last_Processing_Date(dd/mm/yyyy)    53732  non-null values
Solar_Zenith_Angle                  53732  non-null values
time                                53732  non-null values
dtypes: datetime64[ns](2), float64(6), object(1)

Я хочу найти строку, которая ближе всего к определенному времени:

image_time = dateutil.parser.parse('2009-07-28 13:39:02')

и найдите, насколько он близок. До сих пор я пробовал разные вещи, основываясь на идее вычитания времени, которое я хочу со всех времен, и нахождения наименьшей абсолютной величины, но, похоже, никто не работает.

Например:

aeronet.index - image_time

Дает ошибку, которая, как мне кажется, связана с +/- в индексе Datetime, меняющим вещи, поэтому я попытался помещать индекс в другой столбец, а затем работал над этим:

aeronet['time'] = aeronet.index
aeronet.time - image_time

Кажется, что это работает, но для того, чтобы делать то, что я хочу, мне нужно получить разницу по времени ABSOLUTE, а не относительную разницу. Однако при запуске abs или np.abs на нем появляется сообщение об ошибке:

abs(aeronet.time - image_time)

C:\Python27\lib\site-packages\pandas\core\series.pyc in __repr__(self)
   1061         Yields Bytestring in Py2, Unicode String in py3.
   1062         """
-> 1063         return str(self)
   1064 
   1065     def _tidy_repr(self, max_vals=20):

C:\Python27\lib\site-packages\pandas\core\series.pyc in __str__(self)
   1021         if py3compat.PY3:
   1022             return self.__unicode__()
-> 1023         return self.__bytes__()
   1024 
   1025     def __bytes__(self):

C:\Python27\lib\site-packages\pandas\core\series.pyc in __bytes__(self)
   1031         """
   1032         encoding = com.get_option("display.encoding")
-> 1033         return self.__unicode__().encode(encoding, 'replace')
   1034 
   1035     def __unicode__(self):

C:\Python27\lib\site-packages\pandas\core\series.pyc in __unicode__(self)
   1044                     else get_option("display.max_rows"))
   1045         if len(self.index) > (max_rows or 1000):
-> 1046             result = self._tidy_repr(min(30, max_rows - 4))
   1047         elif len(self.index) > 0:
   1048             result = self._get_repr(print_header=True,

C:\Python27\lib\site-packages\pandas\core\series.pyc in _tidy_repr(self, max_vals)
   1069         """
   1070         num = max_vals // 2
-> 1071         head = self[:num]._get_repr(print_header=True, length=False,
   1072                                     name=False)
   1073         tail = self[-(max_vals - num):]._get_repr(print_header=False,

AttributeError: 'numpy.ndarray' object has no attribute '_get_repr'

Я подхожу к этому правильно? Если да, как мне заставить работать abs, чтобы я мог выбрать минимальную абсолютную разницу во времени и, таким образом, получить самое близкое время. Если нет, каков наилучший способ сделать это с помощью временного ряда Pandas?

Ответ 1

Я думаю, вы можете попробовать DatetimeIndex.asof найти самую последнюю метку вплоть до ввода и включить ее. Затем используйте возвращенное время datetime для выбора соответствующей строки. Если вам нужны только значения для определенного столбца, Series.asof существует и объединяет два шага выше в один.

Это предполагает, что вы хотите получить самое близкое время и время. Если вам не нужна дата и просто нужно одно и то же время каждый день, используйте at_time в DataFrame.

Последующие действия:

Изменить: ложный сигнал тревоги, у меня была более ранняя версия локально. Последний из мастеров должен работать с np.abs.

In [10]: np.abs(df.time - image_time)
Out[10]: 
0    27 days, 13:39:02
1    26 days, 13:39:02
2    25 days, 13:39:02
3    24 days, 13:39:02
4    23 days, 13:39:02
5    22 days, 13:39:02

Также просто уточнить:

aeronet.index - image_time не работает, потому что вычитание по индексу является заданной разницей (в тот же день, когда индекс был ограничен, чтобы быть уникальным).

Ответ 2

Этот простой метод вернет индекс (целочисленный индекс) элемента TimeSeriesIndex, ближайший к данному объекту datetime. Нет необходимости копировать индекс в обычный столбец - просто используйте метод .to_pydatetime.

import numpy as np

i = np.argmin(np.abs(df.index.to_pydatetime() - image_time))

Затем вы просто используете индексор DataFrame .iloc:

df.iloc[i]

Вот функция для этого:

def fcl(df, dtObj):
    return df.iloc[np.argmin(np.abs(df.index.to_pydatetime() - dtObj))]

Затем вы можете дополнительно фильтровать плавно, например.

fcl(df, dtObj)['column']