PandasでJSONファイルを保存するときの注意点
個人的にはTensorFlowでモデリングするようになってから、numpyを触る頻度が高くなって、それに伴いpandasを触る機会が減っていった。
データの可視化もpyplotとかseaboneとかを使って、可視化の方法を調べながら模索している状況が増えていった。
しかし、先日副業の案件で学習データをサクッと可視化させようと思ったときに選んだのは、pandasだった。
やはりpandasは優秀かな
テキストデータを読み込んで、異常値を探すとかその場でフィルタリングしようかと思うと、
やはりpandasは楽だなと改めて思たった。(ただnumpy力が低いだけかもしれないが…)
例えば、とりあえずテキストに保存したデータセットをDataFrameに読み込んで、
データセットの概要を知りたいなーと思ったら、
df.describe()
とすれば、カラム毎の最大値・最小値、四分位数とかを出してくれるし、
histグラムで可視化したいなーとおもったら、
df.plot.hist(y=[<可視化するカラム名>], bins=<ビン数>)
とすれば、指定したカラムだけのヒストグラムが可視化できて、すごく楽だった。
分布はどのような形なのか、どの範囲で異常値を切り出すのかなど判断して
そのままDataFrameでフィルターすればいいので、短時間でデータセットのチェックと更新ができた。
DataFrameの保存には注意が必要
前提
前提として、データセットはJSON形式で保存しており、
すでに実験するノートブックを用意してある、としてます。
なので、同じJSONの形式で保存することで実験のノートブックを再利用することが前提です。
問題点
通常、PythonでdictionaryをJSONとして保存した場合、
import json dict_list = [] for i in range(10): dict_obj = {} dict_obj["single"] = i dict_obj["double"] = i * 2 dict_obj["square"] = i * i dict_list.append(dict_obj) with open('dict2json.json', 'w') as f: json.dump(dict_list, f)
のような処理になる。 そして、この場合テキストにはざっくりと
[{"single": 0, "double": 0, "square": 0}, {"single": 1, "double": 2, "square": 1}, {"single": 2, "double": 4, "square": 4}, {"single": 3, "double": 6, "square": 9}, {"single": 4, "double": 8, "square": 16}, {"single": 5, "double": 10, "square": 25}, {"single": 6, "double": 12, "square": 36}, {"single": 7, "double": 14, "square": 49}, {"single": 8, "double": 16, "square": 64}, {"single": 9, "double": 18, "square": 81}]
このような形式で保存されている。
いわゆる、key-valueが配列に格納されている形である。
なので、配列の1要素が1行(1レコード)のデータを表現している。
そして、何も意識せずにDataFrameをJSONファイルとして保存すると痛い目に遭った。 それが今回の教訓だった。
PandasでJSONを読み込むには、
import pandas as pd df = pd.read_json('dict2json.json')
とすればよい。 そして、このDataFrameをJSONとして保存する場合、以下のように書けば良い。
df.to_json("df2json.json")
人によりけりだとは思うが、簡単で直感的だ。ただし、この場合保存されたファイルの中身は、
{"double":{"0":0,"1":2,"2":4,"3":6,"4":8,"5":10,"6":12,"7":14,"8":16,"9":18},"single":{"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9},"square":{"0":0,"1":1,"2":4,"3":9,"4":16,"5":25,"6":36,"7":49,"8":64,"9":81}}
となる。
形としては、カラム毎に、 "index: value"
の形で保存されている。
この場合、保存されたファイルを
with open('df2json.json') as f: json_data = json.load(f)
として読み込むと、1レコードずつとして読み込まれず、keyが想定していたものと異なる結果になる。
Key-Valueの形式で保存するには、
DataFrameをkey-valueの形式のJSONに保存するときには orient
オプションに record
を指定する必要があることに注意する。
df.to_json(filtered_data_filepath, orient='records')
そうすると、
[{"double":0,"single":0,"square":0},{"double":2,"single":1,"square":1},{"double":4,"single":2,"square":4},{"double":6,"single":3,"square":9},{"double":8,"single":4,"square":16},{"double":10,"single":5,"square":25},{"double":12,"single":6,"square":36},{"double":14,"single":7,"square":49},{"double":16,"single":8,"square":64},{"double":18,"single":9,"square":81}]
と保存された。