python - 如何正确地将包含 timedelta 列的 Pandas DataFrame 与 JSON 相互转换?

标签 python pandas dataframe timedelta

我有一个应用程序,我试图在 Pandas DataFrame 与 JSON 对象之间进行转换,当 df 包含 Timedelta 对象时,我遇到了问题。我正在使用 Pandas 1.2.4。

这是我一直在使用的示例 df:

>>> timedelta_df = pd.DataFrame({'datetime': pd.Series(['2013-12-31T00:00:00.000Z'], dtype='datetime64[ns]'),
                                 'days': pd.Series([pd.Timedelta(days=1)])})
>>> timedelta_df
    datetime   days
0 2013-12-31 1 days
>>> timedelta_df.dtypes
datetime     datetime64[ns]
days        timedelta64[ns]
dtype: object

然后我一直使用 to_json 和 read_json 将 df 转换为 JSON 并返回 df:

>>> js_result = timedelta_df.to_json()
>>> js_result
'{"datetime":{"0":1388448000000},"days":{"0":86400000}}'
>>> result_df = pd.read_json(js_result)
>>> result_df
    datetime      days
0 2013-12-31  86400000
>>> result_df.dtypes
datetime    datetime64[ns]
days                 int64
dtype: object

然后,为了再次尝试获取正确的类型,我一直在使用 astype,这似乎是我遇到问题的地方:

>>> result_df = result_df.astype(timedelta_df.dtypes.to_dict())
>>> result_df
    datetime                   days
0 2013-12-31 0 days 00:00:00.086400
>>> result_df.dtypes
datetime     datetime64[ns]
days        timedelta64[ns]
dtype: object

所以我得到了正确的类型,但值不正确。

接下来我尝试使用 iso 日期格式,但出现错误:

>>> iso_js_result = timedelta_df.to_json(date_format='iso')
>>> iso_js_result
'{"datetime":{"0":"2013-12-31T00:00:00.000Z"},"days":{"0":"P1DT0H0M0S"}}'
>>> iso_results_df = pd.read_json(iso_js_result)
>>> iso_results_df
                   datetime        days
0 2013-12-31 00:00:00+00:00  P1DT0H0M0S
>>> iso_results_df = iso_results_df.astype(timedelta_df.dtypes.to_dict())
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "F:\temp\virtualEnvironments\inference_schema_py37_dev\lib\site-packages\pandas\core\generic.py", line 5862, in astype
    col.astype(dtype=dtype[col_name], copy=copy, errors=errors)
  File "F:\temp\virtualEnvironments\inference_schema_py37_dev\lib\site-packages\pandas\core\generic.py", line 5877, in astype
    new_data = self._mgr.astype(dtype=dtype, copy=copy, errors=errors)
  File "F:\temp\virtualEnvironments\inference_schema_py37_dev\lib\site-packages\pandas\core\internals\managers.py", line 631, in astype
    return self.apply("astype", dtype=dtype, copy=copy, errors=errors)
  File "F:\temp\virtualEnvironments\inference_schema_py37_dev\lib\site-packages\pandas\core\internals\managers.py", line 427, in apply
    applied = getattr(b, f)(**kwargs)
  File "F:\temp\virtualEnvironments\inference_schema_py37_dev\lib\site-packages\pandas\core\internals\blocks.py", line 673, in astype
    values = astype_nansafe(vals1d, dtype, copy=True)
  File "F:\temp\virtualEnvironments\inference_schema_py37_dev\lib\site-packages\pandas\core\dtypes\cast.py", line 1074, in astype_nansafe
    return lib.astype_intsafe(arr.ravel(), dtype).reshape(arr.shape)
  File "pandas\_libs\lib.pyx", line 619, in pandas._libs.lib.astype_intsafe
ValueError: Could not convert object to NumPy timedelta

此时我感觉自己错过了一些东西。我主要关注的是 to_json、read_json 和 astype 的 API 引用文档,而我在参数方面所做的尝试都没有为我解决这个问题。我还尝试在特定列上使用 to_timedelta (并不理想,因为我需要动态地找出在实际应用程序中运行它的列),但我在那里得到了相同的错误值。

如果有适当的方法,任何关于我应该在这里做什么的帮助/指示,将不胜感激。谢谢。

最佳答案

result_df.astype(timedelta_df.dtypes.to_dict()) 导致错误值的问题是 days 列的数据类型是 timedelta64[ ns],即它需要纳秒,而 to_json 默认将时间增量序列化为毫秒。

因此,解决此问题的一种简单方法是将其显式序列化为纳秒:timedelta_df.to_json(date_unit="ns")

>>> result_df = pd.read_json(timedelta_df.to_json(date_unit="ns"))
>>> result_df.astype(timedelta_df.dtypes)
    datetime   days
0 2013-12-31 1 days

另一种方法是告诉 pd.to_timedelta 需要哪些单位:

>>> result_df = pd.read_json(timedelta_df.to_json())
>>> pd.to_timedelta(result_df.days, unit="ms")
0   1 days
Name: days, dtype: timedelta64[ns]

或者对于 iso 格式:

>>> result_df = pd.read_json(timedelta_df.to_json(date_format='iso')
>>> pd.to_timedelta(result_df.days)
0   1 days
Name: days, dtype: timedelta64[ns]

关于python - 如何正确地将包含 timedelta 列的 Pandas DataFrame 与 JSON 相互转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67892569/

相关文章:

python - 创建数据框子集的散点图

python - Django类继承创建table表

python - 二叉树递归循环返回 None

python - Groupby Sum 忽略几列

python - 是否有一种矢量化的方法来检查 DataFrame 中的值(例如,如果一切都是长度为 0 的字符串)

python - 将具有列表中值的字典转换为 Pandas DataFrame

python - 动态计算工作日数,不包括 Python 中的假期日历

python - Matplotlib 总是为每个绘图打开一个窗口,而不是仅仅将其写入文件

r - 将数组操作为 BASE R 中的 data.frame

r - 检查数据框本身是否为 NA