pandas dataframe列是否可以具有datetime.date类型?

时间:2017-09-04 17:15:16

标签: python pandas datetime numpy

我正在使用cx_oracle从数据库中获取日期。我想将获取的数据放入pandas数据帧中。我的问题是日期被转换为我绝对不需要的numpy.datetime64个对象。

我想将它们作为datetime.date对象。我已经看到了dt.date方法,但它仍然给出了numpy datetypes。

1 个答案:

答案 0 :(得分:4)

编辑:看起来使用pandas 0.21.0或更新版本,在DataFrame中保存python datetime.date是没有问题的。 date-like列不会自动转换为datetime64[ns] dtype。

import numpy as np
import pandas as pd
import datetime as DT

print(pd.__version__)
# 0.21.0.dev+25.g50e95e0
dates = [DT.date(2017,1,1)+DT.timedelta(days=2*i) for i in range(3)]
df = pd.DataFrame({'dates': dates, 'foo': np.arange(len(dates))})
print(all([isinstance(item, DT.date) for item in df['dates']]))
# True
df['dates'] = (df['dates'] + pd.Timedelta(days=1))
print(all([isinstance(item, DT.date) for item in df['dates']]))
# True

对于旧版本的Pandas:

有一种方法可以防止Pandas DataFrame自动转换 通过分配一个附加值(如a),将日期值设置为datetime64[ns] 空字符串与列不是日期。在DataFrame之后 形成后,您可以删除非日期值:

import pandas as pd
import datetime as DT
dates = [DT.date(2017,1,1)+DT.timedelta(days=i) for i in range(10)]
df = pd.DataFrame({'dates':['']+dates})
df = df.iloc[1:]
print(all([isinstance(item, DT.date) for item in df['dates']]))
# True
显然,将这​​种shenanigan编程为严格的代码感觉完全错误,因为我们颠覆了开发人员的意图。 使用datetime64[ns]datetime.dates的列表或对象数组也有计算速度优势。 此外,如果df[col]有dtype datetime64[ns],那么df[col].dt.date.values会返回一个对象NumPy的python datetime.date数组:

import pandas as pd
import datetime as DT
dates = [DT.datetime(2017,1,1)+DT.timedelta(days=2*i) for i in range(3)]
df = pd.DataFrame({'dates': dates})
print(repr(df['dates'].dt.date.values))
# array([datetime.date(2017, 1, 1), datetime.date(2017, 1, 3),
#        datetime.date(2017, 1, 5)], dtype=object)

因此,您可以将列保持为datetime64[ns]并使用df[col].dt.date.values在必要时获取datetime.date,从而享受两全其美。

另一方面,datetime64[ns]和Python datetime.date具有不同的可表示日期范围。

  • datetime64[ns]可以代表1678 AD to 2262 AD的日期时间。
  • datetime.date可以表示从DT.date(0,1,1)DT.date(9999,1,1)的日期。

如果您要使用datetime.date而不是datetime64[ns] s的原因是为了克服有限范围的可表示日期,那么可能a better alternative is to use a pd.PeriodIndex

import pandas as pd
import datetime as DT
dates = [DT.date(2017,1,1)+DT.timedelta(days=2*i) for i in range(10)]
df = pd.DataFrame({'dates':pd.PeriodIndex(dates, freq='D')})
print(df)
#        dates
# 0 2017-01-01
# 1 2017-01-03
# 2 2017-01-05
# 3 2017-01-07
# 4 2017-01-09
# 5 2017-01-11
# 6 2017-01-13
# 7 2017-01-15
# 8 2017-01-17
# 9 2017-01-19