XMLデータの扱い方

[2015-04-21追記] Hadley Wickham の xml2 パッケージが CRAN に入りました。Parse and process XML (and HTML) with xml2 | RStudio Blog 参照。

[2015-12-30追記] 久しぶりにページを更新しようと思ったら,鯖江市の人口XMLはまったく内容が変わっていました。とりあえず新しいXMLデータの扱い方のページを作りましたので,そちらをご覧ください。

XMLとは

XMLはExtensible Markup Language(拡張可能なマーク付け言語)の略称です。構造をもつデータを表現するための一種の言語です。

鯖江市がXMLなどを使ったオープンデータの公開を始めました:

ここではこのデータをRで読んで使う方法を解説します。

人口データ

鯖江市の人口XMLをWebブラウザで開いてもおそらくタグがたくさん入ったテキストとして扱われてしまうと思います。

このようなXMLをデータとして読むためのRのパッケージXMLをインストールし,読み込んでおきます:

install.packages("XML")
library(XML)

これで次のようにURLを指定してデータが読み込めます:

data = xmlToDataFrame("http://www3.city.sabae.fukui.jp/xml/population/population.xml")

head(data) と打ち込むと,何となく読めているようです:

  no year  gengo household population   man woman url
1  1 1956 昭和31      8500      41735 19561 22174  …
2  2 1957   32      9719      47855 22744 25111  …
3  3 1958   33      9794      47899 22677 25222  …
……

「昭和」や「平成」が付いていたり付いていなかったりするし,そもそもこんな単純なデータならXMLでなくてもCSVにしておけばExcelでも簡単に開けるのに……という突っ込みはさておいて,str(data) と打ち込んで,読み込んだデータの構造を調べてみましょう。

'data.frame':	56 obs. of  8 variables:
 $ no        : Factor w/ 56 levels "1","10","11",..: 1 12 23 34 45 53 54 55 56 2 ...
 $ year      : Factor w/ 56 levels "1956","1957",..: 1 2 3 4 5 6 7 8 9 10 ...
 $ gengo     : Factor w/ 56 levels "    17","    18",..: 55 17 18 19 20 21 22 23 24 26 ...
 $ household : Factor w/ 56 levels "10125","10286",..: 52 53 54 55 56 1 2 3 4 5 ...
 $ population: Factor w/ 56 levels "41735","47855",..: 1 2 3 4 5 6 7 8 9 10 ...
 $ man       : Factor w/ 56 levels "19561","22646",..: 1 4 3 2 5 6 7 8 9 10 ...
 $ woman     : Factor w/ 56 levels "22174","25111",..: 1 2 3 4 5 8 7 6 9 11 ...
 $ url       : Factor w/ 56 levels ...

全部factor(因子)として読み込まれてしまいました。これを文字列として読み込むのであれば

data = xmlToDataFrame("http://www3.city.sabae.fukui.jp/xml/population/population.xml",
                      stringsAsFactors=FALSE)

のようにオプションを付けます。さらに,年や人口は整数か実数で読み込みたいので,

data = xmlToDataFrame("http://www3.city.sabae.fukui.jp/xml/population/population.xml",
                      stringsAsFactors=FALSE,
                      colClasses=c("integer","integer","character",
                                   "numeric","numeric","numeric",
                                   "numeric","character"))

望み通りの型で読めたか str(data) で確認しておきましょう。

その場限りの処理なら,いちいち読み直すのではなく,

data$year = as.integer(data$year)
data$population = as.numeric(data$population)

のようにして数値に変換するほうが早いでしょう。

とりあえず人口のグラフを描くと次のようになります:

par(mgp=c(2,0.8,0))
plot(data$year, data$population, type="o", pch=16, xlab="年", ylab="人口")
鯖江市の人口の推移

Last modified: