KaggleのiMaterialist Challengeで画像URLとラベル情報が載っているデータがJSON形式で42MBある。

普段私は Julia 言語を使っていて、JSONだと情報が扱いにくいので、DataFrame型にしたいが、そうするには一度CSVファイルに変換してから処理したい。

実際のJSONデータ

train.json

{
  "images": [
    {
      "url": [
        "https://img13.360buyimg.com/imgzone/jfs/t2857/351/510705008/279959/4e27dce0/57171f60N523c940e.jpg"
      ],
      "image_id": 1
    },
    "...": "19万個データが続く",
  ],
  "annotations": [
    {
      "image_id": 1,
      "label_id": 5
    },
    "...": "19万個のデータが続く",
  ]
}

面倒な点

  • images と annotations で分かれてる
  • url の中は配列になってる

なので、train_images.csv と train_annotaions.csv に分割して、urlの配列の中身も必ずと言っていいほど1つしか入ってないので、中身は展開しておきたい。

対処方法

jq コマンド

jq は Linux のターミナル上でJSONの値を扱える。出力も自分で指定できるのでCSV形式で出すことができる。

実行したコマンド

$ cat train.json | jq '.images[] | "\(.url[0]),\(.image_id)"' | sed 's/"//g' >> train_images.csv
$ cat train.json | jq '.annotations[] | "\(.image_id),\(.label_id)"' | sed 's/"//g' >> train_annotations.csv

cat したJSONファイルの中身を jq で読み込みCSVの形で出力。 jqだと行毎に "(ダブルコーテーション) が出てくるので sed で取り除いている。 実行も40MBのファイルでも2,3秒で終わってしまう。

最初は、BigQueryにJSON読ませてとか考えてたけど、CUI強い。

おまけ: Juliaで生成したファイルを呼ぶ

header情報は記載していないので、読み込む時に設定する。

using DataFrames
using FileIO

annotations = DataFrame(load("./input/train_annotations.csv", header_exists=false, colnames=["url","image_id"]))