2016年6月16日木曜日

Rでデータフレームを部分抽出後、ベクトルや行列に変換する

例えば↓こんな感じで、各市町村の人口データがあったとします。

city   <- c("A市", "B町", "C村", "D市")
male   <- c(95, 49, 26, 45)
female <- c(99, 51, 24, 55)
df <- data.frame(city, male, female)
df
  city male female
1  A市   95     99
2  B町   49     51
3  C村   26     24
4  D市   45     55

で、人口や男女比を比較するために、それぞれの市町村に対してグラフを描いてみようとしたとします。

じゃあ、1行ごとにループで回しながら、barplotあたりを使って、グラフを描いてみようとしまして、↓こんな風にスクリプトを書くと(iがループのカウンタだと思ってね)、

# i行目の男女人口を棒グラフにしたい・・・
barplot(df[i, c("male", "female")])

 barplot.default(df[i, c("male", "female")]) でエラー: 
   'height' はベクトルか行列でなければなりません

なんでだ?と思って、切り出される部分をチェックしてみると、

df[i, c("male", "female")]

  male female
1   95     99

class(df[i, c("male", "female")])

[1] "data.frame"

構成要素としては、2つの数値の並びになっているもの、型がデータフレームなもんだから、barplotにそのまま渡すとエラーになってしまうのね。ちなみに、円グラフのpie関数なんかでも同じで、データフレームのままでは受け取ってくれない。

じゃあ、ベクトルに変換してあげよう。

barplot(as.vector(df[i, c("male", "female")], mode="numeric"))

as.vector後にbarplotに渡したもの

ラベル(maleとかfemale)の情報は消えちゃったけど、まあなんとかなったと。

エラーメッセージには「ベクトルか行列でなければなりません」とあったから、今度は行列にしてみよう↓


barplot( as.matrix(df[i, c("male", "female")]) )



as.matrix後にbarplotに渡したもの

列名が残っているおかげで、軸ラベルがそのまま出てくれるので、こっちの方がいいですね。
ちなみに↓こんな風に書いても、同じ動きになります。

barplot( t(t(df[1, c("male", "female")])) )


転置したときに行列に変換されるからですね。文字数的には少なく済みますが、あとで見たときや、他の人が見たときに混乱するかもしれないので、こういう書き方はやめた方がよさそうです。
で、ここからは補足になるんですが、もともとデータフレームを入力とするggplotを使ってみたらどうだろうかと。

前述のデータフレームはwideフォーマットなので、いったんlongフォーマットに変換します。

library(reshape2)

# longフォーマットに変換
df_l <- melt( df, id.vars="city", variable.name="gender",
              value.name="population" )
df_l
  city gender population
1  A市   male         95
2  B町   male         49
3  C村   male         26
4  D市   male         45
5  A市 female         99
6  B町 female         51
7  C村 female         24
8  D市 female         55

「dl_l」という名前のロングフォーマットのデータフレームに変換できたので、これをggplotに渡します。

library(ggplot2)


# A市の行だけ取り出してプロット

ggplot( df_l[city=="A市", ], aes(x=gender, y=population)) +
  geom_bar(stat="identity")



1行だけ取り出してggplot
うん、想定通りに表示できました。

じゃあ、これをループで回す? いやいや、ggplotなら、いっぺんにプロットできますよね。

ggplot( df_l, aes(x=city, y=population, fill=gender)) +
  geom_bar(stat="identity", position="dodge")



各市町村の男女人口や比率を比較したいなら、この可視化がよさげですね。

でも、このデフォルトのmaleとfemaleの色の割り当ては、無用な勘違いを生んでしまいそうです。
ggplotで、塗りつぶし(fill)の色を変更する方法については、

Rグラフィックスクックブック ―ggplot2によるグラフ作成のレシピ集
Rグラフィックスクックブック ―ggplot2によるグラフ作成のレシピ集

↑この書籍の「レシピ3.2 棒をグループ化する」のところなんかに、カラーパレットとしてbrewerパレットを使うレシピが載っていたりします。

その方法を使ってみると↓


はい、それっぽい色になりました。

やり方については、上記の書籍を買って読んでみてください。(最後はアフィリエイトかよ!)