Edited at

RubyでCSVを処理する(駅データの重複レコードの検出)

More than 1 year has passed since last update.


やりたかったこと

駅データ.jpさんから駅データをダウンロードしてきて重複した駅を消したかった


CSVを整理する方法


  1. 文字コード(JIS)に気をつけてエクセルで頑張る(戦前からある方法)

  2. CSV系アプリを使う(専用アプリだと文字化けしないけどやれることが少ない)

  3. Rubyで頑張る(作る!)


1. エクセルで頑張る

エクセル先輩は実に素晴らしい。ほぼなんでも出来る。

重複削除もできるしソートなども出来る。あれは表計算ソフトというのは嘘だと思う。

尚、スプレッドシートも重複削除などは出来るんですが、エクセルほど簡単にはいかないっぽい。

Unique関数、Google App Script使うとやれるっぽい。

が、僕個人としてrubyでやっちゃったほうが早そう!と思ってスプレッドシートは回避しちゃいました(どなたか素敵なやり方あったら教えてくださいw)。


2. CSV系アプリ

なんか良いのあったら教えてください(汗


3. Rubyで頑張る

rails consoleを立ち上げてCSVデータをとりあえず変数に格納。

だいぶ古い記事なんだけど

Ruby標準添付ライブラリcsvのCSV.tableメソッドが最強な件について

で解説されているCSVを扱う系の「.table」が素晴らしいと思った。

table = CSV.read('station.csv')

こんな感じでreadメソッドでもいいんですが、

table = CSV.table('station.csv')

と、CSVライブラリのtableメソッドを使うとすごく便利でした。


CSV.tableの何が便利か?

table[0]とかtable[1]とかでreadメソッドでも同じようなデータが出てきます。

が、readでやるとただの配列。

tableでやるとRowでラッピングされて出てきます。

table = CSV.table('station.csv')

table[0]
=> #<CSV::Row id:1 name:"東京駅" address:"東京都千代田区丸の内一丁目9-1" ......

table[0]とかだとこんな感じ。tableメソッドでなくreadメソッドとほぼ同じ出力。

table = CSV.table('station.csv')

table[:name]
=> ["東京駅", "新横浜駅", "品川駅", "東京駅", "小田原駅", "熱海駅", "三島駅", "品川駅", "新富士駅", ......

CSVの縦列、カラム名を0,1などの代わりに入れると縦列で抽出が出来ます。すごい。

これで駅名がかぶっているレコードの抽出ができるわけです。すごい(2度目)。


さて本題!「rubyを使って重複データの抽出」

table = CSV.table('station.csv')

table[:name].group_by{|i| i}.reject{|key,value| value.one?}.keys
=> ["東京駅", "品川駅", ......]


  1. group_byして、同じ値を持っているkeyを探す。

  2. rejectしてvalue側が1つしか該当しなかったレコードを除外(ここでは重複だけ欲しいから)

  3. keyの名前だけ出す

以上で、重複しているレコードを出せる。


よくわかる解説(わからなかったらゴメン)

group_byすると、

table[:station].group_by{|i| i}

=> {"東京駅"=>["東京駅", "東京駅", "東京駅"], "新横浜駅"=>["新横浜駅"], "品川駅"=>["品川駅", "品川駅"], ......

こんな感じで、まさにグルーピングできる。

んで、これに対してrejectすることで、

table[:station].group_by{|i| i}.reject{|key,value| value.one?}.keys

=> {"東京駅", "品川駅", ......

単一回答(重複してないデータ=ここでは品川駅)を除外することで重複した項目だけ表示できる。

重複してたら1個にしちゃいなさい!みたいなこともできるんですが、一応数十万行をそれでミスったら怖かったので、一応ラスト目検をしたほうがいいだろうと思って抽出までで留まっています。


駅データ関係豆知識

駅データ.jpから駅および路線などのデータが無料でダウンロード可能。

ただ、一部が欠けていて、有料にすることでフリガナなど足らないデータが補完された全データが取れます。


有料データと無料データどちらも、仕様は同じです。

無料データは、有料データに対して、以下の情報が含まれていません。

・路線マスタの「路線カラー(コード)」の一部

・路線マスタの「路線カラー(名称)」の一部

・路線マスタの「路線区分」の全部

・駅マスタの「駅名称(カナ)」の全部

・駅マスタの「駅名称(ローマ字)」の全部

・駅マスタの新幹線駅のデータすべて


そもそも駅名データは、東京駅とかだと路線によって東京駅というデータが多数存在してる。

(同じ東京駅ではあるもののJRと新幹線としては別データとして登録されている)

一番エグいデータだと思ったのは大江戸線の都庁前駅(上下線&折り返し線があるため始発駅・終着駅のデータが混在している。氏ねばいいのに)。

単に駅名リストだけ欲しい!みたいに思っても重複がすごくあるので注意すべし(まさにこれで今回困ったんだけどさ)。

※上記サンプルコードの駅データは多少加工した後のデータでごにょっています。駅データjpさんから取ったデータとは少し変わっていますのでご注意ください。