为什么 Pandas 拒绝读取 9 个世纪后的日期?
Why Pandas refuse to read a date 9 centuries into the future?
考虑这个例子 df.
import pandas as pd
from io import StringIO
mycsv = StringIO("id,date\n1,11/07/2018\n2,11/07/<b>2918</b>\n3,02/01/2019")
df = pd.read_csv(mycsv)
df
id date
0 1 11/07/2018
1 2 11/07/2918
2 3 02/01/2019
很明显那里有错字(2918 而不是 2018),但我还是想将其解析为日期。
所以让我们检查一下df.dtypes
id int64
date object
dtype: object
好的,默认情况下它被读取为一个字符串。所以我会明确告诉 read_csv
将该列解析为日期。
df = pd.read_csv(mycsv, parse_dates=["date"])
但是df.dtypes
仍然显示日期被读取为字符串(对象数据类型)。
如果我更正错字...
mycsv = StringIO("id,date\n1,11/07/2018\n2,<b>11/07/2018</b>\n3,02/01/2019")
有效
df = pd.read_csv(mycsv, parse_dates=["date"])
df
id date
0 1 2018-11-07
1 2 2018-11-07
2 3 2019-02-01
df.dtypes
id int64
date datetime64[ns]
dtype: object
很明显,它无法解析这样一个不切实际的日期 (11/07/2918),然后整个列都作为字符串处理。
但为什么它不能正确处理 11/07/2918 日期?以及如何让它正确解析这样的日期?
read_csv
文档说默认情况下它使用 dateutil.parser.parse
。当您手动尝试时:
import dateutil
dateutil.parser.parse("13/07/2918")
它很管用。没有异常,没有错误并生成有效的 datetime
对象:datetime.datetime(2918, 7, 13, 0, 0)
也可以将其转换为 numpy.datetime64
有效
import dateutil
toy = dateutil.parser.parse("13/07/2918")
np.datetime64(toy)
它生成一个有效且正确解析的对象。
numpy.datetime64('2918-07-13T00:00:00.000000')
同样,使用 pandas
' strptime
可以正常工作并生成有效的日期时间对象。
pd.datetime.strptime("11/07/2918", "%d/%m/%Y")
现在,尝试使用自定义日期解析器,只是为了确保日期格式正确
mycsv = StringIO("id,date\n1,11/07/2018\n2,11/07/2918\n3,02/01/2019")
df = pd.read_csv(
mycsv,
parse_dates=["date"],
date_parser=lambda x: pd.datetime.strptime(x, "%d/%m/%Y")
)
同样 df["date"].dtype
是 dtype('O')
好的,所以我放弃了说服 read_csv
正确解析日期的尝试。所以我说,让我们把它转换成日期吧。
这一个
df["date"].astype("datetime64")
或这个
pd.to_datetime(df["date"])
抛出和异常
OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 2918-07-11 00:00:00
似乎没有任何效果。
知道为什么会发生这种情况以及如何让它发挥作用吗?
来自文档:
Since pandas represents timestamps in nanosecond resolution, the time span that can
be represented using a 64-bit integer is limited to approximately 584 years:
In [92]: pd.Timestamp.min
Out[92]: Timestamp('1677-09-21 00:12:43.145225')
In [93]: pd.Timestamp.max
Out[93]: Timestamp('2262-04-11 23:47:16.854775807')
如何表示越界时间:
https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#timeseries-oob
考虑这个例子 df.
import pandas as pd
from io import StringIO
mycsv = StringIO("id,date\n1,11/07/2018\n2,11/07/<b>2918</b>\n3,02/01/2019")
df = pd.read_csv(mycsv)
df
id date
0 1 11/07/2018
1 2 11/07/2918
2 3 02/01/2019
很明显那里有错字(2918 而不是 2018),但我还是想将其解析为日期。
所以让我们检查一下df.dtypes
id int64
date object
dtype: object
好的,默认情况下它被读取为一个字符串。所以我会明确告诉 read_csv
将该列解析为日期。
df = pd.read_csv(mycsv, parse_dates=["date"])
但是df.dtypes
仍然显示日期被读取为字符串(对象数据类型)。
如果我更正错字...
mycsv = StringIO("id,date\n1,11/07/2018\n2,<b>11/07/2018</b>\n3,02/01/2019")
有效
df = pd.read_csv(mycsv, parse_dates=["date"])
df
id date
0 1 2018-11-07
1 2 2018-11-07
2 3 2019-02-01
df.dtypes
id int64
date datetime64[ns]
dtype: object
很明显,它无法解析这样一个不切实际的日期 (11/07/2918),然后整个列都作为字符串处理。
但为什么它不能正确处理 11/07/2918 日期?以及如何让它正确解析这样的日期?
read_csv
文档说默认情况下它使用 dateutil.parser.parse
。当您手动尝试时:
import dateutil
dateutil.parser.parse("13/07/2918")
它很管用。没有异常,没有错误并生成有效的 datetime
对象:datetime.datetime(2918, 7, 13, 0, 0)
也可以将其转换为 numpy.datetime64
有效
import dateutil
toy = dateutil.parser.parse("13/07/2918")
np.datetime64(toy)
它生成一个有效且正确解析的对象。
numpy.datetime64('2918-07-13T00:00:00.000000')
同样,使用 pandas
' strptime
可以正常工作并生成有效的日期时间对象。
pd.datetime.strptime("11/07/2918", "%d/%m/%Y")
现在,尝试使用自定义日期解析器,只是为了确保日期格式正确
mycsv = StringIO("id,date\n1,11/07/2018\n2,11/07/2918\n3,02/01/2019")
df = pd.read_csv(
mycsv,
parse_dates=["date"],
date_parser=lambda x: pd.datetime.strptime(x, "%d/%m/%Y")
)
同样 df["date"].dtype
是 dtype('O')
好的,所以我放弃了说服 read_csv
正确解析日期的尝试。所以我说,让我们把它转换成日期吧。
这一个
df["date"].astype("datetime64")
或这个
pd.to_datetime(df["date"])
抛出和异常
OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 2918-07-11 00:00:00
似乎没有任何效果。
知道为什么会发生这种情况以及如何让它发挥作用吗?
来自文档:
Since pandas represents timestamps in nanosecond resolution, the time span that can
be represented using a 64-bit integer is limited to approximately 584 years:
In [92]: pd.Timestamp.min
Out[92]: Timestamp('1677-09-21 00:12:43.145225')
In [93]: pd.Timestamp.max
Out[93]: Timestamp('2262-04-11 23:47:16.854775807')
如何表示越界时间: https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#timeseries-oob