【问题标题】:pandas to_datetime parsing wrong year熊猫 to_datetime 解析错误的年份
【发布时间】:2016-10-12 11:46:48
【问题描述】:

我遇到了一些几乎可以肯定是我的愚蠢错误,但我似乎无法弄清楚发生了什么。

基本上,我有一系列日期为格式为"%d-%b-%y" 的字符串,例如26-Sep-05。当我将它们转换为日期时间时,年份有时是正确的,但有时不是。

例如:

dates = ['26-Sep-05', '26-Sep-05', '15-Jun-70', '5-Dec-94', '9-Jan-61', '8-Feb-55']

pd.to_datetime(dates, format="%d-%b-%y")
DatetimeIndex(['2005-09-26', '2005-09-26', '1970-06-15', '1994-12-05',
               '2061-01-09', '2055-02-08'],
              dtype='datetime64[ns]', freq=None)

最后两个条目(年份分别返回 2061 和 2055)是错误的。但这适用于 15-Jun-70 条目。这是怎么回事?

【问题讨论】:

  • 你的日期不明确,所以 Python 不知道是 1965 年还是 2065 年。你确定以后不会有任何日期吗?
  • 70 与 65 一样模棱两可——问题的部分原因在于为什么在一种情况下做出了一种选择,而不是在另一种情况下做出了选择

标签: python datetime pandas


【解决方案1】:

另一个快速解决问题的方法:-

import pandas as pd
import numpy as np
dates = pd.DataFrame(['26-Sep-05', '26-Sep-05', '15-Jun-70', '5-Dec-94', '9-Jan-61', '8-Feb-55'])

for i in dates:
    tempyear=pd.to_numeric(dates[i].str[-2:])
    dates["temp_year"]=np.where((tempyear>=44)&(tempyear<=99),tempyear+1900,tempyear+2000).astype(str)
    dates["temp_month"]=dates[i].str[:-2]
    dates["temp_flyr"]=dates["temp_month"]+dates["temp_year"]
    dates["pddt"]=pd.to_datetime(dates.temp_flyr.str.upper(), format='%d-%b-%Y', yearfirst=False)
    tempdrops=["temp_year","temp_month","temp_flyr",i]
    dates.drop(tempdrops, axis=1, inplace=True)

输出如下,这里我使用pd.to_datetime

将输出从对象转换为pandas日期时间格式
    pddt
0   2005-09-26
1   2005-09-26
2   1970-06-15
3   1994-12-05
4   1961-01-09
5   1955-02-08

正如在其他一些答案中提到的,如果两个世纪的日期之间没有重叠,这种方法效果最好。

【讨论】:

    【解决方案2】:

    您可以编写一个简单的函数来纠正这种错误年份的解析,如下所述:

    import datetime
    
    def fix_date(x):
    
        if x.year > 1989:
    
            year = x.year - 100
    
        else:
    
            year = x.year
    
        return datetime.date(year,x.month,x.day)
    
    
    df['date_column'] = data['date_column'].apply(fix_date)
    

    希望这会有所帮助..

    【讨论】:

      【解决方案3】:

      对于任何寻求快速而肮脏的代码 sn-p 来解决这些情况的人,这对我有用:

      from datetime import timedelta, date
      col = 'date'
      df[col] = pd.to_datetime(df[col])
      future = df[col] > date(year=2050,month=1,day=1)
      df.loc[future, col] -= timedelta(days=365.25*100)
      

      您可能需要根据数据中最早的日期将阈值日期调整为更接近现在。

      【讨论】:

        【解决方案4】:

        来自docs

        2000 年 (Y2K) 问题: Python 依赖于平台的 C 库, 通常没有 2000 年的问题,因为所有日期和 时间在内部表示为自纪元以来的秒数。功能 当给定 %y 格式代码时,strptime() 可以解析 2 位数的年份。什么时候 解析 2 位数的年份,它们根据 POSIX 进行转换 和 ISO C 标准:值 69–99 映射到 1969–1999,值 0–68 映射到 2000–2068

        【讨论】:

          【解决方案5】:

          这似乎是 Python 库 datetime 的行为,我做了一个测试,看看截止点在哪里 68 - 69:

          datetime.datetime.strptime('31-Dec-68', '%d-%b-%y').date()
          >>> datetime.date(2068, 12, 31)
          
          datetime.datetime.strptime('1-Jan-69', '%d-%b-%y').date()
          >>> datetime.date(1969, 1, 1)
          

          两位数年份模糊度

          因此,似乎 %y 年低于 69 的任何事物都将被归为 2000 年,而 69 年以上则为 1900

          %y 两位数只能从 0099,如果我们开始跨越几个世纪,这将是模棱两可的。

          如果没有重叠,你可以手动处理并标注世纪(消除歧义)

          我建议您手动处理数据并指定世纪,例如您可以决定将数据中年份介于 17 和 68 之间的任何内容归因于 1917 - 1968(而不是 2017 - 2068)。

          如果您有重叠,那么您无法处理年份信息不足的情况,除非例如你有一些有序的数据和参考

          如果您有重叠,例如您有 2016 年和 1916 年的数据,并且都记录为“16”,这是不明确的,没有足够的信息来解析它,除非数据按日期排序,在这种情况下,您可以使用启发式方法来切换世纪解析它。

          【讨论】:

          • 这就是我认为正在发生的事情。你对为什么截止点在哪里有任何见解吗?我在想这可能与 Unix 时间开始时有关,但由于 69 有效,所以不是这样。
          猜你喜欢
          • 2019-09-05
          • 1970-01-01
          • 2018-06-05
          • 1970-01-01
          • 1970-01-01
          • 2015-10-26
          • 2022-01-12
          • 2018-11-12
          相关资源
          最近更新 更多