高階関数
高階関数とは,関数を引数にとる関数のことである.
data.frameを処理するときに,ループをぶん回すのを一般的に考えがちだが,Rの場合は要素に適用する関数を取る高階関数で回すことが多い.
apply関数
行や列単位でループさせた結果をまとめて記述できるのがapply関数
である.
まず,前項と同じく,八王子市の人口データをdata.frame形式で読み込んでおく.
# 国や自治体の機関が公開しているオープンデータは基本的にExcelからの書き出しであり
# 文字コードがSHIFT_JISなので,
# fileEncodingオプションに'Shift_JIS'を与えてやる
df <- read.csv('http://www.city.hachioji.tokyo.jp/contents/open/002/p005866_d/fil/nenreibetsu_jinkou_2506.csv', fileEncoding='Shift_JIS')
# data.frame形式で出力される
head(df)
apply関数は,data.frame形式の行方向や列方向に対してなんらかの処理を行う関数.行か列のベクトルが入り,処理をしたベクトルを返す.
使い方は,apply(dataframe, 方向, 処理する内容を記述した関数オブジェクト)
方向は1なら行ごとのベクトルが入り,2なら列ごとベクトルが入って回る.
# まず処理する関数オブジェクトを作っておく
line.loop.func <- function(v){
# ベクトルが引数になる
# 行ごと,つまり年齢ごとに男性の人口 - 女性の人口を返す関数を作ると,こうなる
return(v[4] - v[5])
}
# apply関数の行方向に対して,それぞれ上で作ったline.loop.funcという関数を食わせて,結果のベクトルを得る
sub_vec = apply(df, 1, line.loop.func)
# 折れ線グラフで描画する
age = length(df$'年齢')
plot(0:(age-1), sub_vec, type='l', lty=1, xlab='age', ylab='population')
sapply関数
リストやベクトルの全ての「要素」に対して適用する.行列に適用した場合は,全ての値に対して適用されるので注意.
# 関数を定義しておいて
increase.func <- function(a){
return(a+1)
}
# 偶数のベクトルを作り
vec1 <- seq(0, 10, by=2)
print(vec1)
# sapply関数を適用すると,奇数のベクトルができる
vec2 <- sapply(vec1, increase.func)
print(vec2)
# 同じく偶数の行列を作り
mat1 <- matrix(seq(0, 18, by=2), nrow=2, ncol=5)
print(mat1)
# spply関数を適用すると,奇数の行列ができる.入れたのが行列でも戻り値がベクトルになっていることに注意
mat2 <- sapply(mat1, increase.func)
print(mat2)
# なので受け取ったらこいつを行列にする
mat3 <- matrix(mat2, nrow=2, ncol=5)
print(mat3)
結果は以下のようになる.
[1] 0 2 4 6 8 10
[1] 1 3 5 7 9 11
[,1] [,2] [,3] [,4] [,5]
[1,] 0 4 8 12 16
[2,] 2 6 10 14 18
[1] 1 3 5 7 9 11 13 15 17 19
[,1] [,2] [,3] [,4] [,5]
[1,] 1 5 9 13 17
[2,] 3 7 11 15 19
lapply関数というのもあるが,これは必ず(ベクトルではなく)リストを返すのが特徴.(listというのは構造体みたいなものだった)
mapply関数
mapply関数は,apply関数の多変量版であり,複数のベクトルや行列を取ることができる.
例えば以下のように男女の人口のベクトルが分かれている場合,
df.man = df$'人口.男'
df.woman = df$'人口.女'
この2つのベクトルを行ごとに足した合計を出したいとする.
# まず関数を定義
sum.loop.func <- function(a, b){
# 合計を返す
return(a + b)
}
# df.manとdf.womanに適用して結果を得る
sum.of.pop <- mapply(sum.loop.func, df.man, df.woman)
# 折れ線グラフで描画する
age = length(df$'年齢')
plot(0:(age-1), sum.of.pop, type='l', lty=1, xlab='age', ylab='population')
# 実はsum関数は既にあるので,以下のように書くだけでもいける
mapply(sum, df.man, df.woman)
人口合計のグラフは当然わかっているので省略.