防止 Pandas to_json() 将时间组件添加到日期对象
Posted
技术标签:
【中文标题】防止 Pandas to_json() 将时间组件添加到日期对象【英文标题】:Prevent Pandas to_json() from adding time component to date object 【发布时间】:2018-06-30 09:00:56 【问题描述】:我有一个包含一些日期对象的数据框。我需要转换为 json 以在 javascript 中使用,这需要 YYYY-MM-DD,但 to_json()
不断添加时间组件。我已经看到了许多首先转换为字符串的答案,但这是大约 15 个查询的循环的一部分,每个查询都有很多列(为 SO 问题简化了它),我不想将每个列转换硬编码为有很多。
import pandas as pd
from datetime import date
df = pd.DataFrame(data=[[date(year=2018, month=1, day=1)]])
print df.to_json(orient='records', date_format='iso', date_unit='s')
输出:
["0":"2018-01-01T00:00:00Z"]
期望的输出:
["0":"2018-01-01"]
【问题讨论】:
我认为最好的办法是在将 df 转换为 json 之前格式化日期时间。 【参考方案1】:Pandas 目前没有该功能。有一个关于此的未解决问题,您应该订阅该问题,以防在将来的版本中添加更多date_format
参数选项(这似乎是一个合理的功能请求):
No way with to_json to write only date out of datetime #16492
在转储 json 之前手动将相关列转换为字符串可能是最好的选择。
【讨论】:
【参考方案2】:您可以像这样使用strftime('%Y-%m-%d')
格式:
df = pd.DataFrame(data=[[date(year=2018, month=1, day=1).strftime('%Y-%m-
%d')]]
print(df.to_json(orient='records', date_format='iso', date_unit='s'))
# ["0":"2018-01-01"]
我认为这是目前最好的方法,直到 pandas 添加一种仅写入超出日期时间的日期的方法。
【讨论】:
我认为date_format
和 date_unit
kwargs 变得多余,因为 pandas 只看到一个字符串对象,而不是一个日期对象【参考方案3】:
演示:
来源 DF:
In [249]: df = pd.DataFrame(
...: 'val':np.random.rand(5),
...: 'date1':pd.date_range('2018-01-01',periods=5),
...: 'date2':pd.date_range('2017-12-15',periods=5)
...: )
In [250]: df
Out[250]:
date1 date2 val
0 2018-01-01 2017-12-15 0.539349
1 2018-01-02 2017-12-16 0.308532
2 2018-01-03 2017-12-17 0.788588
3 2018-01-04 2017-12-18 0.526541
4 2018-01-05 2017-12-19 0.887299
In [251]: df.dtypes
Out[251]:
date1 datetime64[ns]
date2 datetime64[ns]
val float64
dtype: object
您可以在一个命令中将datetime
列转换为字符串:
In [252]: df.update(df.loc[:, df.dtypes.astype(str).str.contains('date')].astype(str))
In [253]: df.dtypes
Out[253]:
date1 object
date2 object
val float64
dtype: object
In [254]: df.to_json(orient='records')
Out[254]: '["date1":"2018-01-01","date2":"2017-12-15","val":0.5393488718,"date1":"2018-01-02","date2":"2017-12-16","val":0.3085324043,"
date1":"2018-01-03","date2":"2017-12-17","val":0.7885879674,"date1":"2018-01-04","date2":"2017-12-18","val":0.5265407505,"date1":"2018-0
1-05","date2":"2017-12-19","val":0.887298853]'
或者,您可以在 SQL 端将日期列转换为字符串
【讨论】:
谢谢 MaxU。我意识到这确实有效,但实际上,我有多个列和许多数据帧(都来自 SQL 查询),所以像这样硬编码列引用对我来说并不实用。 @user2242044,好吧,我认为无论如何你都必须将这些列转换为字符串 - 无论是在 SQL 端还是在 Pandas 中 啊,我忘了我可以在 SQL 端做到这一点,这可能是最好的。谢谢。【参考方案4】:我也遇到过这个问题,但是由于我只查找日期,而忽略了时区,所以我可以使用以下表达式解决这个问题:
df = pd.read_json('test.json')
df['date_hour'] = [datetime.strptime(date[0:10],'%Y-%m-%d').date() for date in df['date_hour']]
因此,如果您在 json 文件中有 df[date_hour] 的 'iso' date_format = "2018-01-01T00:00:00Z",则可以使用此解决方案。
通过这种方式,您可以提取真正重要的部分。重要的是要说您必须使用此列表推导来执行此操作,因为转换只能逐个字符串(或逐行)完成,否则仅 datetime.strptime 会引发错误,说明不能与系列一起使用。
【讨论】:
【参考方案5】:通用解决方案如下:
df.assign( **df.select_dtypes(['datetime']).astype(str).to_dict('list') ).to_json(orient="records")
它根据 dtype 选择日期时间列并将它们设置为 str 对象,以便在序列化期间保持日期格式。
【讨论】:
以上是关于防止 Pandas to_json() 将时间组件添加到日期对象的主要内容,如果未能解决你的问题,请参考以下文章
pandas DataFrame 使用 to_json() 到字典列表
Pandas DataFrame to_json() 生成带点符号的索引
pandas to_json 返回一个字符串而不是 json 对象
Pandas Series 写入和读取 json 数据会产生带有 to_json 和 read_json 的 ValueError [重复]