【问题标题】:Pandas find nearest datetime index with conditional argumentsPandas 使用条件参数查找最近的日期时间索引
【发布时间】:2021-08-05 06:26:51
【问题描述】:

我正在尝试查找我的表中最近的日期时间索引。我使用this post 作为起点,并且正在使用这个 MWE:

import os
import numpy as np
import pandas as pd
from datetime import datetime, date, timedelta

df = pd.DataFrame() 
df['datetime'] = pd.date_range(start='2019-01-01', end='2021-01-01', freq='H')
df = df.set_index('datetime')

df['year'] = pd.DatetimeIndex(df.index).year
df['mnth'] = pd.DatetimeIndex(df.index).month
df['day'] = pd.DatetimeIndex(df.index).day
df['dow'] = pd.DatetimeIndex(df.index).dayofweek # Mon=0, ..., Sun=6
df['hour'] = pd.DatetimeIndex(df.index).hour

years = df.year.unique()

idxlist = []

for y in years:
    idx1 = df.loc[((df.year==y) & (df.mnth==4) & (df.day<=7) & (df.dow==6) & (df.hour==2))]
    #idx1 = df.iloc[df.get_loc(((df.year==y) & (df.mnth==4) & (df.day<=7) & (df.dow==6) & (df.hour==2)), method='nearest')]
    idxlist.append(idx1)

编辑基于 Michael Delgado cmets:

我有几年的日常数据,包括正确的日子(每年四月的第一个星期日)。

尽管这适用于我的 MWE,但我的实际数据集包含缺失的数据,并且可能没有恰好凌晨 2 点的数据。数据的间隔大约为 20-35 分钟,因此最接近的值应该距离凌晨 2 点的目标不到 15 分钟。

我想找到最接近 4 月第一个星期日凌晨 2 点的日期时间。这是 DataFrame 中的每一年,但我不知道该怎么做。

【问题讨论】:

  • 我建议创建一个列,从正常时间戳中减去凌晨 2 点的时间戳,按绝对值排序,取最大值
  • 您想要在任何一年的四月的第一个星期日最接近凌晨 2 点的日期吗?还是只是 2020 年 4 月 5 日?
  • @迈克尔·德尔加多。每年都在df,谢谢
  • 知道了。因此,我们应该忽略示例中将年份设置为max(df.year) 的部分?如果是这样,您能否在问题中进一步阐明您的目标?
  • 数据是否总是有正确日期的观测值,只是可能不正好是凌晨 2 点?或者最接近的值可能是+/-几天?还是几个月?

标签: python pandas dataframe datetime


【解决方案1】:

根据您的 cmets,您似乎可以依靠在每年所需时间(4 月的第一个星期日)的一个小时内获得数据。在这种情况下,您可以采取更简单的方法。

使用具有时代变化的示例数据集:

In [4]: df = pd.DataFrame(
   ...:     ...:     {'val': np.arange(24*366*10)},
   ...:     ...:     index=(
   ...:     ...:         pd.date_range('2010-01-01', periods=24*366*10, freq='H')
   ...:     ...:         + pd.to_timedelta(np.random.randint(-30, 30, size=(24*366*10)), unit='minutes')
   ...:     ...:     ),
   ...:     ...: )

In [5]: df
Out[5]:
                       val
2010-01-01 00:14:00      0
2010-01-01 01:20:00      1
2010-01-01 01:46:00      2
2010-01-01 03:20:00      3
2010-01-01 03:51:00      4
...                    ...
2020-01-08 18:48:00  87835
2020-01-08 19:46:00  87836
2020-01-08 21:07:00  87837
2020-01-08 22:06:00  87838
2020-01-08 23:11:00  87839

[87840 rows x 1 columns]

我们可以根据四舍五入到最接近 2 小时的时间进行过滤:

within_an_hour = df[
    (df.index.month==4)
    & (df.index.day<=7)
    & (df.index.day_of_week == 6)
    & (df.index.round('2H').hour == 2)
]

然后我们可以通过取每年 2 小时舍入值的最小绝对差值来选择最接近的指数:

In [15]: closest_indices = (
    ...:     within_an_hour
    ...:     .groupby(within_an_hour.index.year)
    ...:     .apply(
    ...:         lambda x: x.index.values[np.argmin(abs(x.index - x.index.round('2H')))]
    ...:     )
    ...: )

In [16]: closest_indices
Out[16]:
2010   2010-04-04 02:17:00
2011   2011-04-03 02:22:00
2012   2012-04-01 01:49:00
2013   2013-04-07 01:39:00
2014   2014-04-06 02:01:00
2015   2015-04-05 01:58:00
2016   2016-04-03 02:12:00
2017   2017-04-02 01:54:00
2018   2018-04-01 02:22:00
2019   2019-04-07 02:13:00
dtype: datetime64[ns]

