json_normalizeとは?Python・pandasでJSONデータを表形式に変換する方法を徹底解説

「JSONデータをpandasのDataFrameに変換したい」
「ネストしたJSONを表形式にしたい」
「pandasのjson_normalizeの使い方がわからない」
このような悩みを解決するのが、pandasのjson_normalize()です。
json_normalize()を使うと、APIなどから取得した入れ子構造のJSON(ネストしたJSON)を、分析しやすいDataFrameへ変換できます。
本記事では、json_normalize()の基本的な使い方から、ネストしたJSON、record_path、meta、sepなどの便利なオプション、エラー対策まで詳しく解説します。
json_normalizeとは?
json_normalize()は、Pythonのpandasに用意されている関数で、JSON形式の階層構造をフラットな表形式に変換するための機能です。
基本的には、次のように利用します。
import pandas as pd
df = pd.json_normalize(data)
JSONデータが次のような構造だったとします。
data = [
{
"id": 1,
"name": "田中",
"age": 30
},
{
"id": 2,
"name": "佐藤",
"age": 25
}
]
json_normalize()を使うと、
df = pd.json_normalize(data)
print(df)
以下のようなDataFrameになります。
id name age
0 1 田中 30
1 2 佐藤 25
つまり、JSONの各要素をDataFrameの行・列に変換できます。
json_normalizeの基本的な使い方
まずpandasをインポートします。
import pandas as pd
次にJSON形式のデータを用意します。
data = [
{
"id": 1,
"name": "田中",
"age": 30
},
{
"id": 2,
"name": "佐藤",
"age": 25
}
]
pd.json_normalize()に渡します。
df = pd.json_normalize(data)
print(df)
結果は次のようになります。
id name age
0 1 田中 30
1 2 佐藤 25
これだけでJSONからDataFrameへの変換ができます。
json_normalizeが便利な理由
通常のJSONであれば、pd.DataFrame()でもDataFrameに変換できます。
df = pd.DataFrame(data)
しかし、JSONが複雑な階層構造になっている場合、json_normalize()が便利です。
例えば次のJSONを考えてみましょう。
data = [
{
"id": 1,
"name": "田中",
"address": {
"city": "東京",
"zipcode": "100-0001"
}
}
]
このデータに対して、
df = pd.json_normalize(data)
とすると、次のようなDataFrameになります。
id name address.city address.zipcode
0 1 田中 東京 100-0001
addressの中にあったcityやzipcodeも展開されています。
json_normalizeでネストしたJSONを展開する
APIから取得するJSONでは、データが階層化されていることがよくあります。
例えば、
data = [
{
"id": 1,
"name": "田中",
"profile": {
"age": 30,
"gender": "男性"
}
},
{
"id": 2,
"name": "佐藤",
"profile": {
"age": 25,
"gender": "女性"
}
}
]
これを、
df = pd.json_normalize(data)
print(df)
とすると、
id name profile.age profile.gender
0 1 田中 30 男性
1 2 佐藤 25 女性
となります。
このように、json_normalize()はネストされた辞書を自動的に展開できます。
sepで列名の区切り文字を変更する
デフォルトでは、ネストされた項目の区切りに.が使われます。
例えば、
profile.age
profile.gender
という列名になります。
区切り文字はsepで変更できます。
df = pd.json_normalize(
data,
sep="_"
)
すると、
profile_age
profile_gender
のようになります。
例えば、
df = pd.json_normalize(data, sep="_")
print(df.columns)
結果:
Index(['id', 'name', 'profile_age', 'profile_gender'], dtype='object')
CSVなどに出力する場合にも、sep="_"は便利です。
深い階層のJSONをjson_normalizeで処理する
さらに複雑なJSONも考えてみましょう。
data = [
{
"id": 1,
"name": "田中",
"company": {
"name": "ABC株式会社",
"address": {
"city": "東京",
"country": "日本"
}
}
}
]
json_normalize()を使うと、
df = pd.json_normalize(data)
以下のようになります。
id name company.name company.address.city company.address.country
0 1 田中 ABC株式会社 東京 日本
階層に応じて、
company.name
company.address.city
company.address.country
という列名が作られます。
record_pathとは?
json_normalize()で特に重要なのがrecord_pathです。
record_pathは、JSONの中にあるリストを指定して、DataFrameの行として展開するための引数です。
例えば、次のJSONを考えます。
data = [
{
"id": 1,
"name": "田中",
"orders": [
{
"product": "Python入門",
"price": 3000
},
{
"product": "Python応用",
"price": 4000
}
]
}
]
ordersを表形式にしたい場合、
df = pd.json_normalize(
data,
record_path="orders"
)
print(df)
結果:
product price
0 Python入門 3000
1 Python応用 4000
このようにordersの配列をDataFrameの行に変換できます。
record_pathとmetaを組み合わせる
record_pathだけでは、親データの情報が失われることがあります。
例えば、
data = [
{
"id": 1,
"name": "田中",
"orders": [
{
"product": "Python入門",
"price": 3000
},
{
"product": "Python応用",
"price": 4000
}
]
}
]
ここで、
record_path="orders"
とすると、idやnameはDataFrameに含まれません。
そこでmetaを使用します。
df = pd.json_normalize(
data,
record_path="orders",
meta=["id", "name"]
)
print(df)
結果:
product price id name
0 Python入門 3000 1 田中
1 Python応用 4000 1 田中
metaを使うことで、親階層にある情報を一緒に取得できます。
metaでネストした項目を指定する
metaにはネストした項目も指定できます。
例えば、
data = [
{
"id": 1,
"user": {
"name": "田中",
"department": "営業部"
},
"orders": [
{
"product": "Python入門",
"price": 3000
}
]
}
]
この場合、
df = pd.json_normalize(
data,
record_path="orders",
meta=[
"id",
["user", "name"],
["user", "department"]
]
)
とできます。
json_normalizeのerrors引数
JSONによっては、一部のデータに特定の項目が存在しない場合があります。
例えば、
data = [
{
"id": 1,
"name": "田中"
},
{
"id": 2
}
]
このような場合です。
errors引数を使うと、欠損した項目がある場合の動作を指定できます。
df = pd.json_normalize(
data,
errors="ignore"
)
errors="ignore"を指定すると、存在しない項目があっても処理を継続できます。
json_normalizeでJSON APIのデータを処理する
json_normalize()は、Web APIから取得したJSONデータを処理するときにもよく利用されます。
例えばAPIから次のようなデータを取得したとします。
import requests
import pandas as pd
response = requests.get("https://example.com/api/users")
data = response.json()
df = pd.json_normalize(data)
print(df)
APIによっては、次のような複雑なJSONが返されます。
{
"users": [
{
"id": 1,
"name": "田中"
},
{
"id": 2,
"name": "佐藤"
}
]
}
この場合は、
df = pd.json_normalize(data["users"])
とすることで、usersの配列をDataFrameに変換できます。
JSONファイルを読み込んでjson_normalizeを使う
JSONファイルをPythonで読み込む場合は、jsonモジュールを利用できます。
import json
import pandas as pd
with open("data.json", encoding="utf-8") as f:
data = json.load(f)
df = pd.json_normalize(data)
print(df)
大量のJSONデータを分析するときにも便利な方法です。
json_normalizeとDataFrameの違い
単純なJSONであれば、pd.DataFrame()でも問題ありません。
df = pd.DataFrame(data)
一方、ネストしたJSONの場合は、
df = pd.json_normalize(data)
のほうが適しています。
| 方法 | 単純なJSON | ネストしたJSON | リストの展開 |
|---|---|---|---|
pd.DataFrame() |
◎ | △ | △ |
pd.json_normalize() |
◎ | ◎ | ◎ |
階層構造を持つJSONを扱うなら、まずjson_normalize()を検討するとよいでしょう。
json_normalizeでよくあるエラー
KeyErrorが発生する
record_pathに指定したキーが存在しないと、エラーになることがあります。
例えば、
df = pd.json_normalize(
data,
record_path="orders"
)
としているのに、JSONにordersが存在しないケースです。
まず、
print(data)
などで実際のJSON構造を確認しましょう。
JSONの構造がデータごとに違う
例えば、あるデータには、
{
"name": "田中",
"address": {
"city": "東京"
}
}
がある一方で、別のデータには、
{
"name": "佐藤"
}
しかない場合があります。
このようなJSONを扱う場合は、欠損値が発生することを前提に処理する必要があります。
json_normalize()では、存在しない項目がNaNになる場合があります。
json_normalizeで作成したDataFrameをCSVにする
DataFrameに変換した後は、CSVファイルとして保存できます。
df.to_csv(
"output.csv",
index=False,
encoding="utf-8-sig"
)
これにより、Excelなどでも扱いやすいCSVファイルを作成できます。
json_normalizeの主な引数
json_normalize()では、さまざまな引数を利用できます。
代表的なものは以下の通りです。
| 引数 | 内容 |
|---|---|
data |
変換するJSONデータ |
record_path |
行として展開するリスト |
meta |
親階層から取得する項目 |
meta_prefix |
metaの列名に付ける接頭辞 |
record_prefix |
レコードの列名に付ける接頭辞 |
errors |
エラー処理方法 |
sep |
階層を区切る文字 |
max_level |
展開する階層の深さ |
max_levelで展開する階層を制限する
JSONが非常に深い階層になっている場合、max_levelを利用できます。
例えば、
df = pd.json_normalize(
data,
max_level=1
)
とすると、展開する階層を制限できます。
JSONをすべてフラット化するのではなく、必要な階層だけ展開したい場合に便利です。
json_normalizeを使うときのポイント
json_normalize()を使うときは、次の3点を意識するとよいでしょう。
1. まずJSONの構造を確認する
print(data)
JSONのどの階層にデータがあるかを確認します。
2. リストを展開するときはrecord_pathを使う
pd.json_normalize(
data,
record_path="items"
)
3. 親データも必要ならmetaを使う
pd.json_normalize(
data,
record_path="items",
meta=["id", "name"]
)
この3つを理解するだけでも、かなり複雑なJSONを処理できるようになります。
json_normalizeまとめ
pandas.json_normalize()は、JSONデータをDataFrameへ変換するときに非常に便利な関数です。
特に、APIなどから取得したネスト構造のJSONをデータ分析に利用するときに活躍します。
基本的な使い方は、
import pandas as pd
df = pd.json_normalize(data)
です。
さらに、
pd.json_normalize(
data,
record_path="items",
meta=["id", "name"],
sep="_"
)
のようにすれば、リストの展開、親データの取得、列名の変更なども行えます。
「JSONをDataFrameにしたい」ならjson_normalize()、「ネストしたJSONを表形式に整理したい」なら特にjson_normalize()を覚えておくと便利です。
PythonでAPI連携やデータ分析、スクレイピングなどを行う場合は、ぜひ使いこなしてみてください。







