R : 一重角括弧[]と二重角括弧[[]]の違い

R

Rでは、一重角括弧[]と二重角括弧[[]]でデータの抽出ができます。

一重角括弧[] : vectorの要素、list(data.frameを含む)の一部を取り出したい時に使用   
二重角括弧[[]] : list(data.frameを含む)の要素を取り出したい時に使用

両者の使い分け方は上記の通りなのですが、どうにもしっくりこなかったので整理しました。

data.frame(またはlist)から考える

一重括弧[]、二重括弧[[]]について、いろいろ調べた結果、data.frameから考えるとわかりやすく整理できました。

以下のようなdata.frameを考えます。

v列 : 一様乱数
w列 : 標準正規分布に従う乱数
x列 : ランダムに並んだ小文字アルファベット
y列 : 平均50、標準偏差10の正規分布に従う乱数
z列 : ランダムに並んだ1〜12月の英語名
データ数はそれぞれ100個

set.seed(1) 

df <- data.frame(v = runif(100),
w = rnorm(100),
x = sample(letters, 100, replace = TRUE),
y = rnorm(100,50,10),
z = sample(month.name, 100, replace = TRUE))
head(df, 5)
          v          w x         y       z 
1 0.2655087 0.3981059 y 65.19745 June
2 0.3721239 -0.6120264 i 46.91259 March
3 0.5728534 0.3411197 i 37.46710 November
4 0.9082078 -1.1293631 o 56.42241 December
5 0.2016819 1.4330237 y 49.55291 October

このdata.frameから1,3,5列を抜き出し、それをaという変数に代入します。aのclassを調べるとdata.frameになります。

a <- df[c(1,3,5)]
head(a, 5)
class(a)
> a <- df[c(1,3,5)]
> head(a, 5)
          v x        z
1 0.2655087 y     June
2 0.3721239 i    March
3 0.5728534 i November
4 0.9082078 o December
5 0.2016819 y  October
> class(a)
[1] "data.frame"

 

aには、double型のデータとcharacter型のデータが含まれ、全データが同じ型にはなっていないので、aがvectorやmatrixでないのは当然で、必然的にaはlistになります(この場合はdata.frameですが、data.frameは本質的にはlistです)。

このことを踏まえると、listやdata.frameに対し一重角括弧[]で任意の列を抽出できるという機能を持つためには、一重角括弧[]の戻り値はlistもしくはdata.frameでなければならないことだと思います。

したがって、data.frameの各列個別の要素にアクセスしたい場合は別の方法で行わなければならず、それが二重角括弧[[]]というわけです。

b <- df[[1]]
head(b, 5)
class(b)
> head(b, 5)
[1] 0.2655087 0.3721239 0.5728534 0.9082078 0.2016819
> class(b)
[1] "numeric"

二重角括弧[[]]でデータを抽出すると、戻り値の型はvector(この場合はnumeric型のvector)になります。

vectorから考える

vectorに対しては、n番目の要素を取り出すのは、一般に一重括弧[]を使ってx[n]のようにアクセスしますが、vectorで二重角括弧を使ったらどうなるでしょうか?

x <- 1:100

x[2]
x[[2]]
> x[2]
[1] 2
> x[[2]]
[1] 2

x[2]もx[[2]]もいずれも同じ値を取得することができます。でも、二重角括弧[[]]で複数の値を指定するとエラーになります。

x[c(1,3,5)]
x[[c(1,3,5)]]
> x[c(1,3,5)]
[1] 1 3 5
> x[[c(1,3,5)]]
 x[[c(1, 3, 5)]] でエラー: 
  attempt to select more than one element in vectorIndex

[[]]で指定するのが1データの場合は、R内部で何らかの変換が自動的に行われてうまく機能するようですが、複数の要素にアクセスする場合にはエラーになってしまうみたいです。

というわけで、やはりvectorに対しては[]を使うべきということなのかと思います。

その他

Rには、一重括弧[]、二重括弧[[]]の使い方以外でも、わかりにくかったり、間違えやすかったりする箇所があります。こちらのページでそういう点について整理しています。

R : if文の使い方。間違えやすいポイントに注意
Rにも、他のプログラミング言語と同様、条件判定の制御文があります。ただ、Rのif文は、挙動を正しく理解していないと誤った計算をしてしまう場合があります。if文の使い方と間違えやすいポイントについて整理しています。
R : length() 関数が返す長さって何?
length()関数は、長さを返す関数であるということは想像できるのですが、きちんと理解していないと、引数の型によっては期待しているものと違う答えが返ってきます。そして、誤った評価…。そんなことにならないように、きちんと理解しておきましょう。

そもそもRって何ができるの?って思っている方はこちらをどうぞ。

R言語とは?Rでできること。現役Rユーザーが語る。
R言語は、データ分析、統計解析に特化した言語であるとよく言われます。しかし「データ分析」「統計解析」しかできないと考えてしまっては損をしています。C/C++のような汎用のプログラミング言語同様の制御構造を備えていますし、CRANで公開されているパッケージを利用すれば、はるかに簡単に望みの機能を実装することができる言語です。

まとめ

一重角括弧[] : ベクトルの要素、リストの一部を取り出したい時に使用   
二重角括弧[[]] : リストの要素を取り出したい時に使用

書いていることは、一番始めと変わりませんが、data.frame、listに対して一重角括弧[]を使う場合の戻り値の型を考えると少しはスッキリしてきませんか?