Rは、リストやdata.frameの要素にアクセスするための2つの異なるメソッドを提供します - []
と[[]]
演算子。
両者の違いは何ですか?どちらの状況でどちらを使用するべきですか?
R言語定義はこれらのタイプの質問に答えるのに便利です。
Rには3つの基本的なインデックス演算子があり、構文は次の例のようになります。
x[i] x[i, j] x[[i]] x[[i, j]] x$a x$"a"
ベクトルや行列では
[[
形式はめったに使用されませんが、[
形式とは若干の意味的な違いがあります(例えば、任意の名前やdimnames属性を削除し、その部分一致は文字インデックスに使用されます)。単一のインデックスで多次元構造をインデックス付けするとき、x[[i]]
またはx[i]
はi
のx
番目の順次要素を返します。リストの場合、一般に
[[
を使用して任意の単一要素を選択します。一方、[
は選択された要素のリストを返します。
[[
形式では、整数または文字インデックスを使用して単一の要素のみを選択できますが、[
フォームではベクトルによるインデックス付けが可能です。ただし、リストの場合、インデックスはベクトルにすることができ、ベクトルの各要素はリスト、選択されたコンポーネント、そのコンポーネントの選択されたコンポーネントなどに順番に適用されます。結果はまだ単一の要素です。
2つのメソッドの大きな違いは、抽出に使用されたときに返されるオブジェクトのクラスと、それらが値の範囲を受け入れることができるのか、割り当て中に単一の値を受け入れるのかということです。
次のリストのデータ抽出の場合を考えてください。
foo <- list( str='R', vec=c(1,2,3), bool=TRUE )
Fooからboolによって格納された値を抽出し、それをif()
ステートメントの中で使用したいとしましょう。これは、[]
と[[]]
の戻り値がデータ抽出に使用されるときの違いを説明します。 []
メソッドはクラスリスト(またはfooがdata.frameの場合はdata.frame)のオブジェクトを返し、[[]]
メソッドはそのクラスが値の型によって決まるオブジェクトを返します。
したがって、[]
メソッドを使用すると、次のようになります。
if( foo[ 'bool' ] ){ print("Hi!") }
Error in if (foo["bool"]) { : argument is not interpretable as logical
class( foo[ 'bool' ] )
[1] "list"
これは、[]
メソッドがリストを返し、リストがif()
ステートメントに直接渡すのに有効なオブジェクトではないためです。この場合、[[]]
を使用する必要があります。それは、適切なクラスを持つ「bool」に格納された「ベア」オブジェクトを返すためです。
if( foo[[ 'bool' ]] ){ print("Hi!") }
[1] "Hi!"
class( foo[[ 'bool' ]] )
[1] "logical"
2番目の違いは、[]
演算子は制限されていますが、[[]]
演算子はリスト内のスロットの範囲またはデータフレーム内の列にアクセスするために使用できることです。 単一のスロットまたは列にアクセスする。 2番目のリストbar()
を使って値を代入する場合を考えてみます。
bar <- list( mat=matrix(0,nrow=2,ncol=2), Rand=rnorm(1) )
Fooの最後の2つのスロットをbarに含まれるデータで上書きしたいとしましょう。 [[]]
演算子を使用しようとすると、これが起こります。
foo[[ 2:3 ]] <- bar
Error in foo[[2:3]] <- bar :
more elements supplied than there are to replace
これは[[]]
が単一要素へのアクセスに限定されているためです。 []
を使う必要があります。
foo[ 2:3 ] <- bar
print( foo )
$str
[1] "R"
$vec
[,1] [,2]
[1,] 0 0
[2,] 0 0
$bool
[1] -0.6291121
割り当てが成功しても、fooのスロットは元の名前のままです。
二重括弧はリスト要素にアクセスし、単一括弧は単一の要素を持つリストを返します。
lst <- list('one','two','three')
a <- lst[1]
class(a)
## returns "list"
a <- lst[[1]]
class(a)
## returns "character"
[]
はリストを抽出し、[[]]
はリスト内の要素を抽出します
alist <- list(c("a", "b", "c"), c(1,2,3,4), c(8e6, 5.2e9, -9.3e7))
str(alist[[1]])
chr [1:3] "a" "b" "c"
str(alist[1])
List of 1
$ : chr [1:3] "a" "b" "c"
str(alist[[1]][1])
chr "a"
ここに[[
が再帰的インデックス作成のためにも装備されていることを付け加えるだけで。
これは、@ JijoMatthewによる回答で示唆されていましたが、調査されていませんでした。
?"[["
で述べたように、length(y) > 1
のような構文はx[[y]]
のように解釈されます:
x[[ y[1] ]][[ y[2] ]][[ y[3] ]] ... [[ y[length(y)] ]]
このはでは[
と[[
の違いについてのあなたの主な見方を変えるべきではないことに注意してください - すなわち、前者は サブセット化 のために使われます 抽出 単一リスト要素に使用されます。
例えば、
x <- list(list(list(1), 2), list(list(list(3), 4), 5), 6)
x
# [[1]]
# [[1]][[1]]
# [[1]][[1]][[1]]
# [1] 1
#
# [[1]][[2]]
# [1] 2
#
# [[2]]
# [[2]][[1]]
# [[2]][[1]][[1]]
# [[2]][[1]][[1]][[1]]
# [1] 3
#
# [[2]][[1]][[2]]
# [1] 4
#
# [[2]][[2]]
# [1] 5
#
# [[3]]
# [1] 6
値3を取得するには、次のようにします。
x[[c(2, 1, 1, 1)]]
# [1] 3
上記の@ JijoMatthewの答えに戻って、r
を思い出してください。
r <- list(1:10, foo=1, far=2)
特に、これは[[
の使い方を誤ると起こりがちなエラー、つまり、
r[[1:3]]
r[[1:3]]
のエラー:再帰的インデックス作成はレベル2で失敗しました
このコードは実際にはr[[1]][[2]][[3]]
を評価しようとし、r
のネストはレベル1で停止するので、再帰的索引付けによる抽出の試みは[[2]]
、すなわちレベル2で失敗しました。
r[[c("foo", "far")]]
内のエラー:添字が範囲外
ここで、Rは存在しないr[["foo"]][["far"]]
を探していたので、添字の範囲外エラーを出します。
これらのエラーの両方が同じメッセージを出したなら、それはおそらくもう少し役に立つ/一貫しているでしょう。
どちらもサブセット化の方法です。単一の括弧はリストのサブセットを返します。それ自体はリストです。つまり、複数の要素を含んでいてもいなくてもかまいません。一方、二重括弧はリストから単一の要素だけを返します。
- シングルブラケットは私達にリストを与えるでしょう。リストから複数の要素を返す場合は、単一の括弧を使用することもできます。次のリストを検討してください: -
>r<-list(c(1:10),foo=1,far=2);
表示しようとしたときにリストが返される方法に注意してください。 rと入力してEnterを押す
>r
#the result is:-
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
$foo
[1] 1
$far
[1] 2
今、私たちはシングルブラケットの魔法を見るでしょう: -
>r[c(1,2,3)]
#the above command will return a list with all three elements of the actual list r as below
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
$foo
[1] 1
$far
[1] 2
これは、画面にrの値を表示しようとしたときとまったく同じです。つまり、単一の括弧を使用するとリストが返され、インデックス1には10個の要素からなるベクトルがあります。そして遠い。単一の括弧への入力として単一のインデックスまたは要素名を指定することもできます。例えば:
> r[1]
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
この例では、1つのインデックス "1"を与え、その結果として1つの要素(10個の数字の配列)のリストを得ました。
> r[2]
$foo
[1] 1
上記の例では、インデックス「2」を1つ指定し、その結果、1つの要素を含むリストを取得しました。
> r["foo"];
$foo
[1] 1
この例では、1つの要素の名前を渡し、その結果、1つの要素を含むリストが返されました。
次のような要素名のベクトルを渡すこともできます -
> x<-c("foo","far")
> r[x];
$foo
[1] 1
$far
[1] 2
この例では、 "foo"と "far"という2つの要素名を持つベクトルを渡しました。
その結果、2つの要素を含むリストが得られました。
簡単に言うと、単一の括弧は常に、単一の括弧に渡した要素数またはインデックス数に等しい要素数を持つ別のリストを返します。
対照的に、二重括弧は常に1つの要素だけを返します。二重大括弧に移動する前に、覚えておくべき注意事項があります。 NOTE:THE MAJOR DIFFERENCE BETWEEN THE TWO IS THAT SINGLE BRACKET RETURNS YOU A LIST WITH AS MANY ELEMENTS AS YOU WISH WHILE A DOUBLE BRACKET WILL NEVER RETURN A LIST. RATHER A DOUBLE BRACKET WILL RETURN ONLY A SINGLE ELEMENT FROM THE LIST.
いくつか例を挙げます。以下の例を見終わったら、単語を太字で書き留めておいてください。
二重括弧は、インデックスの実際の値を返します(リストを返すのではなく_)。
> r[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
>r[["foo"]]
[1] 1
二重括弧の場合、ベクトルを渡して複数の要素を表示しようとすると、その必要性に応えるために構築されたのではなく単一の要素を返すためだけにエラーになります
以下を検討してください
> r[[c(1:3)]]
Error in r[[c(1:3)]] : recursive indexing failed at level 2
> r[[c(1,2,3)]]
Error in r[[c(1, 2, 3)]] : recursive indexing failed at level 2
> r[[c("foo","far")]]
Error in r[[c("foo", "far")]] : subscript out of bounds
初心者が手動の霧の中を移動するのを助けるために、折りたたみ関数として[[ ... ]]
記法を見ることは役に立つかもしれません - 言い換えれば、それはあなたがちょうど名前付きベクトル、リスト、またはデータフレームから「データを取得」したい。これらのオブジェクトからのデータを計算に使用したい場合は、これを実行することをお勧めします。これらの簡単な例で説明します。
(x <- c(x=1, y=2)); x[1]; x[[1]]
(x <- list(x=1, y=2, z=3)); x[1]; x[[1]]
(x <- data.frame(x=1, y=2, z=3)); x[1]; x[[1]]
3番目の例から:
> 2 * x[1]
x
1 2
> 2 * x[[1]]
[1] 2
用語として、[[
演算子はリストから要素を抽出しますが、[
演算子はリストのsubsetを取ります。
さらに別の具体的な使用例として、split()
関数によって作成されたデータフレームを選択したい場合は、二重括弧を使用します。あなたが知らないなら、split()
はキーフィールドに基づいてリスト/データフレームをサブセットにグループ化します。複数のグループを操作したいとき、それらをプロットしたいときなどに便利です。
> class(data)
[1] "data.frame"
> dsplit<-split(data, data$id)
> class(dsplit)
[1] "list"
> class(dsplit['ID-1'])
[1] "list"
> class(dsplit[['ID-1']])
[1] "data.frame"
加えて:
ここで A N S W E R の L N K に従います。
これは、次の点に対処する簡単な例です。
x[i, j] vs x[[i, j]]
df1 <- data.frame(a = 1:3)
df1$b <- list(4:5, 6:7, 8:9)
df1[[1,2]]
df1[1,2]
str(df1[[1,2]])
str(df1[1,2])