pandasでJSON文字列・ファイルを読み込み(read_json)
pandas.read_json()
関数を使うと、JSON形式の文字列(str
型)やファイルをpandas.DataFrame
として読み込むことができる。JSON Lines(.jsonl
)にも対応している。
pandas.DataFrame
として読み込んでしまえば、もろもろのデータ分析はもちろん、to_csv()
メソッドでcsvファイルとして保存したりもできるので、pandas.DataFrame
を介してJSONファイルをCSVファイルに簡単に変換できて便利。
ここでは以下の内容について説明する。そのほかの引数については上記の公式ドキュメントを参照。
pandas.read_json()
の基本的な使い方- JSON形式の文字列を読み込み
- JSON形式のファイルを読み込み
- 圧縮ファイルを読み込み: 引数
compression
- 圧縮ファイルを読み込み: 引数
- 形式を指定: 引数
orient
- JSON Lines(
.jsonl
)を読み込み - JSON文字列・ファイルの一部を読み込み
Python標準ライブラリのjsonモジュールでJSONファイルや文字列を辞書として読み込む方法は以下の記事を参照。
辞書やリストからなるオブジェクトをpandas.DataFrame
に変換するにはpandas.io.json.json_normalize()
を使う。
そのほかpandasでのcsvファイル、Excelファイルの読み書き(入出力)については以下の記事を参照。
- 関連記事: pandasでcsv/tsvファイル読み込み(read_csv, read_table)
- 関連記事: pandasでcsvファイルの書き出し・追記(to_csv)
- 関連記事: pandasでExcelファイル(xlsx, xls)の読み込み(read_excel)
- 関連記事: pandasでExcelファイル(xlsx, xls)の書き込み(to_excel)
pandas.read_jsonの基本的な使い方
例として使う文字列、ファイルは以下の記事で作成したもの。
JSON形式の文字列を読み込み
pandas.read_json()
関数の第一引数にJSON形式の文字列を渡すと、文字列がpandas.DataFrame
に変換される。
import pandas as pd
import json
s = '{"col1":{"row1":1,"row2":2,"row3":3},"col2":{"row1":"a","row2":"x","row3":"\u3042"}}'
df_s = pd.read_json(s)
print(df_s)
# col1 col2
# row1 1 a
# row2 2 x
# row3 3 あ
元の文字列のUnicodeエスケープシーケンス\uXXXX
は対応する文字に変換される。
なお、JSON文字列内の引用符はダブルクォート"
でなければならない。シングルクォート'
の場合はエラー(ValueError
)となる。
s_single_quote = "{'col1':{'row1':1,'row2':2,'row3':3},'col2':{'row1':'a','row2':'x','row3':'\u3042'}}"
# df_s_single_quote = pd.read_json(s_single_quote)
# ValueError: Expected object or value
シングルクォート'
が使われた文字列の場合、文字列メソッドreplace()
でシングルクォート'
をダブルクォート"
に置換すればOK。
print(pd.read_json(s_single_quote.replace("'", '"')))
# col1 col2
# row1 1 a
# row2 2 x
# row3 3 あ
JSON形式のファイルを読み込み
pandas.read_json()
関数の第一引数にJSON形式のファイルのパスを渡すと、ファイルがpandas.DataFrame
として読み込まれる。
df_f = pd.read_json('data/src/sample_from_pandas_columns.json')
print(df_f)
# col1 col2
# row1 1 a
# row2 2 x
# row3 3 あ
元のファイルのUnicodeエスケープシーケンス\uXXXX
は対応する文字に変換される。
文字列の場合と同様、JSONファイル内で使われる引用符はダブルクォート"
でなければならない。
圧縮ファイルを読み込み: 引数compression
pandasのバージョン0.21.0
から引数compression
が追加され、'gzip'
, 'bz2'
, 'zip'
, 'xz'
を指定することで圧縮ファイルを直接読み込めるようになった。
拡張子が.gz
, .bz2
, .zip
, .xz
の場合はcompression='infer'
とすると対応する圧縮方式が自動的に選ばれる。
df_gzip = pd.read_json('data/src/sample_from_pandas_columns.gz', compression='infer')
print(df_gzip)
# col1 col2
# row1 1 a
# row2 2 x
# row3 3 あ
なお、単独のファイルが圧縮されたもののみが対象で、複数ファイルがまとめられたzip
は読み込めない。
形式を指定: 引数orient
JSONの中身をどのようにpandas.DataFrame
の行ラベルindex
、列ラベルcolumns
、値values
に割り当てるかという形式には以下の種類がある。
'split'
{index -> [index], columns -> [columns], data -> [values]}
'records'
[{column -> value}, ... , {column -> value}]
'index'
{index -> {column -> value}}
'columns'
(デフォルト){column -> {index -> value}}
'values'
[values]
実際の例は以下の記事を参照されたい。
読み込む文字列やファイルの形式と引数orient
で指定する形式が違っていると、行と列が入れ替わったり、エラーになったりするので注意。
df_s_index = pd.read_json(s, orient='index')
print(df_s_index)
# row1 row2 row3
# col1 1 2 3
# col2 a x あ
# df_s_split = pd.read_json(s, orient='split')
# ValueError: JSON data had unexpected key(s): col2, col1
JSON Lines(.jsonl)を読み込み
JSON Lines(.jsonl
)はJSONが改行で区切られたフォーマット。
引数orient='records'
の場合に、さらに引数lines=True
とすると、pandas.read_json()
でJSON Lines(.jsonl
)を読み込める。
s_jsonl = '''{"col1":1,"col2":"a"}
{"col1":2,"col2":"x"}
{"col1":3,"col2":"\u3042"}'''
print(s_jsonl)
# {"col1":1,"col2":"a"}
# {"col1":2,"col2":"x"}
# {"col1":3,"col2":"あ"}
df_s_jsonl = pd.read_json(s_jsonl, orient='records', lines=True)
print(df_s_jsonl)
# col1 col2
# 0 1 a
# 1 2 x
# 2 3 あ
JSONLファイルを読み込む場合は、上の例と同様に、第一引数にファイルのパスを指定すればよい。
JSON文字列・ファイルの一部を読み込み
実際にWeb APIなどで取得できるJSONにはpandas.DataFrame
として読み込みたいデータ以外の情報も付加されているので、そのままpandas.read_json()
を適用できない場合が多い。
そのような場合は、以下のような流れで読み込むことが可能。もっといいやり方があるかもしれない。
- JSON文字列・ファイルを標準ライブラリのjsonモジュールの
json.loads()
,json.load()
で辞書として読み込む - 辞書から読み込みたい部分を抽出
- 抽出した部分を
json.dumps()
で文字列に変換 - 文字列を
pandas.read_json()
に渡す
json.loads()
やjson.dumps()
についての詳細は以下の記事を参照。
以下のネストしたJSON文字列を例とする。
s_nested = '{"OTHER": "x", "DATA": {"col1":{"row1":1,"row2":2},"col2":{"row1":"a","row2":"x"}}}'
これをそのままpandas.read_json()
に渡すと以下のようになってしまう。
print(pd.read_json(s_nested))
# DATA OTHER
# col1 {'row1': 1, 'row2': 2} x
# col2 {'row1': 'a', 'row2': 'x'} x
まずjson.loads()
で辞書に変換する。ファイルを読み込む場合はjson.load()
。
d = json.loads(s_nested)
print(d)
# {'OTHER': 'x', 'DATA': {'col1': {'row1': 1, 'row2': 2}, 'col2': {'row1': 'a', 'row2': 'x'}}}
print(type(d))
# <class 'dict'>
辞書からpandas.DataFrame
として読み込みたい部分を抽出。ネストが深い場合は[キー名][キー名]
のように繰り返す。
d_target = d['DATA']
print(d_target)
# {'col1': {'row1': 1, 'row2': 2}, 'col2': {'row1': 'a', 'row2': 'x'}}
print(type(d_target))
# <class 'dict'>
json.dumps()
で文字列に変換。
s_target = json.dumps(d_target)
print(s_target)
# {"col1": {"row1": 1, "row2": 2}, "col2": {"row1": "a", "row2": "x"}}
print(type(s_target))
# <class 'str'>
pandas.read_json()
に渡す。形式に応じた引数orient
を指定する。例はデフォルト(orient='columns'
)。
df_target = pd.read_json(s_target)
print(df_target)
# col1 col2
# row1 1 a
# row2 2 x
まとめて書いてもOK。
df_target2 = pd.read_json(json.dumps(json.loads(s_nested)['DATA']))
print(df_target2)
# col1 col2
# row1 1 a
# row2 2 x
読み込みたい部分がorient='records'
(辞書のリスト)形式の場合はpandas.io.json.json_normalize()
を使って辞書のリストを直接pandas.DataFrame
に変換できる。
詳細は以下の記事を参照。