【问题标题】:Create pandas DatetimeIndex without leap day创建没有闰日的熊猫 DatetimeIndex
【发布时间】:2021-07-09 21:46:06
【问题描述】:

我想创建一个 pandas DatetimeIndex,其中包含不同年份的闰日前后的一系列日期。有些年份是闰年,有些年份不是。不过需要注意的是,我希望所有这些日期列表的长度相同。让我们看一些例子。

import pandas as pd
from datetime import timedelta

leap=pd.date_range('2020-02-27-12',pd.to_datetime('2020-02-27-12')+dt.timedelta(days=2),freq='6H')

DatetimeIndex(['2020-02-27 12:00:00', '2020-02-27 18:00:00',
               '2020-02-28 00:00:00', '2020-02-28 06:00:00',
               '2020-02-28 12:00:00', '2020-02-28 18:00:00',
               '2020-02-29 00:00:00', '2020-02-29 06:00:00',
               '2020-02-29 12:00:00'],
              dtype='datetime64[ns]', freq='6H')
len(leap)
9

避免采用这种格式的闰日的最常见方法之一是简单地将它们从列表中删除。

leap=leap[(leap.day != 29) | (leap.month != 2)]
len(leap)
6

如果我只想删除闰日而不关心列表的具体长度,这可以正常工作。

让我们在非闰年做同样的练习。

leap=pd.date_range('2021-02-27-12',pd.to_datetime('2021-02-27-12')+dt.timedelta(days=2),freq='6H')

DatetimeIndex(['2021-02-27 12:00:00', '2021-02-27 18:00:00',
               '2021-02-28 00:00:00', '2021-02-28 06:00:00',
               '2021-02-28 12:00:00', '2021-02-28 18:00:00',
               '2021-03-01 00:00:00', '2021-03-01 06:00:00',
               '2021-03-01 12:00:00'],
              dtype='datetime64[ns]', freq='6H')

len(leap)
9

当然,前两个长度相同。但是,当我们从第一个列表中删除闰日时,我们现在可以看到长度不同,如 6 =/ 9。

这导致了一个终极问题:如何创建一个 pandas 日期范围,它会采用第一个列表并跳过闰日并直接进入 3 月,同时保持列表的长度为 9?


就上下文而言,我正在使用居中日期方法对地理空间 (3D) 数据进行索引。例如,如果我想查看 1 月 5 日全球某个时间点的数据,我会分析 1 月 5 日(1 月 3 日至 7 日)前后 2 天的数据。在很长一段时间(> 30 年)内采用这种方法,我对我正在分析的变量有了更好的气候学认识。为了做这个索引,我循环日期并使用上面描述的 pandas 日期范围方法。这是我用来解决地理空间 (3D) 数据索引问题的循环:

times=pd.date_range('1979-09-01','1980-04-30-18', freq='6H')
final_times = times[(times.day != 29) | (times.month != 2)]
years=np.arange(1979,2020,1)
for i in final_times:
    print(i)

    times_list=[]

    for j in years:
        times_forward=pd.date_range(i.replace(year=j),i.replace(year=j)+dt.timedelta(days=2), freq='6H')
        times_back=pd.date_range(i.replace(year=j)-dt.timedelta(days=2),i.replace(year=j)-dt.timedelta(hours=6), freq='6H')
        total_times=times_forward.union(times_back)
        times_list.append(total_times)
    combined_times=pd.DatetimeIndex([item for sublist in times_list for item in sublist]).sort_values()

按原样运行此代码时,闰日周围的日期列表比闰日附近的日期列表长度短。

