【问题标题】:Creating pandas DatetimeIndex in Dataframe from DST aware datetime objects从 DST 感知日期时间对象在 Dataframe 中创建 pandas DatetimeIndex
【发布时间】:2020-08-19 21:57:54
【问题描述】:

我从一个在线 API 收集了一系列数据点,每个数据点都有一个值和一个 ISO 时间戳。不幸的是,我需要遍历它们,所以我将它们存储在一个临时的 dict 中,然后从中创建一个 pandas 数据框并将索引设置为时间戳列(简化示例):

from datetime import datetime
import pandas


input_data = [
    '2019-09-16T06:44:01+02:00',
    '2019-11-11T09:13:01+01:00',
]

data = []
for timestamp in input_data:
    _date = datetime.fromisoformat(timestamp)

    data.append({'time': _date})

pd_data = pandas.DataFrame(data).set_index('time')

只要所有时间戳都在同一个时区 并且 DST/非 DST 一切正常,我得到一个带有 DatetimeIndex 的 Dataframe,我可以稍后再处理。 但是,一旦两个不同的时间偏移出现在一个数据集中(上例),我的数据框中只会得到一个Index,它不支持任何基于时间的方法。

有什么方法可以让 pandas 接受时区感知、不同日期作为索引?

【问题讨论】:

    标签: python pandas datetime datetimeindex


    【解决方案1】:
    • pandas datetime 列也要求偏移量相同。具有不同偏移量的列将不会转换为 datetime dtype。
    • 我建议,在 pandas 中之前不要将数据转换为日期时间
    • 分隔时间偏移,并将其视为timedelta
    • to_timedelta 需要'hh:mm:ss' 的格式,所以将':00' 添加到偏移量的末尾
    • 请参阅 Pandas: Time deltas 了解所有可用的 timedelta 操作
    • pandas.Series.dt.tz_convert
    • pandas.Series.tz_localize
    • 使用以下命令转换为特定的 TZ:
      • 如果日期时间不是datetime64[ns, UTC] dtype,则在.dt.tz_convert('US/Pacific') 之前先使用.dt.tz_localize('UTC')
      • 否则df.datetime_utc.dt.tz_convert('US/Pacific')
    import pandas as pd
    
    # sample data
    input_data = ['2019-09-16T06:44:01+02:00', '2019-11-11T09:13:01+01:00']
    
    # dataframe
    df = pd.DataFrame(input_data, columns=['datetime'])
    
    # separate the offset from the datetime and convert it to a timedelta
    df['offset'] = pd.to_timedelta(df.datetime.str[-6:] + ':00')
    
    # if desired, create a str with the separated datetime
    # converting this to a datetime will lead to AmbiguousTimeError because of overlapping datetimes at 2AM, per the OP
    df['datetime_str'] = df.datetime.str[:-6]
    
    # convert the datetime column to a datetime format without the offset
    df['datetime_utc'] = pd.to_datetime(df.datetime, utc=True)
    
    # display(df)
                        datetime          offset        datetime_str              datetime_utc
    0  2019-09-16T06:44:01+02:00 0 days 02:00:00 2019-09-16 06:44:01 2019-09-16 04:44:01+00:00
    1  2019-11-11T09:13:01+01:00 0 days 01:00:00 2019-11-11 09:13:01 2019-11-11 08:13:01+00:00
    
    print(df.info())
    [out]:
    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 2 entries, 0 to 1
    Data columns (total 4 columns):
     #   Column        Non-Null Count  Dtype              
    ---  ------        --------------  -----              
     0   datetime      2 non-null      object             
     1   offset        2 non-null      timedelta64[ns]    
     2   datetime_str  2 non-null      object             
     3   datetime_utc  2 non-null      datetime64[ns, UTC]
    dtypes: datetime64[ns, UTC](1), object(2), timedelta64[ns](1)
    memory usage: 192.0+ bytes
    
    # convert to local timezone
    df.datetime_utc.dt.tz_convert('US/Pacific')
    
    [out]:
    0   2019-09-15 21:44:01-07:00
    1   2019-11-11 00:13:01-08:00
    Name: datetime_utc, dtype: datetime64[ns, US/Pacific]
    

    其他资源

    【讨论】:

    • @Timm 我已经更新了答案以反映更多信息。
    【解决方案2】:

    对问题的措辞稍作更正(我认为这很重要)。您所拥有的是 UTC 偏移量 - DST/no-DST 将需要 更多 信息,即时区。在这里,这很重要,因为您可以轻松地将带有 UTC 偏移量(甚至不同的时间戳)的时间戳解析为 UTC:

    import pandas as pd
    
    input_data = [
        '2019-09-16T06:44:01+02:00',
        '2019-11-11T09:13:01+01:00',
    ]
    
    dti = pd.to_datetime(input_data, utc=True)
    # dti
    # DatetimeIndex(['2019-09-16 04:44:01+00:00', '2019-11-11 08:13:01+00:00'], dtype='datetime64[ns, UTC]', freq=None)
    

    我一直更喜欢使用 UTC,所以我可以接受。但是,如果您确实需要某个时区的日期时间,则可以转换例如作为

    dti = dti.tz_convert('Europe/Berlin')
    # dti
    # DatetimeIndex(['2019-09-16 06:44:01+02:00', '2019-11-11 09:13:01+01:00'], dtype='datetime64[ns, Europe/Berlin]', freq=None)
    

    【讨论】:

    • 您的更正绝对正确且重要。但是,您的回答会忘记原始时区的所有信息,这在示例中是可以的,但是一旦您合并来自多个来源的数据,我希望将其存储在某个地方。
    • @Timm:不过,如果您知道时区,为什么还要忍受将偏移量存储在某个地方的痛苦?反之亦然,如果你只知道 UTC 偏移量,你就无法明确地推断出特定的时区,那么为什么要关心呢? ;-)
    • 当我保持原始时间的偏移量时,当 UTC 偏移量发生变化时,我无法创建 DatetimeIndex。当我删除它时,合并来自不同来源的数据可能/将导致它被 sunrise/-set 对齐,或者我移动到 UTC 并按时间对齐。如果我需要其他表示,这两种方法都可能需要一些额外的手动步骤,并且要求我随时准备好这些信息。我可能过度设计了这个。但是我非常害怕编码中的日期时间数据,它总是让某处失败。
    • @Timm:“它总是让某处失败。”——尤其是在 Python 中,存在一些陷阱。由于我不知道您工作的任何细节,因此我对此的想法很笼统,请不要误会我的意思。根据我的经验,我只能说最好将所有内容都保留在内部的 UTC 中。这避免了许多转换错误。如果您希望人类阅读它,请仅转换为某个本地时间,例如对于演示文稿,在网页上显示或类似的东西。
    • 我同意,这就是我现在正在做的事情。我将您的建议与 utc=True 一起使用,以 UTC 执行所有操作,但存储偏移量以允许恢复人性化、基于时区的输出。
    【解决方案3】:

    我不知道使用时区感知日期时间作为索引并在 pandas 中获取日期时间索引的方法。不过,我确实有一个建议可能会有所帮助,具体取决于您对数据的要求。

    将日期时间对象转换为同一时区是否可以接受,或者时区信息是否必须保留?如果您确实需要时区但不一定需要索引,则在循环访问日期时,您可以使用旧时区存储新列,或者在新列中保留时区原始时间的副本,以便仍然可以访问它。

    【讨论】:

      猜你喜欢
      • 2016-11-04
      • 1970-01-01
      • 2011-10-27
      • 2014-06-05
      • 1970-01-01
      • 2016-08-06
      • 2020-10-15
      • 1970-01-01
      相关资源
      最近更新 更多