R apply系をわかりやすく解説する (2)sapply

このシリーズではRの処理を高速に処理するためには避けて通れないapply系の使い方を自分自身で仕組みを理解しつつまとめていきます。

今回のテーマはsapplyです。

第一回はlapplyを取り上げました。

今回のテーマ: sapply

このブログでは何事もざっくりと理解をして、応用力をつけることに力を入れていますので今回もsapplyの本質をまず理解することから始めたいと思いますが、ずばり
前回取り上げたlapplyと決定的に異なる点は、戻り値がベクトルになるということです(もちろん例外はたくさんあるので細かい話は後半で)

ややこしいことを考えずに、前回の例をベースにlapplysapplyに変えて結果を見てみましょう。

a <- list(c(1:5), c(6:10), c(11:15))
res1 = lapply(a, mean)
res2 = sapply(a, mean)

上記を実行したときの結果です(RStudioの”Environment”パネル)

f:id:okdata:20191005121610p:plain:w400

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)で取得されています。

f:id:okdata:20191005122148p:plain:w400

この点が本質的な違いなので、我々がカラムごとに平均値の計算や何らかの関数を当てはめて、単純に計算結果を取り出したいといった
ニーズに対してはsapplyを使う
方がデータ取り出し時に余分なステップがなくてすむので良いと思います。

なお、入力するデータは、lapplysapplyはどちらも、ベクトル、リスト、データフレーム形式を受け付けますので違いはありません。

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です

いろいろ調べていると、両者の微妙な違いについて解説しているサイトやブログがたくさん見つかります。
よくある説明は、sapplylapplyの結果をできるだけシンプルになるように配慮して結果を返す、という説明です。だから、simplify=Fのように簡略化された結果はいらないと明示的に指定すればlapplyと同じ結果になるということです。sapplysもシンプルのsとすれば納得です。

ではlapplyはいつ使うのか

lapplysapplyもほとんど機能は同じでsapplyの方が簡単に使えて良い、というのであれば 逆にどういったタイミングでlapplyを使うのかですが、
私の初〜中級程度の経験では、複数の計算結果を一つの変数に持たせたいといった強いニーズがあるとき以外にはあまり使う機会はないという印象です。

もっとも、使い方や仕組みの基本を理解しておけば他人のプログラムを読むときもスムーズで、特定のタイミングでどの関数を使ったら良いかといった時にも困らないで、両者の機能は基本同じだがsapplyの方が利用には便利というざっくりとしたイメージで普段は使っていても問題ないかと思われます。