1
0

`pandas.DataFrame.to_json`はスラッシュをエスケープして出力する

Posted at

環境

  • Python 3.12.1
  • pandas 2.2.2

はじめに

pandas.DataFrame.to_json()は、スラッシュ/\\でエスケープして出力します。

In [6]: import pandas as pd

In [12]: data = [{"id":"alice", "url":"https://example.com"}]

In [16]: df = pd.DataFrame(data)

In [17]: df.to_json()
Out[17]: '{"id":{"0":"alice"},"url":{"0":"https:\\/\\/example.com"}}'

しかし、json.dumpsではスラッシュをエスケープせずに出力します。

In [15]: json.dumps(data)
Out[15]: '[{"id": "alice", "url": "https://example.com"}]'

この違いは何なのでしょうか?

JSONの仕様

JSONの仕様では、スラッシュをエスケープすることができます。ただし、スラッシュのエスケープは必須でありません。

ここで一つポイントなのは、いくつかの実装でsolidus(スラッシュ)がエスケープの対象でなかったり、オプションだったりすること。JavaScriptの規格であるECMA-262ではエスケープ表記の対象にsolidus(スラッシュ)は含まれていなかったけど、最初の独立したJSON規格であるRFC 4627以降では対象に含まれている、という違いが有る。

なお、jsonモジュールはスラッシュをエスケープしてエンコードしませんが、エスケープされたスラッシュをデコードできます。

In [19]: tmp = df.to_json()

In [20]: tmp
Out[20]: '{"id":{"0":"alice"},"url":{"0":"https:\\/\\/example.com"}}'

In [21]: data2 = json.loads(tmp)

In [22]: data2
Out[22]: {'id': {'0': 'alice'}, 'url': {'0': 'https://example.com'}}

pandasの話

スタックオーバーフローの回答によると、pandas.DataFrame.to_jsonではusjonというライブラリが使われているそうです。

pandas.DataFrame.to_json()の中身を調べていくと、pandas.is.json._json.Writer.write関数で、pandas._libs.json.ujson_dumpsという関数を呼び出していることが分かりました。

なお、ujsonはデフォルトではスラッシュをエスケープして出力します。

スラッシュをエスケープしないようにする方法

pandas.DataFrame.to_json()を使わずにjson.dumpsを使えば、スラッシュをエスケープせずにJSON出力できます。

In [34]: tmp2 = df.to_dict("records")

In [35]: tmp2
Out[35]: [{'id': 'alice', 'url': 'https://example.com'}]

In [36]: json.dumps(tmp2)
Out[36]: '[{"id": "alice", "url": "https://example.com"}]'

ただし、以下の点に注意してください。

NaNはnullに変換されずにそのままNaNが出力される

pandas.DataFrame.to_json()NaNnullに変換します。

Note NaN’s and None will be converted to null and datetime objects will be converted to UNIX timestamps.

pandas.DataFrame.to_jsonを使わずに、pandas.DataFrame.to_dictで変換してjson.dumpsでJSONを出力すると、NaNはそのままNaNと出力されます。

In [38]: df = pd.DataFrame({"value": [1.1, None]})

In [39]: df
Out[39]:
   value
0    1.1
1    NaN

In [41]: tmp2 = df.to_dict("records")

In [42]: tmp2
Out[42]: [{'value': 1.1}, {'value': nan}]

In [43]: json.dumps(tmp2)
Out[43]: '[{"value": 1.1}, {"value": NaN}]'

NaNはJSONの仕様ではありませんが、PythonのjsonモジュールはNaNに対応しています。

In [52]: json.loads("NaN")
Out[52]: nan

pandas.DataFrame.to_dictpandas.NANoneに変換する

pandas.DataFrame.to_dictpandas.NANoneに変換します。
したがって、pandas.DataFrame.to_jsonを使わない場合は、DataFrameの列の型をfloat64ではなくnullableなFloat64にした方がよいでしょう。

In [55]: df = pd.DataFrame({"value": [1.1, None]}, dtype="Float64")

In [56]: df
Out[56]:
   value
0    1.1
1   <NA>

In [57]: tmp3 = df.to_dict("records")

In [58]: tmp3
Out[58]: [{'value': 1.1}, {'value': None}]

まとめ

  • pandas.DataFrame.to_jsonはスラッシュをエスケープして出力する
  • JSONの仕様では、スラッシュをエスケープして出力することは必須でない
  • pandas.DataFrame.to_jsonujsonライブラリを使ってJSONを出力している
    • ujsonはデフォルトでは、スラッシュをエスケープして出力する
  • pandas.DataFrame.to_jsonNaNnullに変換して出力する

参考にしたサイト

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0