一人十郷 - takuminasuno.com一人十郷
takuminasuno.com
ビジネス
2019/06/12

【Pythonデータ活用】CSVファイルをJSONファイル、XMLファイルに変換して出力してみる

 

前回の投稿では『Pythonでpandasを使ってExcelファイルを読み込んでcsvファイルを出力するまで』ということで、Pythonの環境構築からCSV出力までの段取りを書いてみました。

CSV出力ができればデータ分析の現場としてはどうにかなってしまうことが多いといえば多いですが、JSON形式やXML形式でも出力できると色々とやれることの幅が広がります。なので今回の投稿では各データ形式のメリット・デメリットを簡単に比較しつつ、実際にコードを書いて実行するところまでを書いてみたいと思います。

 

データ形式の比較

どのデータ形式もデータ活用の現場でバリバリの現役ではありますが、だからこそ、それぞれのデータ形式に適した活用シーンがあります。そのあたりを考慮しつつ、CSV, XML, JSONの順に特徴を見ていきます。(※なお下記特徴は、PythonだけでなくVBAでも処理することを念頭に書いています。)

特徴
CSV
  • データ容量が軽く、処理も速い。
  • Pythonでは『pandas』ライブラリを使うことで非常にシンプルに扱うことができる。
  • 列が固定であり、柔軟なデータ構造を設計できない。
  • VBAでも処理できるが、何も考慮せずにファイルを開くと書式が崩れて思わぬミスを誘発することがある。
  • エンコード形式を考慮する必要がある。
XML
  • 階層によるデータ構造を自由に設計でき、値とは別に属性も自由にセットできる。
  • 文字列の塊なので、Excelやスプレッドシートなどの1セルに階層データとしてまとめて放り込むこともできる。
  • VBAでも『Microsoft XML』系のライブラリを使うことで、自由度高く読み書き(CRUD全て)ができる。
  • CSVと比較して、書き方が冗長的で、データ容量が重く、処理も遅くなりがち。
  • Pythonでは『xml.etree.ElementTree』ライブラリを使って処理できるが、『pandas』ライブラリでのJSON処理ほど洗練されておらず、Pythonの真価を発揮しづらい。
JSON
  • 階層によるデータ構造を自由に設計でき、配列を含めたデータ型の表現が豊富である。
  • 文字列の塊なので、Excelやスプレッドシートなどの1セルに階層データをまとめて放り込むことができる。
  • 書き方はXMLよりはシンプル。処理もXMLよりは速い。
  • Pythonではその名の通り『json』ライブラリで諸々の処理ができ、『pandas』ライブラリのDataFrameとも相性が良い。
  • CSVと比較して、書き方が冗長的で、データ容量が重く、処理も遅くなりがち。(XMLよりはマシ)
  • VBAでの扱いがイマイチ。一般公開されている『VBA-JSON』や『cJobject』などのライブラリで読み書きはできるが、VBAの多重連想配列の下層が更新できない制約のため、CRUD機能のうちUDが極めて苦手。(※VBA×JSONではScriptControlオブジェクトでパースする方法もあるが、32bitの実行環境でしか使えないうえ呼び出し文が冗長的であるため割愛。)

やはりPythonで使うならCSV or JSONの2択ですね。わざわざJSONではなくXMLを使うべきシーンはなかなか思いつきません。とはいえ両方変換できるに越したことはないので、タイトル通りJSONとXMLの両方に変換してみたいと思います。

 

変換スクリプトを書く

ということで前回の続きで変換スクリプトを早速書いてみます。

(※ちなみにCSVの読み込みとJSON処理に使っている『pandas』ライブラリについて知りたい方は Python Data Analysis Library - pandas を、XML処理に使っている『xml.etree.ElementTree』ライブラリについて知りたい方は Python Software Foundationをご覧ください。)

 

順番としては、最初にJSON形式、次にXML形式にて出力しました。

JSON出力はpandasの基本機能として提供されているので、圧倒的に楽ですね。一般的なフォーマットはorient="records"だと思いますが、大規模なCSV的データの場合はorient="split"にすることでデータをより軽快に扱うことができると思います。

