【问题标题】:Clean way to convert quarterly periods to datetime in pandas在熊猫中将季度周期转换为日期时间的干净方法
【发布时间】:2019-05-22 17:37:46
【问题描述】:

编辑:
如果您要回答这个问题并且您的字符串看起来像 1996-Q1,那么只需使用 pd.to_datetime(df['Quarter']) 将其转换为正确的 pandas 日期时间。这个问题是关于解决所有不是这种标准格式的季度日期。

原始问题:
我正在寻找一种很好的、​​可读的和可理解的方式(您下次可以记住的方式)将Q3 1996 转换为熊猫日期时间,例如1996-07-01 在这种情况下。 直到现在我才发现这个,但它非常丑陋:

df = pd.DataFrame({'Quarter':['Q3 1996', 'Q4 1996', 'Q1 1997']})
​
df['date'] = (
    pd.to_datetime(
        df['Quarter'].str.split(' ').apply(lambda x: ''.join(x[::-1]))
))
​
print(df)
   Quarter       date
0  Q3 1996 1996-07-01
1  Q4 1996 1996-10-01
2  Q1 1997 1997-01-01

我希望以下内容可以工作,因为它是可读的,但不幸的是它没有:

df['date'] = pd.to_datetime(df['Quarter'], format='%q %Y')

问题还在于,pandas 进行简单处理时,季度和年份的顺序显然是错误的。

谁能帮我找到一种更简洁的方法将Q3 1996 转换为 pandas 日期时间?

【问题讨论】:

    标签: python pandas date datetime period


    【解决方案1】:

    您可以(并且应该)使用pd.PeriodIndex 作为第一步,然后使用PeriodIndex.to_timestamp 转换为时间戳:

    qs = df['Quarter'].str.replace(r'(Q\d) (\d+)', r'\2-\1')
    qs
    
    0    1996-Q3
    1    1996-Q4
    2    1997-Q1
    Name: Quarter, dtype: object
    
    df['date'] = pd.PeriodIndex(qs, freq='Q').to_timestamp()
    df
    
       Quarter       date
    0  Q3 1996 1996-07-01
    1  Q4 1996 1996-10-01
    2  Q1 1997 1997-01-01
    

    初始替换步骤是必要的,因为PeriodIndex 期望您的句点采用%Y-%q 格式。


    另一种选择是在执行字符串替换后使用pd.to_datetime,方法与之前相同。

    df['date'] = pd.to_datetime(
        df['Quarter'].str.replace(r'(Q\d) (\d+)', r'\2-\1'), errors='coerce')
    df
    
       Quarter       date
    0  Q3 1996 1996-07-01
    1  Q4 1996 1996-10-01
    2  Q1 1997 1997-01-01
    

    如果性能很重要,你可以拆分和加入,但你可以干干净净:

    df['date'] = pd.to_datetime([
        '-'.join(x.split()[::-1]) for x in df['Quarter']])
    
    df
    
       Quarter       date
    0  Q3 1996 1996-07-01
    1  Q4 1996 1996-10-01
    2  Q1 1997 1997-01-01
    

    【讨论】:

    • 两个答案都很棒。为什么 pd.to_datetime() 需要切换年份和季度才能正常工作?
    • @SandervandenOord 我认为这恰好与正在使用的底层日期时间解析器有关(pytz,如果我没记错的话)。但我不确定。我不知道如何为 PeriodIndex 指定格式,但如果可以的话,那就太好了。
    • 如何获得与季度末对应的日期?比如,2018 年第一季度变成了 2018-03-31?
    • @ifly6 有同样的问题,直接输入to_timestamp(how='end')
    • @cs95 第一个解决方案似乎不再起作用:df['date'] = pd.PeriodIndex(qs, freq='Q') 我得到“不正确的 dtype”。使用 pandas 0.25.3 和 pytz 2019.2 你知道为什么这不再起作用了吗?还是我弄错了?
    【解决方案2】:

    给定像2018-Q1 这样的四分之一格式,可以使用内置的pd.to_datetime 函数。作为一般答案,必须处理存储季度观测值的多种方式(例如2018:12018:Q120181Q1:2018 等),将数据强制转换为 supra 超出了我的回答范围。

    但是给定一个格式化的系列:

    formatted_series = formatted_series_supplier() ...
    df['date'] = pd.to_datetime(formatted_series)
    

    例如:

    >>> pd.to_datetime(pd.Series(['2018-Q1']))
    0   2018-01-01
    dtype: datetime64[ns]
    

    如果您正在处理监管数据,它几乎总是反映季度末而不是开始(即,您想要 2019-01-01,而不是 2019-03-31),您可以使用偏移量,例如下面:

    df['date'] = df['date'] + pd.offsets.QuarterEnd(0)
    

    使用上面的示例,删除中间结果,

    >>> pd.to_datetime(pd.Series(['2018-Q1'])) + pd.offsets.QuarterEnd(0)
    0   2018-03-31
    dtype: datetime64[ns]
    

    请注意,如果您希望在结束日期的同一季度内正确索引,则必须将 0 参数提供给 QuarterEnd。否则,你会得到这样的东西:

    >>> pd.to_datetime('2018-03-31') + pd.offsets.QuarterEnd()
    Timestamp('2018-06-30 00:00:00')
    

    【讨论】:

      【解决方案3】:

      使用前 4 个值和第一个 2 进行切片并转换为日期时间:

      df['date'] = pd.to_datetime(df['Quarter'].str[-4:] + df['Quarter'].str[:2])
      

      pandas 中的字符串操作很慢,所以如果不可能有缺失值,请使用 list comprehension:

      #python 3.6+ 
      df['date'] = pd.to_datetime([f'{x[-4:]}{x[:2]}' for x in df['Quarter']])
      #python bellow
      #df['date'] = pd.to_datetime(['{}{}'.format(x[-4:], x[:2]) for x in df['Quarter']])
      print (df)
         Quarter       date
      0  Q3 1996 1996-07-01
      1  Q4 1996 1996-10-01
      2  Q1 1997 1997-01-01
      

      【讨论】:

        猜你喜欢
        • 2015-09-19
        • 2018-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-18
        • 2017-06-05
        • 2018-12-08
        相关资源
        最近更新 更多