找到离给定日期最近的日期

82

我有一个日期时间对象的数组,我想找到数组中离给定日期(例如datetime.datetime(2014,12,16))最近的元素是哪个。

这篇文章介绍了如何找到离给定日期最近的日期但不要早于给定日期。 我该如何修改这段代码以便它可以返回早于给定日期的日期?

例如,如果数组包含元素datetime.datetime(2014,12,10)datetime.datetime(2014,12,28),则应返回前者,因为它在绝对值上最接近datetime.datetime(2014,12,16)


也许你可以先把日期排序,然后检查你要查找的日期之前和之后的索引,看哪一个更接近它? - Zarwan
目前,我使用 np.argwhere 查找给定日期之前和之后的所有元素,并分别取最后一个或第一个元素。问题在于,有时数组中没有2014年12月16日之后的日期,这是我的脚本遇到的问题。找到最接近的日期会更容易。 - user3600497
你可以考虑使用 truncate 函数。 - Kevin Zhu
9个回答

152

该函数将返回items中最接近日期pivotdatetime

def nearest(items, pivot):
    return min(items, key=lambda x: abs(x - pivot))

如果类型支持比较、减法和 abs,例如数字和向量类型,这个函数对于除了 datetime 之外的其他类型也可以直接使用。


1
哇,太棒了!也许这有点像我 bigram 方法试图复制的东西,但更短。 - DevLounge
9
你没有解释清楚你的答案“这也适用于数字”的含义,并没有给出解释。什么是items,什么是pivot - Toskan
13
min(item for item in items if item > pivot) - Tamas Hegedus
4
此代码不返回给定日期之前最接近的日期。 - Chiel
2
这将返回一个日期。Lambda获取日期之间的绝对差异,然后min返回绝对差异最小的日期。 - Guy Keogh
显示剩余2条评论

47
根据这个链接的回答,'truncate'函数可以满足您的需求。df.truncate(before='2012-01-07') 或者您可以使用'get_loc'函数,选择'options'为'nearest', 'backfill'或'ffill'。
df.iloc[df.index.get_loc(datetime.datetime(2016,2,2),method='nearest')]

1
我无法编辑(太短了,很奇怪!),但是有一个小错误:标题零不允许作为datetime.datetime构造函数的参数:它会导致“无效令牌”错误。 - user3017048
我进行了测试:在我的机器上,iloc 方法比 (~446µs vs. ~588µs) 快大约 25%。 - user3017048
3
我认为使用“向后填充”(backfill)而不是“最近邻”(nearest)更加直观。因为它字面上告诉你,如果没有完全匹配,它将选择下一个索引。 - Brian
这可能应该成为被接受的答案。 - Charly Empereur-mot

9

这段代码返回给定日期之前最近的日期:

def nearest(items, pivot):
    return min([i for i in items if i <= pivot], key=lambda x: abs(x - pivot))

1
这个答案基于Tamas Hegedus的回答。 - Chiel
我会将 < 运算符更改为 <=。 - binarymason

6

我提供了一种解决方案来查找最接近索引而非值的方法。

def nearest_ind(items, pivot):
    time_diff = np.abs([date - pivot for date in items])
    return time_diff.argmin(0)

3
为了找到最接近的日期并返回时间差(两个日期之间的差异),我进行了以下操作:
def nearest_date(items,pivot):
    nearest=min(items, key=lambda x: abs(x - pivot))
    timedelta = abs(nearest - pivot)
    return nearest, timedelta

当你的应用程序有最小接近度门槛时,这可能非常有用,就像我一样。


2
假设您想回答以下变体问题:"给定一个带有日期时间索引的数据框,如何确定列col的最后一个值,其中“最后一个”被定义为小于某个值 date 的最后一个索引"。

def last(df, date, col):
    return df.loc[                      # access the dataframe using this index
        max(                            # latest date
            df[df.index < date].index   # that precedes `date`
        )
    ][col]                              # access column `col`

2
我知道这是一个旧答案,但我刚刚使用了Tamas发布的代码,并发现它花费了很长时间 - 我进行了优化并看到了更快的性能;问题在于迭代需要很长时间,这是我的新方法 - 只有当实际的中心出现在列表中时才会更快。
def nearest(items, pivot):
    if pivot in items:
    return pivot
else:
    return min(items, key=lambda x: abs(x - pivot))

希望这能帮到任何遇到这个问题的人。

嗨,这很有用。如果我想要检查数据框中的整个列,我该如何编写函数? - SModi

1
使用numpy的速度比循环/lambda方法快大约2倍。下面的all_dates是一个numpy日期数组。
abs_deltas_from_target_date = np.absolute(all_dates - target_date_raw)
index_of_min_delta_from_target_date = np.argmin(abs_deltas_from_target_date)
closest_date = all_dates[index_of_min_delta_from_target_date]

1
def nearestDate(base, dates):
    nearness = { abs(base.timestamp() - date.timestamp()) : date for date in dates }
    return nearness[min(nearness.keys())]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接