ちなみに出力されたデータを実際に見てみると、

JSON形式, orient="records"

[{"age":"0~4\u6b73","sex":"total","yyyymm":201905,"value":4810000},{"age":"0~4\u6b73","sex":"male","yyyymm":201905,"value":2470000},{"age":"0~4\u6b73","sex":"female","yyyymm":201905,"value":2350000},{"age":"0~4\u6b73","sex":"total","yyyymm":201812,"value":4827000},{"age":"0~4\u6b73","sex":"male","yyyymm":201812,"value":2473000},{"age":"0~4\u6b73","sex":"female","yyyymm":201812,"value":2354000},{"age":"0~4\u6b73","sex":"total-ja","yyyymm":201812,"value":4750000},{"age":"0~4\u6b73","sex":"male-ja","yyyymm":201812,"value":2433000},{"age":"0~4\u6b73","sex":"female-ja","yyyymm":201812,"value":2317000},{"age":"5~9\u6b73","sex":"total","yyyymm":201905,"value":5130000},{"age":"5~9\u6b73","sex":"male","yyyymm":201905,"value":2630000},{"age":"5~9\u6b73","sex":"female","yyyymm":201905,"value":2500000},{"age":"5~9\u6b73","sex":"total","yyyymm":201812,"value":5172000},{"age":"5~9\u6b73","sex":"male","yyyymm":201812,"value":2648000},{"age":"5~9\u6b73","sex":"female","yyyymm":201812,"value":2524000}, ...中略...}

 

JSON形式, orient="split"

{"columns":["age","sex","yyyymm","value"],"index":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188],"data":[["0~4\u6b73","total",201905,4810000],["0~4\u6b73","male",201905,2470000],["0~4\u6b73","female",201905,2350000],["0~4\u6b73","total",201812,4827000],["0~4\u6b73","male",201812,2473000],["0~4\u6b73","female",201812,2354000],["0~4\u6b73","total-ja",201812,4750000],["0~4\u6b73","male-ja",201812,2433000],["0~4\u6b73","female-ja",201812,2317000],["5~9\u6b73","total",201905,5130000],["5~9\u6b73","male",201905,2630000],["5~9\u6b73","female",201905,2500000],["5~9\u6b73","total",201812,5172000],["5~9\u6b73","male",201812,2648000],["5~9\u6b73","female",201812,2524000], ...中略...}

という構造の違いがあります。なおファイル容量はrecordsが12.7KB、splitが8.09KBとなり、splitにすることで約3分の2に減りました。もちろんフォーマットが異なるので処理する際のコードも異なるわけですが、データ容量が大きくなればなるほどこの恩恵は大きくなりますね。

 

さて、続いてXML出力です。私が知る限り、pandasのDataFrameを即座にXML出力する関数は存在しないので、実際にXMLのツリー構造を作ってからファイルとして出力する必要があります。ElementTreeを使えば直感的にツリー構造を作ることはできますが、まあ何も考えずにできるJSONと比べれば少し面倒な気はします。

なお上のコードでは、JSON形式で言うところのrecordsフォーマットをイメージしてツリー構造を作りました。出力時にはunicode指定して、日本語文字を日本語に変換しての出力なので、少し読みやすいです。ちなみに出力された実際のデータを見ると、

XML形式

