【问题标题】:Can pandas.DatetimeIndex remember whether it is closed?pandas.DatetimeIndex 能否记住是否关闭?
【发布时间】:2018-10-09 13:05:51
【问题描述】:

我有一个pandas.DatetimeIndex['2018-01-01', '2018-01-04')(包括开始,结束排除)和freq=1D

>>> 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')

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

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

【问题讨论】:

  • 为什么不用max(index)
  • 因为它会返回 index[-1] 而不是结束参数。
  • @AnnaIliukovich-Strakovskaia max(index) 返回 '2018-01-03' 就像 index[-1]。我想要'2018-01-04',因为这是我在构造函数中的end
  • 创建索引时为什么不直接保存?
  • @user3483203 我可以创建一个具有start/end/freq 属性的虚拟对象,然后传递它并仅在需要时动态创建DatetimeIndex。如果此DatetimeIndex 已附加到现有DataFrame,则不太实用。我想避免保留太多变量。

标签: python pandas datetime


【解决方案1】:

没有办法,因为这个信息在构造对象之后就丢失了。在创建时,区间展开为结果序列:

pandas/core/indexes/datetimes.py:

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 并保存此信息。注意it's an immutable type, so you need to override __new__ instead of __init__:

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__ -- 然后无需替换引用。

【讨论】:

  • 感谢您的精彩解释。
【解决方案2】:

这样的东西对你有用吗?

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”,如果您甚至不想将其作为单独的输入提供,请对其进行解析。

【讨论】:

  • 不,freq 事先不知道。
猜你喜欢
  • 1970-01-01
  • 2011-10-07
  • 1970-01-01
  • 1970-01-01
  • 2015-12-14
  • 2015-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多