PandasでJSON形式の列データを複数列に展開する

PandasでJSON形式の列データを複数列に展開する
目次

過去、Pandas を使った列データの処理について様々書きました。

今回もデータの下処理のうちの1つ、「列データがJSON 文字列の場合」を考えます。

JSON文字列が格納されている列データを複数列に展開したい

以下のように、列名が json_col という DataFrame を準備します。 なお、 json_col 列の中身は JSON 形式の文字列 であるとします。

1import pandas as pd
2
3data = {
4    'json_col': ['{"name": "soudegesu", "age": "30"}', '{"name": "hogehoge", "age": "10"}']
5}
6
7df = pd.DataFrame(data)
8df.head()
json_col
0{“name”: “soudegesu”, “age”: “30”}
1{“name”: “hogehoge”, “age”: “10”}

今回のゴールは json_col 列を持った DataFrame を、 キー毎に別の列へ展開した DataFrame に変換すること とします。

以下になればOKです。

agename
030soudegesu
110hogehoge

では早速やってみましょう。

案1: applyjson_normalize を使う

まず、 applyjson_normalize の2つの関数を使う方法を紹介します。

これは、既に読み込まれた DataFrame に対して適用する場合に有用です。

1from pandas.io.json import json_normalize
2import json 
3
4df_json = json_normalize(df['json_col'].apply(lambda x: json.loads(x)))
5df_json.head()
agename
030soudegesu
110hogehoge

ここでポイントになるのは、 df['json_col'] で取得した Series オブジェクトに対して

  • apply 関数を使って 各行のデータを辞書型に変換する
  • json_normalize を使ってキーを展開した DataFrame に変換する

の2点になります。

案2:converters オプションと json_normalize を使う

次はデータを csv ファイルから読み込むことを前提として話をします。

Pandasread_csv 関数にある converters というオプションを使います。 イメージとしては、案1の apply での変換処理を、csv ファイルのデータを DataFrame に変換するタイミングで行う感じです。

 1from pandas.io.json import json_normalize
 2import json 
 3import pandas as pd
 4
 5df = pd.read_csv(
 6    './hoge.csv',  #元データがhoge.csvに保存されているとします
 7    converters={column: json.loads for column in ['json_col']},
 8)
 9
10df_json = json_normalize(df['json_col'])
11df_json.head()

こちらの方法でも変換できました。

agename
030soudegesu
110hogehoge

ネストしているJSONはどのように展開されるのか

先程、2つの方法を紹介しましたが、 ネストしたJSONはどのように展開してくれるのか 気になりますよね。 試してみましょう。

1import pandas as pd
2
3data = {
4    'json_col': ['{"name": "soudegesu", "age": "30", "address": {"area": "東京"}}', '{"name": "hogehoge", "age": "10", "address": {"area": "北海道"}}']
5}
6df = pd.DataFrame(data)
7df_json = json_normalize(df['json_col'].apply(lambda x: json.loads(x)))
8df_json.head()
address.areaagename
0東京30soudegesu
1北海道10hogehoge

列名が [キー名].[キー名] で展開されることがわかります。

配列が含まれるJSONはどのように展開されるのか

最後に 配列が含まれるJSONはどのように展開されるのか を確認します。

1import pandas as pd
2
3data = {
4    'json_col': ['{"name": "soudegesu", "age": "30", "tag": ["おっちょこちょい", "よく寝る"]}', '{"name": "hogehoge", "age": "10", "tag": ["せっかち", "よく食べる"]}']
5}
6df = pd.DataFrame(data)
7df_json = json_normalize(df['json_col'].apply(lambda x: json.loads(x)))
8df_json.head()
agenametag
030soudegesu[おっちょこちょい, よく寝る]
110hogehoge[せっかち, よく食べる]

なるほど。展開はされるが、列に配列のまま出力される というところですね。

まとめ

今回は DataFrame の列データが JSON文字列 の場合の処理の仕方をまとめました。 ステップとしては以下の2つを踏むことで、JSON内のデータを複数の列に展開することができます。

  1. 文字列を辞書型に変換する(applyconverters オプション)
  2. 辞書型を複数列に展開する(json_normalize

ネストしたJSONでも問題なく展開されますが、JSONに配列が含まれる場合には別途展開するロジックが必要になりそうです。