2013-11-07 2 views
3

Я использую Pandas 0.12.0 и вижу некоторое поведение, которое противоречит документам при преобразовании серии или dataframe в json.Pandas to_json не выводит null для NaT

Если создать серию с несколькими датами, которые включают нулевые значения, я получаю что-то вроде этого:

>>> 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 не должны быть представлены как ноль.

Если я затем вывожу to_json, я получу нуль для третьей записи, как и ожидалось.

>>> s.to_json() 
'{"0":1383840647530771000,"1":1383840647530782000,"2":null}' 

Однако, мне нужно, чтобы убедиться, что тип данных datetime64 [нс] для некоторых других вычислений, так что я преобразовать поля 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 вместо нулевого, которое я ожидал.

>>> t.to_json() 
'{"0":1383840647530771000,"1":1383840647530782000,"2":-9223372036854775808}' 

Это становится еще хуже, при использовании формата изо, поскольку он пытается форматировать дату, но большинство парсеров не могут понять, как обрабатывать даты выхода, и это навлекает все виды опустошения вниз линии.

>>> 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"}' 

Любые мысли о том, как я должен действовать здесь? Благодаря!

EDIT:

Похоже, это проблема с строковым представлением pandas.NaT?

>>> str(pandas.NaT) 
'0001-255-255 00:00:00' 
+0

FWIW I не может воспроизвести это в багажнике, которое я сегодня вытащил; Я получаю '' {"0": 1383841824833, "1": 1383841824833, "2": null} 'и '' {" 0 ":" 2013-11-07T16: 30: 24.833Z "," 1 ": "2013-11-07T16: 30: 24.833Z", "2": null} '', соответственно. – DSM

+0

iirc это было исправлено на раннем этапе dev для 0,13. 0.13 rc выходит в начале следующей недели/u может попробовать мастер, чтобы подтвердить, что он исправлен. в качестве альтернативы вы можете выполнить строчку перед передачей to_json – Jeff

+0

Подтверждено, что это исправлено в багажнике/0.13, спасибо, ребята. Я сделал быстрый поиск в списке проблем, но не нашел этого.Джефф, я попробую ваше хакерское обходное решение, пока не будет выпущено 0,13. – brandon

ответ

2

Немного 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"}' 
+0

Спасибо, Джефф, это в основном работало. Я изменил его на 'return None', иначе json имеет строку« null »вместо фактического значения NULL. Ура! – brandon

1

Просто создать пользовательский кодировщик:

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) 

затем использовать его для кодирования dataframe:

df_as_dict = df.to_dict(outtype = 'records') # transform to dict 

df_as_json = CustomEncoder().encode(df_as_dict) #transform to json 

Поскольку кодировщик стандартизовал данные а, регулярный декодер будет действовать штраф в преобразовании его обратно в dataframe:

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 

Конечно, это также будет работать, если вы поставите dataframe в большой Словарь перед кодированием, например

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) 
Смежные вопросы