我正在尝试为我的表查找最近的日期时间索引。我使用 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 的评论:
我有几年的每日数据,包括正确的日期(每年四月的第一个星期日)。
尽管这适用于我的 MWE,但我的实际数据集包含缺失的数据,并且可能没有正好是凌晨 2 点的数据。数据的间隔大约为 20-35 分钟,因此最接近的值应该与凌晨 2 点的目标相距不到 15 分钟。
我想在四月的第一个星期日找到最接近凌晨 2 点的日期时间。这是 DataFrame 中的每一年,但我不知道如何做到这一点。
答案 0 :(得分:1)
这有点挑战,只是因为“任何一年的四月的第一个星期日”需要几个步骤来计算。您可以通过几种方式来解决这个问题,但我将首先计算目标日期当年以及下一年中最近的目标日期(因为四月总是在一年的第一部分,所以日期永远不会接近前一年的 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
接下来,我找到每一行年份的四月第一个星期日(凌晨 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
答案 1 :(得分:1)
根据您的评论,您似乎可以依赖于每年在您想要的时间(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]