読者です 読者をやめる 読者になる 読者になる

StatsBeginner: 初学者の統計学習ノート

初学者が統計学、機械学習、R、Pythonの勉強の過程をメモっていくノート。

Rで全角数字を半角数字に書き換える

 ↓このページに、Rで文字列を操作する系のコマンドが色々載っていました。
 文字列 | Rを利用して文字列のマッチング,結合,分割,置換を行う関数
 これを参考に、データの全角数字を半角数字に入れ替えるというのをやってみたいと思います。


 そういえば、はてなブログで


>|r|
||<


 で挟む記法を使うと、ソースコードに色がつくというのを今日知りました。rが大文字だと駄目らしい。デフォルトだと折り返しが無効になって、長い行があると横スクロールが発生します。
 プログラマの人とかは改行場所をコントロールしたいので折り返し表示を嫌うようですが、私はべつに複雑なコードは書けませんしこのブログは横幅が狭いので、CSSでpre{word-wrap: break-word;}と設定して折り返しありにしておきました。


 さて。
 データとしては、郵便局のサイトにある「事業所の個別郵便番号データダウンロード」ってのを使ってみようと思います。
 事業所の個別郵便番号のダウンロード - 日本郵便


 全件データを使うと多すぎるので、7月31日更新分(差分)のデータを使います。
 配布されているのがzip形式なので*1、URLで直接読み込むのではなくPC上で解凍してから読み込みます。タイトルレコードは入っていない(1行目からいきなりデータ)ので、「header=FALSE」と指定します。

> zip <- read.csv("JADD1407.CSV", header=FALSE)  # ダウンロードしたファイルの読み込み
Error in type.convert(data[[i]], as.is = as.is[i], dec = dec, na.strings = character(0L)) :
  invalid multibyte string at '<bb><c2><ce><df><db><cc><c4><de>≥<bb>›∂<b2><ca><c2> <b6><cc>fiº<b7><b6>fi≤<bc><d4> <ce>¬∂<b2><c4>fi≥<bc>fi∑<de>÷≥<ce><dd><cc><de>'


 読み込めない・・・
 郵便局のサイトの説明によるとShift-JISらしいので、文字コードを指定してみる。「encoding="SHIFT-JIS"」を追加します。

> zip <- read.csv("JADD1407.CSV", header=FALSE, encoding="SHIFT-JIS")
Error in type.convert(data[[i]], as.is = as.is[i], dec = dec, na.strings = character(0L)) :
  invalid multibyte string at '<bb><c2><ce><df><db><cc><c4><de>≥<bb>›∂<b2><ca><c2> <b6><cc>fiº<b7><b6>fi≤<bc><d4> <ce>¬∂<b2><c4>fi≥<bc>fi∑<de>÷≥<ce><dd><cc><de>'


 なぜかエラーで読み込めない・・・
 よく分からないので、テキストエディタでcsvをUTF-8に変換してから読み込むこととします。

> zip <- read.csv("zip_utf8.csv", header=FALSE)
> head(zip)  # 先頭の6行を表示


f:id:midnightseminar:20140813140423p:plain
※ブログに貼ると汚くなるところは、画像にしときます。


 先頭の6行だけを表示するhead()というコマンド、意外に使えますね。
 V8の列をみると、0で始まる郵便番号が、数字と認識された結果消えてしまってます。
 read.csv()で読み込む際に、列単位でクラスを指定することもできるので、ここでは、全部文字列として読み込むことにしてやり直します。「colClasses=」という引数に、列ごとのクラスを記述したベクトルを与えます。ここでは13列のクラスを全てcharacterにします。

> zip <- read.csv("zip_utf8.csv", header=FALSE, colClasses=c(rep("character", 13)))
> head(zip)


f:id:midnightseminar:20140813140909p:plain


 これでよし。
 列名称を書き換えておきます。read.csv()の段階でも引数に列名称を指定できたんだけど。

> colnames(zip) <- c("JIS","カナ名","漢字名","都道府県","市区町村","町域","丁目等","郵便番号","旧番号","取扱局","種別","複数","修正")
> head(zip)


f:id:midnightseminar:20140813140919p:plain


 変換の練習をしたいだけなので、郵便番号と住所のところだけ抜き出してみます。

> address <- data.frame(zip[,c(8, 4:7)])
> head(address)


f:id:midnightseminar:20140813140930p:plain


 さてここから、冒頭のページに載ってたgsub()というコマンドで、全角数字を半角数字に置き換えてみます。
 しかしgsub()は、1種類の文字列を1種類の文字列に置き換えるものなので、「0〜9」→「0〜9」をまとめて指定することができないっぽい。なので、「0」→「0」から順番に繰り返していく関数を作ります。
 また、データフレームに対してgsub()による置換を実行すると謎な出力がでてきてむかついたので、列ごとにベクトルとして処理していくことにします。

> gsub.multi <- function (pattern, replacement, data) {
+    # patternには、置き換える対象となる文字列をベクトルで与える
+    # replacementには、上記のそれぞれを何で置き換えるかをベクトルで与える
+    # dataにはデータフレームを入れる
+   
+    for (i in 1:ncol(data)) {
+       for (j in 1:length(pattern)) {
+       data[,i] <- gsub(pattern[j], replacement[j], data[,i])
+       }
+    }
+    return(data)
+ }


ではこの処理をためしてみます。

> zenkaku <- c("0","1","2","3","4","5","6","7","8","9")
> hankaku <- c("0","1","2","3","4","5","6","7","8","9")
>
> address2 <- gsub.multi(pattern=zenkaku, replacement=hankaku, data=address)
> head(address2)


f:id:midnightseminar:20140813140943p:plain


 成功しました!
 「丁目等」の列の数字が全部、半角に置き換わっています。


 次は逆に、半角を全角に戻してみます。
 郵便番号も変わってしまうと思いますが。

> address3 <- gsub.multi(pattern=hankaku, replacement=zenkaku, data=address2)
> head(address3)


f:id:midnightseminar:20140813140952p:plain


 できました!
 満足したので、出かけてきます。台風ですが。

*1:どうでもいいですが、読み込みデータオブジェクト名をzipとしたのはzipcodeを略したからであり、元ファイルがzip形式であることとは関係ないです。