关于python:pandas.DatetimeIndex可以记住它是否已关闭?

Can pandas.DatetimeIndex remember whether it is closed?

我有一个pandas.DatetimeIndex,用于间隔['2018-01-01', '2018-01-04')(包括开始,不包括结束)和freq=1D

1
2
3
4
5
6
7
>>> index = pd.DatetimeIndex(start='2018-01-01',
                             end='2018-01-04',
                             freq='1D',
                             closed='left')
DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03'],
              dtype='datetime64[ns]',
              freq='D')

如何再次获得正确的open end='2018-01-04'属性?我需要它用于具有时间戳范围的数据库查询。

  • 没有index.end
  • index[-1]返回'2018-01-03'
  • 在这种情况下,index[-1] + index.freq起作用,但对freq='2D'起作用是错误的。

  • 这是不可能的,因为在构造对象之后,这些信息会丢失。在创建时,间隔将展开为结果序列:

    pandas/core/indexes/datetimes.py号:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    class DatetimeIndex(<...>):

        <...>

        @classmethod
        def _generate(cls, start, end, periods, name, freq,
                      tz=None, normalize=False, ambiguous='raise', closed=None):
            <...>

                    index = tools.to_datetime(np.linspace(start.value,
                                                          end.value, periods),
                                              utc=True)
                    <...>

            if not left_closed and len(index) and index[0] == start:
                index = index[1:]
            if not right_closed and len(index) and index[-1] == end:
                index = index[:-1]
            index = cls._simple_new(index, name=name, freq=freq, tz=tz)
            return index

    closed信息也不会保存在任何地方,因此您甚至无法从第一个/最后一个点和步骤中推断出来。

    您可以将DatetimeIndex子类化并保存此信息。请注意,它是不可变的类型,因此需要重写__new__,而不是__init__

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    import inspect, collections
    class SiDatetimeIndex(pd.DatetimeIndex):

        _Interval = collections.namedtuple('Interval',
                ('start','end','freq','closed'))
        #add 'interval' to dir(): DatetimeIndex inherits pandas.core.accessor.DirNamesMixin
        _accessors = pd.DatetimeIndex._accessors | frozenset(('interval',))

        def __new__(cls, *args, **kwargs):
            base_new = super(SiDatetimeIndex,cls).__new__
            callargs = inspect.getcallargs(base_new,cls,*args,**kwargs)
            result = base_new(**callargs)
            result.interval = cls._Interval._make(callargs[a] for a in cls._Interval._fields)
            return result


    In [31]: index = SiDatetimeIndex(start='2018-01-01',
    ...:                              end='2018-01-04',
    ...:                              freq='1D',
    ...:                              closed='left')

    In [38]: index.interval
    Out[38]: Interval(start='2018-01-01', end='2018-01-04', freq='1D', closed='left')

    不要期望所有的pandas方法(包括类中继承的方法)现在可以神奇地开始创建被重写的类。为此,您需要替换那些方法使用的已加载pandas模块中对基类的实时引用。或者,您可以只替换原始的__new__,然后不需要替换引用。


    这种东西对你有用吗?

    1
    2
    3
    4
    5
    6
    7
    index = pd.DatetimeIndex(start='2018-01-01', end='2018-01-04',  freq='1D', closed='left')

    def get_end(index, freq):
        if freq == '1D':
            return(index.max()+1)

    get_end(index, '1D')

    您可以为1d/2d/1M编写逻辑。此外,还可以将带有freq参数的dateindex的列名作为后缀/前缀'purchase_date_1d',如果您甚至不想将其作为单独的输入进行分析。