yskma’s blog

日々の作業の備忘録@株式会社ビズオーシャン

ネストのあるjsonデータをpandasでフラットに扱う

ネストの深いデータ

簡単にデータを取り込んで扱えるpandasだが、下記のようにネストが深いと勝手が悪い。

nested.json
{
    col1:{row1:1,row2:x,row3:{id:1,age:20,data:{a:1,b:2}}},
    col2:{row1:2,row2:y,row3:{id:2,age:23,data:{a:3,b:4}}}
}

そのままとりこむとこんな感じ

import pandas as pd

f = open(filepath, 'r')
data = json.load(f)
df = pd.DataFrame(data)
col1 col2
row1 1 2
row2 x y
row3 {id:1,age:20,data:{a:1,b:2}} {id:2,age:23,data:{a:3,b:4}}

データの転置

列ごとに1件とするデータだとわかる。そのままだと扱いづらいので転置する。

df_t = df.T
row1 row2 row3
col1 1 x {'age': '20', 'data': {'b': '2', 'a': '1'}, 'id': '1'}
col2 2 y {'age': '23', 'data': {'b': '4', 'a': '3'}, 'id': '2'}

json_normalizeでフラットにする

あとはrow3の要素をそれぞれ取り出して一覧したい。
そんなときはjson_normalizeを利用すると便利。

import pandas as pd
from pandas.io.json import json_normalize

def extract_data(d):
    result = json_normalize(d)
    result = result.iloc[0, :]  # seriesに変換
    return result  # seriesで返すこと

f = open(filepath, 'r')
data = json.load(f)
df = pd.DataFrame(data)
df_t = df.T
df_flatten = pd.concat([df_t, df_t.row3.apply(extract_data)], axis=1)

データフレームに入れるとrow3が辞書型の文字列として取り込まれるので、
作成した関数内でjson_normalizeを使ってデータフレームに変換。
そのままだと元のdf_tに返せないのでseriesに変換して渡す。
pd.concatで元のdf_tとrow3のデータから作ったデータフレームをくっつける。

これでめでたく一つのフラットなデータフレームとして扱える。

row1 row2 row3 age data.a data.b id
col1 1 x {'age': '20', 'data': {'b': '2', 'a': '1'}, 'i... 20 1 2 1
col2 2 y {'age': '23', 'data': {'b': '4', 'a': '3'}, 'i... 23 3 4 2

まだ試していないけれど、もっとネストが深くても同じ要領で操作を繰り返せばなんとかなりそう。