如何正确转换包含 timedelta 列 to/from JSON 的 Pandas DataFrame?
How to properly convert Pandas DataFrame which contains timedelta columns to/from JSON?
我有一个应用程序,我正在尝试将 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(不理想,因为我需要在实际应用程序中动态找出要 运行 的列),但我在那里得到了相同的错误值。
任何help/pointers关于我应该在这里做的事情,如果有适当的方法,将不胜感激。谢谢。
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]
read_json
不直接解析 timedelta isoformats,因此 days
作为字符串(对象数据类型)加载。您必须手动解析它:
iso_results_df['days'] = iso_results_df['days'].apply(pd.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(不理想,因为我需要在实际应用程序中动态找出要 运行 的列),但我在那里得到了相同的错误值。
任何help/pointers关于我应该在这里做的事情,如果有适当的方法,将不胜感激。谢谢。
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]
read_json
不直接解析 timedelta isoformats,因此 days
作为字符串(对象数据类型)加载。您必须手动解析它:
iso_results_df['days'] = iso_results_df['days'].apply(pd.Timedelta)