【讨论】:

    【解决方案2】:

    这有点挑战,因为“每年四月的第一个星期日”需要几个步骤来计算。您可以通过几种方式来解决这个问题,但我将通过首先计算目标日期当年以及下一年中最近的目标日期来解决这个问题(因为四月总是在一年的上半年,所以日期永远不会更接近前一年的 4 月),然后找到与任一目标的最小绝对差值。

    第一步,我将通过一些随机偏移(+/- 30 分钟)和更长的时间序列来扩展您的 MWE。我还添加了一个值列,以便 df 显示为一个框架:

    In [26]: df = pd.DataFrame(
        ...:     {'val': np.arange(24*366*10)},
        ...:     index=(
        ...:         pd.date_range('2010-01-01', periods=24*366*10, freq='H')
        ...:         + pd.to_timedelta(np.random.randint(-30, 30, size=(24*366*10)), unit='minutes')
        ...:     ),
        ...: )
    
    In [27]: df
    Out[27]:
                           val
    2010-01-01 00:29:00      0
    2010-01-01 01:09:00      1
    2010-01-01 01:43:00      2
    2010-01-01 03:14:00      3
    2010-01-01 03:54:00      4
    ...                    ...
    2020-01-08 18:31:00  87835
    2020-01-08 20:21:00  87836
    2020-01-08 20:54:00  87837
    2020-01-08 21:47:00  87838
    2020-01-08 23:11:00  87839
    

    接下来,我找到每一行年份的 4 月第一个星期日(凌晨 2 点)的日期:

    In [28]: apr1 = pd.to_datetime({'year': df.index.year, 'month': 4, 'day': 1, 'hour': 2})
    
    In [29]: apr_first_sun = apr1 + pd.to_timedelta(6 - apr1.dt.weekday, unit='day')
    
    In [30]: apr_first_sun
    Out[30]:
    0       2010-04-04 02:00:00
    1       2010-04-04 02:00:00
    2       2010-04-04 02:00:00
    3       2010-04-04 02:00:00
    4       2010-04-04 02:00:00
                    ...
    87835   2020-04-05 02:00:00
    87836   2020-04-05 02:00:00
    87837   2020-04-05 02:00:00
    87838   2020-04-05 02:00:00
    87839   2020-04-05 02:00:00
    Length: 87840, dtype: datetime64[ns]
    
    In [31]: apr1 = pd.to_datetime({'year': df.index.year + 1, 'month': 4, 'day': 1, 'hour': 2})
    
    In [32]: next_apr_first_sun = apr1 + pd.to_timedelta(6 - apr1.dt.weekday, unit='day')
    

    接下来,找到更接近的绝对差:

    In [36]: nearer_abs_diff = np.minimum(abs(df.index - apr_first_sun.values), abs(df.index - next_apr_first_sun.values))
    
    In [37]: nearer_abs_diff
    Out[37]:
    TimedeltaIndex(['93 days 01:31:00', '93 days 00:51:00', '93 days 00:17:00',
                    '92 days 22:46:00', '92 days 22:06:00', '92 days 20:54:00',
                    '92 days 20:23:00', '92 days 19:25:00', '92 days 18:12:00',
                    '92 days 16:48:00',
                    ...
                    '87 days 12:19:00', '87 days 11:12:00', '87 days 09:36:00',
                    '87 days 08:31:00', '87 days 07:36:00', '87 days 07:29:00',
                    '87 days 05:39:00', '87 days 05:06:00', '87 days 04:13:00',
                    '87 days 02:49:00'],
                   dtype='timedelta64[ns]', length=87840, freq=None
    

    最后,找到最小绝对差的位置索引,并用它来索引数据框:

    In [38]: idx = np.argmin(nearer_abs_diff)
    
    In [39]: df.iloc[idx]
    Out[39]:
    val    37346
    Name: 2014-04-06 02:14:00, dtype: int64
    

    【讨论】:

    • 感谢您的详细回答……不过,找到 4 月的第一个星期日并不难 - 它总是在 4 月 1 日至 7 日之间(因此我写了df.day&lt;=7)。那么有没有办法简化你的代码呢?
    • 我正在查找每年四月第一个星期日的确切时间戳,然后计算相对于该值的差异。所以我需要计算它是什么时候,而不仅仅是过滤匹配的值。
    • 我不确定我是否理解您的回答。 df.iloc[idx] 返回一个值,但我希望它给出第一年和去年之间每年四月的索引。
    • 哦!我以为您想要的是所有年份中最接近任何价值的那个。在这种情况下,您可以按年份分组并找到每年的 argmin。
    猜你喜欢
    • 2021-03-30
    • 1970-01-01
    • 2023-02-07
    • 2019-01-05
    • 1970-01-01
    • 2018-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多