有没有办法在不将 dtype 更改为对象的情况下将 NaT 附加到带有时区的 pandas 日期时间?

Posted

技术标签:

【中文标题】有没有办法在不将 dtype 更改为对象的情况下将 NaT 附加到带有时区的 pandas 日期时间?【英文标题】:Is there a way to append NaT to a pandas datetime with timezone without changing dtype to object? 【发布时间】:2019-08-13 20:09:16 【问题描述】:

我的 DataFrame 中有一个 dtype 列:datetime64[ns, UTC]。当我在该列中附加一个带有 None 或 NaT 的行时,该列的 dtype 更改为“object”。这不会发生在 dtype: datetime64[ns] 的列上。

这是一个演示:

# Test pandas with datetime columns
import pandas as pd
from datetime import datetime, timezone
df = pd.DataFrame(['D': datetime.utcnow()])
df_wtz = pd.DataFrame(['D': datetime.now().astimezone(timezone.utc)])
df_None = pd.DataFrame(['D': None])
# Note that the tz below is ignored even though specified
df_Nat = pd.DataFrame(['D': pd.Timestamp(None,tz=timezone.utc)])

print('df:\n', df['D'])
print('df_wtz:\n', df_wtz['D'])
print('df_None:\n', df_None['D'])
print('df_Nat:\n', df_Nat['D'])

print('df append df_None:\n', df.append(df_None, ignore_index=True, sort=False)['D'])
print('df append df_Nat:\n', df.append(df_Nat, ignore_index=True, sort=False)['D'])

print('df_wtz append df_None:\n', df_wtz.append(df_None, ignore_index=True, sort=False)['D'])
print('df_wtz append df_Nat:\n', df_wtz.append(df_Nat, ignore_index=True, sort=False)['D'])

这是输出:

df:
 0   2019-08-13 19:58:18.811492
Name: D, dtype: datetime64[ns]
df_wtz:
 0   2019-08-13 19:58:18.811968+00:00
Name: D, **dtype: datetime64[ns, UTC]**
df_None:
 0    None
Name: D, dtype: object
df_Nat:
 0   NaT
Name: D, dtype: datetime64[ns]
df append df_None:
 0   2019-08-13 19:58:18.811492
1                          NaT
Name: D, dtype: datetime64[ns]
df append df_Nat:
 0   2019-08-13 19:58:18.811492
1                          NaT
Name: D, dtype: datetime64[ns]
df_wtz append df_None:
 0    2019-08-13 19:58:18.811968+00:00
1                                None
Name: D, dtype: object
df_wtz append df_Nat:
 0    2019-08-13 19:58:18.811968+00:00
1                                 NaT
Name: D, dtype: object

我曾期望在将 None 或 NaT 附加到 datetime64[ns, UTC] 列的情况下保留列类型,但事实并非如此。这是预期的行为还是会被视为错误?

【问题讨论】:

【参考方案1】:

您可以通过这种方式将 NaT 放在 dtype datetime64[ns, UTC] 的列中:

 In [380]: df_Nat = pd.DataFrame('D': pd.to_datetime([None], utc=True)); df_Nat
 Out[380]: 
     D
 0 NaT

 In [381]: df_Nat.info()
 <class 'pandas.core.frame.DataFrame'>
 RangeIndex: 1 entries, 0 to 0
 Data columns (total 1 columns):
 D    0 non-null datetime64[ns, UTC]
 dtypes: datetime64[ns, UTC](1)
 memory usage: 88.0 bytes

现在将df_Nat 附加到df_wtz 会保留数据类型:

import pandas as pd
import datetime as DT
utc = DT.timezone.utc
now = DT.datetime.now()
df_wtz = pd.DataFrame(['D': now.astimezone(utc)])
df_Nat = pd.DataFrame('D': pd.to_datetime([None], utc=True))
# df_Nat = pd.DataFrame('D':pd.Series(pd.NaT, dtype='datetime64[ns, UTC]')) # also works

print('df_wtz append df_Nat:\n', df_wtz.append(df_Nat, ignore_index=True, sort=False)['D'])

产量

df_wtz append df_Nat:
 0   2019-08-13 20:28:15.928023+00:00
1                                NaT
Name: D, dtype: datetime64[ns, UTC]

NaT 本身不支持时区:

In [383]: pd.Timestamp(None) is pd.Timestamp(None, tz=utc)
Out[383]: True

所以pd.DataFrame(['D': pd.Timestamp(None,tz=utc)]) 不会生成具有时区感知 dtype 的列。

由于不可能让 DataFrame 从 NaT 本身推断出可识别时区的 dtype, 我们需要构建一个已经具有正确时区感知 dtype 的容器(例如 Series 或 DatetimeIndex)。这就是pd.to_datetime([None], utc=True) 所做的:

In [385]: pd.to_datetime([None], utc=True)
Out[385]: DatetimeIndex(['NaT'], dtype='datetime64[ns, UTC]', freq=None)

【讨论】:

谢谢 - 这对我有用。我仍然很遗憾添加 None 会修改列类型...

以上是关于有没有办法在不将 dtype 更改为对象的情况下将 NaT 附加到带有时区的 pandas 日期时间?的主要内容,如果未能解决你的问题,请参考以下文章

我们如何在不将 ViewController 对象推入其中的情况下将对象分配给 `UINavigationController`。

如何在不将 LocalDateTime 字段转换为扩展的 json 对象的情况下将 java 对象转换为简单的 json 字符串?

如何在不将 csv 保存到磁盘的情况下将 csv 格式的数据从内存发送到数据库?

如何在不覆盖 ModelForm 中的字段定义的情况下将 ManyToManyField 小部件更改为 CheckboxSelectMultiple

如何在不丢失 Xampp 中的数据的情况下将类型从 varchar 更改为 Date

imagemagick 在不使用 -extent 的情况下将画布更改为正方形(保留最长边)