このシリーズではR
の処理を高速に処理するためには避けて通れないapply系の使い方を自分自身で仕組みを理解しつつまとめていきます。
今回のテーマはsapply
です。
第一回はlapply
を取り上げました。
今回のテーマ: sapply
このブログでは何事もざっくりと理解をして、応用力をつけることに力を入れていますので今回もsapply
の本質をまず理解することから始めたいと思いますが、ずばり
前回取り上げたlapplyと決定的に異なる点は、戻り値がベクトルになるということです(もちろん例外はたくさんあるので細かい話は後半で)
ややこしいことを考えずに、前回の例をベースにlapply
をsapply
に変えて結果を見てみましょう。
a <- list(c(1:5), c(6:10), c(11:15))
res1 = lapply(a, mean)
res2 = sapply(a, mean)
上記を実行したときの結果です(RStudioの”Environment”パネル)
res1
はリスト形式ですが、res2
はベクトルとして結果が入っています。
同様に独自関数に当てはめた場合の結果も、
a <- list(c(1:5), c(6:10), c(11:15))
res1 = lapply(a, function(x) {
y = 3
z = mean(x) + y
return(z)
})
res2 = sapply(a, function(x) {
y = 3
z = mean(x) + y
return(z)
})
この結果も同様に、リスト形式(lapply)とベクトル(sapply)で取得されています。
この点が本質的な違いなので、我々がカラムごとに平均値の計算や何らかの関数を当てはめて、単純に計算結果を取り出したいといった
ニーズに対してはsapplyを使う方がデータ取り出し時に余分なステップがなくてすむので良いと思います。
なお、入力するデータは、lapply
とsapply
はどちらも、ベクトル、リスト、データフレーム形式を受け付けますので違いはありません。
simplify = F
両者がさらに同じように振る舞うケースとして、simplify=F
のオプションをつけた場合です。
以下の例ではres3
の結果はリスト形式で戻されres1
と全く同じ結果になることが確認できます。
a <- list(c(1:5), c(6:10), c(11:15))
res1 = lapply(a, mean)
res2 = sapply(a, mean)
res3 = sapply(a, mean, simplify = F)
identical(res1, res3) #この結果はTRUEです
いろいろ調べていると、両者の微妙な違いについて解説しているサイトやブログがたくさん見つかります。
よくある説明は、sapply
はlapply
の結果をできるだけシンプルになるように配慮して結果を返す、という説明です。だから、simplify=F
のように簡略化された結果はいらないと明示的に指定すればlapply
と同じ結果になるということです。sapply
のs
もシンプルのs
とすれば納得です。
ではlapply
はいつ使うのか
lapply
もsapply
もほとんど機能は同じでsapply
の方が簡単に使えて良い、というのであれば 逆にどういったタイミングでlapply
を使うのかですが、
私の初〜中級程度の経験では、複数の計算結果を一つの変数に持たせたいといった強いニーズがあるとき以外にはあまり使う機会はないという印象です。
もっとも、使い方や仕組みの基本を理解しておけば他人のプログラムを読むときもスムーズで、特定のタイミングでどの関数を使ったら良いかといった時にも困らないで、両者の機能は基本同じだがsapplyの方が利用には便利というざっくりとしたイメージで普段は使っていても問題ないかと思われます。