R Language
*関数ファミリを適用する(関数)
サーチ…
備考
*apply
ファミリーの関数は、 for
ループの抽象です。 for
ループとの比較*apply
関数には次の利点があります。
- 書き込むコードが少なくて済みます。
- 反復カウンタはありません。
- 中間結果を格納するために一時変数を使用しません。
しかしfor
ループはより一般的であり、 *apply
関数を使用することは必ずしも簡単ではない複雑な計算を実現するために、より多くの制御を与えることが*apply
ます。
for
ループと*apply
関数の関係については、 for
ループのドキュメントを参照for
。
*apply
加盟家族のメンバー
*apply
ファミリには、主に返される出力の種類に基づいて異なる、同じ原則の複数のバリアントが含まれています。
関数 | 入力 | 出力 |
---|---|---|
apply | matrix 、 data.frame 、またはarray | ベクトルまたは行列(返される各要素の長さに応じて) |
sapply | ベクトルまたはlist | ベクトルまたは行列(返される各要素の長さに応じて) |
lapply | ベクトルまたはlist | list |
vapply | ベクトルまたは `list | ベクトルまたは行列(返される各要素の長さに応じて)ユーザー指定のクラス |
mapply | 複数のベクトル、 lists または組み合わせ | list |
これらの各関数の使用方法については、「例」を参照してください。
適用時に匿名関数を使用する
apply
は、配列や行列のマージン上の関数(おそらく匿名の関数)を評価するために使われapply
。
このアイデアを説明するためにiris
データセットを使用しましょう。 iris
データセットは、3種から150の花を測定しています。このデータセットの構造を見てみましょう:
> head(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
さて、あなたはこれらの変数のそれぞれの平均値を知りたいことを想像してください。これを解決する1つの方法は、 for
ループを使用することfor
が、Rプログラマはしばしばapply
を使用apply
ことを好みapply
(理由は理由を参照してください)。
> apply(iris[1:4], 2, mean)
Sepal.Length Sepal.Width Petal.Length Petal.Width
5.843333 3.057333 3.758000 1.199333
- 最初のパラメータでは、
mean
は数値データに対してのみ機能するため、最初の4列のみを含めるようにiris
をサブセット化しています。 - 第2のパラメータ値
2
我々は唯一の(Cアレイ×Rの第二の添え字)カラム上で動作することを示しています。1
は行手段を与える。
同様に、より意味のある値を計算することができます。
# standard deviation
apply(iris[1:4], 2, sd)
# variance
apply(iris[1:4], 2, var)
警告 :Rには、列と行の合計を計算するのに適した組み込み関数がいくつかありrowMeans
。 colMeans
、 rowMeans
とrowMeans
を意味します。
ここでは、より意味のある別のタスクを実行しましょう: 0.5
より大きい値に対してのみ平均を計算しましょう。そのために、私たちは独自のmean
関数を作成します。
> our.mean.function <- function(x) { mean(x[x > 0.5]) }
> apply(iris[1:4], 2, our.mean.function)
Sepal.Length Sepal.Width Petal.Length Petal.Width
5.843333 3.057333 3.758000 1.665347
( Petal.Width
の平均の違いに注意してください)
しかし、コードの残りの部分でこの関数を使用したくない場合はどうすればよいでしょうか?次に、無名関数を使用して、次のようなコードを書くことができます:
apply(iris[1:4], 2, function(x) { mean(x[x > 0.5]) })
これまで見てきたように、 apply
を使用して、1行だけを使用してデータセットの列または行に対して同じ操作を実行することができます。
注意 : apply
は指定された関数の結果の長さに応じて非常に異なる出力を返すので、対話的に作業していない場合には最適な選択ではないかもしれません。他の*apply
家族機能のいくつかは、もう少し予測可能です(備考参照)。
バルクファイル読み込み
同様のプロセスで十分に構造化されたファイル名で操作される必要のある多数のファイルについては、
まず、アクセスするファイル名のベクトルを作成する必要があります。これには複数のオプションがあります。
paste0()
でベクトルを手動で作成するfiles <- paste0("file_", 1:100, ".rds")
list.files()
をファイルタイプの正規表現検索語で使用する場合、同じタイプの他のファイルがディレクトリにある場合、正規表現( 正規表現 )の知識が必要です。files <- list.files("./", pattern = "\\.rds$", full.names = TRUE)
X
は、使用されるファイル命名形式の一部のベクトルです。
lapply
は各応答をリストの要素として出力します。
readRDS
は.rds
ファイルに固有であり、プロセスの適用に応じて変更されます。
my_file_list <- lapply(files, readRDS)
これはテストからのforループより必ずしも高速ではありませんが、すべてのファイルを明示的に割り当てずにリストの要素にすることができます。
最後に、複数のパッケージを一度に読み込む必要があることがよくあります。このトリックは、私たちがインポートしたいすべてのライブラリにlibrary()
を適用することで、簡単に行うことができます:
lapply(c("jsonlite","stringr","igraph"),library,character.only=TRUE)
複数の `data.frames`(` lapply`、 `mapply`)を組み合わせると、
この練習では、4つのブートストラップ線形回帰モデルを生成し、これらのモデルのサマリーを1つのデータフレームに結合します。
library(broom)
#* Create the bootstrap data sets
BootData <- lapply(1:4,
function(i) mtcars[sample(1:nrow(mtcars),
size = nrow(mtcars),
replace = TRUE), ])
#* Fit the models
Models <- lapply(BootData,
function(BD) lm(mpg ~ qsec + wt + factor(am),
data = BD))
#* Tidy the output into a data.frame
Tidied <- lapply(Models,
tidy)
#* Give each element in the Tidied list a name
Tidied <- setNames(Tidied, paste0("Boot", seq_along(Tidied)))
この時点で、名前をdata.frameに挿入するには2つの方法があります。
#* Insert the element name into the summary with `lapply`
#* Requires passing the names attribute to `lapply` and referencing `Tidied` within
#* the applied function.
Described_lapply <-
lapply(names(Tidied),
function(nm) cbind(nm, Tidied[[nm]]))
Combined_lapply <- do.call("rbind", Described_lapply)
#* Insert the element name into the summary with `mapply`
#* Allows us to pass the names and the elements as separate arguments.
Described_mapply <-
mapply(
function(nm, dframe) cbind(nm, dframe),
names(Tidied),
Tidied,
SIMPLIFY = FALSE)
Combined_mapply <- do.call("rbind", Described_mapply)
あなたがmagrittr
スタイルパイプのファンであれば、(モデルオブジェクト自体のような中間オブジェクトのどれかが必要な場合はそうするのは賢明ではありませんが)タスク全体を単一のチェーンで実行できます。
library(magrittr)
library(broom)
Combined <- lapply(1:4,
function(i) mtcars[sample(1:nrow(mtcars),
size = nrow(mtcars),
replace = TRUE), ]) %>%
lapply(function(BD) lm( mpg ~ qsec + wt + factor(am), data = BD)) %>%
lapply(tidy) %>%
setNames(paste0("Boot", seq_along(.))) %>%
mapply(function(nm, dframe) cbind(nm, dframe),
nm = names(.),
dframe = .,
SIMPLIFY = FALSE) %>%
do.call("rbind", .)
組み込みfunctionalsの使用
組み込み機能:lapply()、sapply()、mapply()
Rには機能が組み込まれています。その中でもっともよく知られているものは機能の適用ファミリです。最も一般的な適用関数のいくつかについて以下に説明します。
-
lapply()
=は引数としてリストをとり、指定された関数をリストに適用します。 -
sapply()
と同じ=lapply()
が、ベクトルまたは行列に出力を簡素化しようとします。-
vapply()
=出力オブジェクトの型を指定する必要があるsapply()
変種。
-
-
mapply()
=のようなlapply()
が、指定された関数への入力として複数のベクトルを渡すことができます。sapply()
ように単純化することができます。-
Map()
は、SIMPLIFY = FALSE
mapply()
へのエイリアスです。
-
lapply()
lapply()
は、2つの異なる反復で使用できます。
-
lapply(variable, FUN)
-
lapply(seq_along(variable), FUN)
# Two ways of finding the mean of x
set.seed(1)
df <- data.frame(x = rnorm(25), y = rnorm(25))
lapply(df, mean)
lapply(seq_along(df), function(x) mean(df[[x]))
サプリー()
sapply()
は、その出力をベクトルまたは行列に解決しようとします。
# Two examples to show the different outputs of sapply()
sapply(letters, print) ## produces a vector
x <- list(a = 1:10, beta = exp(-3:3), logic = c(TRUE,FALSE,FALSE,TRUE))
sapply(x, quantile) ## produces a matrix
mapply()
mapply()
同じようにlapply()
しますが、入力として複数のベクトルを取ることができます(多変量の場合はm)。
mapply(sum, 1:5, 10:6, 3) # 3 will be "recycled" by mapply
ユーザー定義ファンクショナルの使用
ユーザー定義ファンクショナル
ユーザーはさまざまな程度の複雑さで独自の機能を作成できます。以下の例は、Hadley WickhamのFunctionalsからのものです。
randomise <- function(f) f(runif(1e3))
lapply2 <- function(x, f, ...) {
out <- vector("list", length(x))
for (i in seq_along(x)) {
out[[i]] <- f(x[[i]], ...)
}
out
}
最初のケースでは、 randomise
は単一の引数f
受け取り、それをUniformランダム変数のサンプルで呼び出します。等価性を証明するために、以下のset.seed
を呼び出します。
set.seed(123)
randomise(mean)
#[1] 0.4972778
set.seed(123)
mean(runif(1e3))
#[1] 0.4972778
set.seed(123)
randomise(max)
#[1] 0.9994045
set.seed(123)
max(runif(1e3))
#[1] 0.9994045
2番目の例は、functionalsを使用してリスト( x
)の各要素に操作( f
)を適用するbase::lapply
再実装です。 ...
パラメータを使用すると、 mean
関数のna.rm
オプションなど、 f
に追加の引数を渡すことができます。
lapply(list(c(1, 3, 5), c(2, NA, 6)), mean)
# [[1]]
# [1] 3
#
# [[2]]
# [1] NA
lapply2(list(c(1, 3, 5), c(2, NA, 6)), mean)
# [[1]]
# [1] 3
#
# [[2]]
# [1] NA
lapply(list(c(1, 3, 5), c(2, NA, 6)), mean, na.rm = TRUE)
# [[1]]
# [1] 3
#
# [[2]]
# [1] 4
lapply2(list(c(1, 3, 5), c(2, NA, 6)), mean, na.rm = TRUE)
# [[1]]
# [1] 3
#
# [[2]]
# [1] 4