【问题讨论】:

    标签: python pandas datetime


    【解决方案1】:

    如果您只使用 DateOffset 对象,那么问题已经为您解决了:

    >>> pd.date_range('2021-02-27-12', periods=9, freq='6H')
    DatetimeIndex(['2021-02-27 12:00:00', '2021-02-27 18:00:00',
                   '2021-02-28 00:00:00', '2021-02-28 06:00:00',
                   '2021-02-28 12:00:00', '2021-02-28 18:00:00',
                   '2021-03-01 00:00:00', '2021-03-01 06:00:00',
                   '2021-03-01 12:00:00'],
                  dtype='datetime64[ns]', freq='6H')
    >>> pd.date_range('2021-02-27-12', periods=9, freq='6H') - pd.DateOffset(years=1)
    DatetimeIndex(['2020-02-27 12:00:00', '2020-02-27 18:00:00',
                   '2020-02-28 00:00:00', '2020-02-28 06:00:00',
                   '2020-02-28 12:00:00', '2020-02-28 18:00:00',
                   '2020-03-01 00:00:00', '2020-03-01 06:00:00',
                   '2020-03-01 12:00:00'],
                  dtype='datetime64[ns]', freq=None)
    

    只要您参考的年份不是闰年,这就是您想要的。请注意,如果您以闰年为基础,您将有两次相同的日期,即您会将 28 日和 29 日与上一年或明年的 28 日进行比较:

    >>> pd.date_range('2020-02-27-12', periods=9, freq='6H')
    DatetimeIndex(['2020-02-27 12:00:00', '2020-02-27 18:00:00',
                   '2020-02-28 00:00:00', '2020-02-28 06:00:00',
                   '2020-02-28 12:00:00', '2020-02-28 18:00:00',
                   '2020-02-29 00:00:00', '2020-02-29 06:00:00',
                   '2020-02-29 12:00:00'],
                  dtype='datetime64[ns]', freq='6H')
    >>> pd.date_range('2020-02-27-12', periods=9, freq='6H') + pd.DateOffset(years=1)
    DatetimeIndex(['2021-02-27 12:00:00', '2021-02-27 18:00:00',
                   '2021-02-28 00:00:00', '2021-02-28 06:00:00',
                   '2021-02-28 12:00:00', '2021-02-28 18:00:00',
                   '2021-02-28 00:00:00', '2021-02-28 06:00:00',
                   '2021-02-28 12:00:00'],
                  dtype='datetime64[ns]', freq=None)
    

    我不确定这是否有问题 - 索引包含重复的项目,但这是我认为的唯一缺点。

    基于此,这里有一个函数,它为给定日期提供每年日期的索引(在范围内)以进行比较:

    def compare_times(datetime, periods=9, freq='6H', years=np.arange(1979, 2021)):
        ref_index = pd.DatetimeIndex([
            *pd.date_range(datetime, periods=1 + periods // 2, freq=f'-{freq}')[::-1],
            *pd.date_range(datetime, periods=1 + periods // 2, freq=freq)[1:]
        ])
        return pd.DatetimeIndex(np.concatenate([ref_index + pd.DateOffset(years=y -datetime.year) for y in years]))
    

    现在没有问题了,只要您不使用 2 月 29 日调用该函数。如果这样做,非闰年将返回相同数量的项目,但 2 月 28 日的条目重复:

    >>> compare_times(pd.Timestamp(2020, 2, 29))
    DatetimeIndex(['1979-02-28 00:00:00', '1979-02-28 06:00:00',
                   '1979-02-28 12:00:00', '1979-02-28 18:00:00',
                   '1979-02-28 00:00:00', '1979-02-28 06:00:00',
                   '1979-02-28 12:00:00', '1979-02-28 18:00:00',
                   '1979-03-01 00:00:00', '1980-02-28 00:00:00',
                   ...
                   '2019-03-01 00:00:00', '2020-02-28 00:00:00',
                   '2020-02-28 06:00:00', '2020-02-28 12:00:00',
                   '2020-02-28 18:00:00', '2020-02-29 00:00:00',
                   '2020-02-29 06:00:00', '2020-02-29 12:00:00',
                   '2020-02-29 18:00:00', '2020-03-01 00:00:00'],
                  dtype='datetime64[ns]', length=378, freq=None)
    

    在这里您可以看到 1979 年的复制品。

    【讨论】:

    • 这就是我想要的,谢谢。
    猜你喜欢
    • 2019-01-06
    • 2016-10-05
    • 2015-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-27
    • 2020-07-21
    • 2016-03-16
    相关资源
    最近更新 更多