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です。
| age | name | |
|---|---|---|
| 0 | 30 | soudegesu |
| 1 | 10 | hogehoge |
では早速やってみましょう。
案1: apply と json_normalize を使う
まず、 apply と json_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()| age | name | |
|---|---|---|
| 0 | 30 | soudegesu |
| 1 | 10 | hogehoge |
ここでポイントになるのは、 df['json_col'] で取得した Series オブジェクトに対して
- apply 関数を使って 各行のデータを辞書型に変換する
- json_normalize を使ってキーを展開した
DataFrameに変換する
の2点になります。
案2:converters オプションと json_normalize を使う
次はデータを csv ファイルから読み込むことを前提として話をします。
Pandas の read_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()こちらの方法でも変換できました。
| age | name | |
|---|---|---|
| 0 | 30 | soudegesu |
| 1 | 10 | hogehoge |
ネストしている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.area | age | name | |
|---|---|---|---|
| 0 | 東京 | 30 | soudegesu |
| 1 | 北海道 | 10 | hogehoge |
列名が [キー名].[キー名] で展開されることがわかります。
配列が含まれる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()| age | name | tag | |
|---|---|---|---|
| 0 | 30 | soudegesu | [おっちょこちょい, よく寝る] |
| 1 | 10 | hogehoge | [せっかち, よく食べる] |
なるほど。展開はされるが、列に配列のまま出力される というところですね。
まとめ
今回は DataFrame の列データが JSON文字列 の場合の処理の仕方をまとめました。
ステップとしては以下の2つを踏むことで、JSON内のデータを複数の列に展開することができます。
- 文字列を辞書型に変換する(
applyやconvertersオプション) - 辞書型を複数列に展開する(
json_normalize)
ネストしたJSONでも問題なく展開されますが、JSONに配列が含まれる場合には別途展開するロジックが必要になりそうです。
