pandas to_datetime解析错误的一年

时间:2016-06-11 17:02:37

标签: python datetime pandas

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

基本上,我将一系列日期作为"%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条目。这里发生了什么?

5 个答案:

答案 0 :(得分:10)

这似乎是Python库日期时间的行为,我做了一个测试,看看截止点是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两位数字只能从00变为99,如果我们开始跨越几个世纪,这将是不明确的。

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

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

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

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

答案 1 :(得分:4)

对于那些寻找快速而脏的代码片段来修复这些案例的人来说,这对我有用:

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)

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

答案 2 :(得分:3)

来自docs

  

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

答案 3 :(得分:1)

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

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)

希望这会有所帮助。

答案 4 :(得分: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

从对象将输出转换为熊猫日期时间格式
    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

如其他一些答案所述,如果两个世纪的日期之间没有重叠,则效果最好。