こんにちは。学生アルバイトのohkiです。みなさん、テーブル構造というとどんなものを思い浮かべるでしょうか?おそらく多くの方が横持ち構造を思い浮かべるのではないかと思います。確かに横持ち構造の方が見やすいですが、縦持ち構造の方が扱いやすい場合もあります。そこで、今回はcsvファイルを横持ち構造から縦持ち構造に変換する方法を紹介します。

縦持ちとは

カラムを横に並べたテーブルのことを横持ちというのに対して、縦持ちは1行に1つの情報のみを格納したテーブルのことです。縦持ちのメリットとしては、カラムの追加や削除に柔軟に対応できます。例えば、カラムを追加するときに、横持ちの場合はテーブル定義を変更する必要がありますが、縦持ちの場合は、テーブル定義はそのままで、行が増えるだけです。また、テーブルがスパースな場合は、縦持ちの方が行数が少なくなり、コンパクトになります。

横持ちテーブル
name gender age flag
Tom male 20 0
John male 22 0
縦持ちテーブル
name カラム
Tom name Tom
Tom gender male
Tom age 20
Tom flag 0
John name John
John gender male
John age 22
John flag 0

Rubyで縦持ち構造に変換する

では、csvファイルを縦持ち構造に変換していきたいと思います。今回は以下の横持ちcsvファイルを例に実行していきたいと思います。

#meibo.csv
"name","gender","age","flag"
"Tom","male","20","0"
"John","male","22","0"
"Paul","male","43","1"
"Alice","female","31","0"

以下が実行コードになります。元の横持ちcsvを1行ずつ読み込んでいき、nameカラムを属性として縦持ちに変換していきます。また、”headers: true”を与えることで、先頭行をヘッダとして扱うことができます。ここでの”csv_row”のクラスはCSV::Rowであり、ハッシュのようにカラム名でフィールドにアクセスする事ができます。

require 'csv'

def unpivot_csv(csv_name, output_csv_io=STDOUT)
  CSV.foreach(csv_name, encoding: 'BOM|UTF-8', headers: true) do |csv_row|
    csv_row.each do |head, field|
      output_csv_io.puts( [ csv_row['name'], head, field ].join(",") )
    end
  end
end

unpivot_io = File.open('./unpivot_meibo.csv','w')
unpivot_csv('./meibo.csv', unpivot_io)
unpivot_io.close

生成ファイルは以下のようになります。

#unpivot_meibo.csv
Tom,name,Tom
Tom,gender,male
Tom,age,20
Tom,flag,0
John,name,John
John,gender,male
John,age,22
John,flag,0
Paul,name,Paul
Paul,gender,male
Paul,age,43
Paul,flag,1
Alice,name,Alice
Alice,gender,female
Alice,age,31
Alice,flag,0

まとめ

今回はcsvファイルの縦持ち変換について紹介しました。これからは、用途に合わせてcsvの構造を使い分けていきましょう。

Pocket