データベースからデータをロードするデータフレームdf
があります。ほとんどの列はJSON文字列ですが、一部の列はJSONのリストです。例えば:
id name columnA columnB
1 John {"dist": "600", "time": "0:12.10"} [{"pos": "1st", "value": "500"},{"pos": "2nd", "value": "300"},{"pos": "3rd", "value": "200"}, {"pos": "total", "value": "1000"}]
2 Mike {"dist": "600"} [{"pos": "1st", "value": "500"},{"pos": "2nd", "value": "300"},{"pos": "total", "value": "800"}]
...
ご覧のとおり、すべての行が列のjson文字列で同じ数の要素を持っているわけではありません。
私がする必要があるのは、id
やname
などの通常の列をそのままにして、json列を次のようにフラット化することです。
id name columnA.dist columnA.time columnB.pos.1st columnB.pos.2nd columnB.pos.3rd columnB.pos.total
1 John 600 0:12.10 500 300 200 1000
2 Mark 600 NaN 500 300 Nan 800
私はjson_normalize
を次のように使用しようとしました:
from pandas.io.json import json_normalize
json_normalize(df)
しかし、keyerror
にはいくつかの問題があるようです。これを行う正しい方法は何ですか?
これは、カスタム関数を使用して json_normalize()
を再度使用して、_json_normalize
_関数で認識される正しい形式でデータを取得するソリューションです。
_import ast
from pandas.io.json import json_normalize
def only_dict(d):
'''
Convert json string representation of dictionary to a python dict
'''
return ast.literal_eval(d)
def list_of_dicts(ld):
'''
Create a mapping of the tuples formed after
converting json strings of list to a python list
'''
return dict([(list(d.values())[1], list(d.values())[0]) for d in ast.literal_eval(ld)])
A = json_normalize(df['columnA'].apply(only_dict).tolist()).add_prefix('columnA.')
B = json_normalize(df['columnB'].apply(list_of_dicts).tolist()).add_prefix('columnB.pos.')
_
最後に、共通インデックスのDFs
を結合して以下を取得します。
_df[['id', 'name']].join([A, B])
_
EDIT:-@MartijnPietersのコメントによると、json文字列のデコードの推奨方法は json.loads()
を使用すること。データソースがJSONであることがわかっている場合、 ast.literal_eval()
を使用する場合に比べてはるかに高速です。
最も速いのは次のようです:
json_struct = json.loads(df.to_json(orient="records"))
df_flat = pf.io.json.json_normalize(json_struct)