在Pandas中找到与给定时间最近的DataFrame行

17 投票
3 回答
25373 浏览
提问于 2025-04-17 17:19

我有一个Pandas的数据框,它的索引是时间格式的:

<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

这个方法报错了,我觉得是因为在时间索引上进行加减操作会导致一些问题,所以我尝试把索引放到另一列,然后在那上面进行操作:

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

这个方法似乎有效,但为了实现我的目标,我需要得到绝对的时间差,而不是相对的差值。然而,直接对它使用 absnp.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时间序列的最佳方法是什么呢?

3 个回答

5

今天我也遇到了同样的问题。我想要一个函数,能够给我在某个时间戳之前最近的值。下面是我写的函数:

def get_nearest_past(data, timestamp):
    index = data.index.get_loc(timestamp,"ffill")
    return data.iloc[index]

如果你需要的是全局最近的值(而不是像我这种只要在之前的值),你可以使用:

def get_nearest(data, timestamp):
    index = data.index.get_loc(timestamp,"nearest")
    return data.iloc[index]

你可以在get_loc的文档中找到更多信息。

20

这个简单的方法会返回一个整数,表示离给定的日期时间对象最近的时间序列索引的位置。你不需要把这个索引复制到一个普通的列里,只需使用 .to_pydatetime 方法就可以了。

import numpy as np

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

接着,你只需使用数据框的 .iloc 索引器:

df.iloc[i]

这里有一个函数可以做到这一点:

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

然后你可以继续无缝地进行进一步的筛选,比如:

fcl(df, dtObj)['column']
8

我觉得你可以试试 DatetimeIndex.asof 这个方法,它可以找到输入时间之前最近的标签,包括这个输入时间。然后你可以用返回的时间来选择对应的那一行数据。

如果你只需要某一列的值,Series.asof 这个方法可以把上面两个步骤合并成一个。

这假设你想要的是最接近的时间。如果你不在乎日期,只想要每天的同一时间,可以在 DataFrame 中使用 at_time

后续补充:

编辑:没事,是我本地的版本太旧了。最新的主版本应该可以和 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 这个不行,因为在 Index 上做减法是集合差(以前 Index 是要求唯一的)。

撰写回答