<root><records><record><age>0~4歳</age><sex>total</sex><yyyymm>201905</yyyymm><value>4810000</value></record><record><age>0~4歳</age><sex>male</sex><yyyymm>201905</yyyymm><value>2470000</value></record><record><age>0~4歳</age><sex>female</sex><yyyymm>201905</yyyymm><value>2350000</value></record><record><age>0~4歳</age><sex>total</sex><yyyymm>201812</yyyymm><value>4827000</value></record><record><age>0~4歳</age><sex>male</sex><yyyymm>201812</yyyymm><value>2473000</value></record><record><age>0~4歳</age><sex>female</sex><yyyymm>201812</yyyymm><value>2354000</value></record><record><age>0~4歳</age><sex>total-ja</sex><yyyymm>201812</yyyymm><value>4750000</value></record><record><age>0~4歳</age><sex>male-ja</sex><yyyymm>201812</yyyymm><value>2433000</value></record><record><age>0~4歳</age><sex>female-ja</sex><yyyymm>201812</yyyymm><value>2317000</value></record><record><age>5~9歳</age><sex>total</sex><yyyymm>201905</yyyymm><value>5130000</value></record><record><age>5~9歳</age><sex>male</sex><yyyymm>201905</yyyymm><value>2630000</value></record><record><age>5~9歳</age><sex>female</sex><yyyymm>201905</yyyymm><value>2500000</value></record><record><age>5~9歳</age><sex>total</sex><yyyymm>201812</yyyymm><value>5172000</value></record><record><age>5~9歳</age><sex>male</sex><yyyymm>201812</yyyymm><value>2648000</value></record><record><age>5~9歳</age><sex>female</sex><yyyymm>201812</yyyymm><value>2524000</value></record> ...中略...</root>

こんな感じに並びます。JSONと違ってデータ型が区別されないので、全て文字列扱いです。今回は使っていないですが、これに属性を付与してよりリッチなデータ表現にすることも可能です。(データが散らばるので私はあまり使いませんが・・・)

 

まとめ

ということで、『【Pythonデータ活用】CSVファイルをJSONファイル、XMLファイルに変換して出力してみる』と題して各形式を比較しつつ、実際に変換するコードを書いて試してみました。

各形式にメリット・デメリットがあるのでどれが正義というわけではありませんが、現場に合った最適な形式を選定できること、その形式のもとで最適なデータ構造を設計できること、そして万一の際に変換ができることが、データ活用において大切なことかなと思いました。

 

とりわけJSONやXMLは、後から色々とデータ構造を追加/変更しやすい点がメリットであるとともに、日々の運用によってデータ構造が滅茶苦茶になりやすいという裏の意味がデメリットにもなりえます。その意味では初期にどこまで先を見通したデータ構造を設計できるかが重要だと思いつつも・・・このあたり、実務書としてあまり良い教科書的なものに巡り合えていないので、

データベース設計のベストプラクティスを把握しつつ、オントロジーを参考に業務要件を再整理して、あとはどこまで精緻・厳密なデータであるべきか実効性とコストパフォーマンスを鑑みながら調整して落としどころを探すくらいしか思い付かないので、何か良書があればご指南くださいませ。。

同じカテゴリーの投稿もどうぞ!
ConoHaのVPSを使うこのブログが突如使えなくなった後に復旧した話
ビジネス
2021/07/04
ConoHaのVPSを使うこのブログが突如使えなくなった後に復旧した話
業務のためにSaaSを選定するテックリサーチの思考の流れを言語化してみた
ビジネス
2021/05/01
業務のためにSaaSを選定するテックリサーチの思考の流れを言語化してみた
Pythonによるデータ処理の基本まとめ【pandas, json, datetime, gzipなど】
ビジネス
2021/04/11
Pythonによるデータ処理の基本まとめ【pandas, json, datetime, gzipなど】
アジャイルとスクラムについて、原理原則と基本を押さえる【2020年12月版】
ビジネス
2020/12/10
アジャイルとスクラムについて、原理原則と基本を押さえる【2020年12月版】
IT&マーケティング界隈でプロジェクトマネージャーとして生き残るためのサバイバルハック【2020年9月版】
ビジネス
2020/09/16
IT&マーケティング界隈でプロジェクトマネージャーとして生き残るためのサバイバルハック【2020年9月版】
ブログ著者について
那須野 拓実(なすの たくみ)。たなぐら応援大使(福島県棚倉町)。トリプレッソを勝手に応援する人。ネイチャーフォト中心の多言語ブログを書いてます。本業はIT&マーケティング界隈でナレッジマネジメントとかデータ分析とかの何でも屋。半年間の育休明けで、家事育児と外働きのバランスを模索中。