我正在使用Pandas 0.12.0,并且在将系列或数据帧转换为json时,我看到一些与文档相矛盾的行为。
如果我创建一个包含一些包含空值的日期的系列,我会得到这样的结果:
>>> s = pandas.Series(data=[datetime.datetime.now(), datetime.datetime.now(), None])
>>> s
0 2013-11-07 16:10:47.530771
1 2013-11-07 16:10:47.530782
2 None
dtype: object
根据http://pandas.pydata.org/pandas-docs/dev/io.html#writing-json,当转换为json时,None,NaT和NaN值应输出为null。
如果我然后输出to_json,我会按预期为第三个条目获取null。
>>> s.to_json()
'{"0":1383840647530771000,"1":1383840647530782000,"2":null}'
但是,我需要确保数据类型是datetime64 [ns]用于其他一些计算,因此我将字段转换为Pandas中的datetime,如下所示:
>>> t = pandas.to_datetime(s)
>>> t
0 2013-11-07 16:10:47.530771
1 2013-11-07 16:10:47.530782
2 NaT
dtype: datetime64[ns]
“无”现在是一个NaT,这是一致的和预期的。然后我尝试再次输出json,我得到NaT值的负值而不是我期望的null。
>>> t.to_json()
'{"0":1383840647530771000,"1":1383840647530782000,"2":-9223372036854775808}'
使用iso格式会变得更糟,因为它试图格式化日期,但大多数解析器无法弄清楚如何处理输出日期,这会造成各种各样的破坏。
>>> t.to_json(date_format='iso')
'{"0":"2013-11-07T16:10:47.530771","1":"2013-11-07T16:10:47.530782","2":"0001-255-255T00:00:00"}'
关于我应该如何进行的任何想法?谢谢!
修改:
看起来这是pandas.NaT的字符串表示问题?
>>> str(pandas.NaT)
'0001-255-255 00:00:00'
答案 0 :(得分:3)
有点hacky,但你可以这样做
In [13]: s = Series(pd.to_datetime(['20130101',None]))
In [14]: s
0 2013-01-01 00:00:00
1 NaT
dtype: datetime64[ns]
In [15]: def f(x):
if isnull(x):
return 'null'
return x.isoformat() ....:
In [16]: s.apply(f).to_json()
Out[16]:
'{"0":"2013-01-01T00:00:00","1":"null"}'
答案 1 :(得分:2)
只需创建一个自定义编码器:
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if pd.isnull(obj):
return None
elif isinstance(obj, datetime):
return obj.isoformat()
elif isinstance(obj, date):
return obj.isoformat()
elif isinstance(obj, timedelta):
return (datetime.min + obj).time().isoformat()
else:
return super(CustomEncoder, self).default(obj)
然后用它来编码数据帧:
df_as_dict = df.to_dict(outtype = 'records') # transform to dict
df_as_json = CustomEncoder().encode(df_as_dict) #transform to json
由于编码器对数据进行了标准化,因此常规解码器可以很好地将其转换回数据帧:
result_as_dict = json.JSONDecoder().decode(df_as_json) # decode back to dict
result_as_df = pd.DataFrame(result_as_dict) # transform dict back to dataframe
当然,如果在编码之前将数据帧放入更大的dict中,这也会有效,例如
input_dict = {'key_1':val_1,'key_2':val_2,...,'df_as_dict':df_as_dict}
input_json = CustomEncoder().encode(input_dict)
input_json_back_as_dict = json.JSONDecoder().decode(input_json)
input_df_back_as_dict = input_json_back_as_dict['df_as_dict']
input_df_back_as_df = pd.DataFrame(input_df_back_as_dict)