R は、リストまたは data.frame の要素にアクセスするための 2 つの異なるメソッドを提供します:[]
と[[]]
。
2 つの違いは何ですか? また、いつどちらを使用する必要がありますか?
R 言語定義は、次のような質問に答えるのに便利です。
R には 3 つの基本的なインデックス演算子があり、構文は次の例に示されています
x[i] x[i, j] x[[i]] x[[i, j]] x$a x$"a"
ベクトルと行列の場合、この
[[
形式はめったに使用されませんが、形式とは若干の意味上の違いがあり[
ます (たとえば、names または dimnames 属性が削除され、文字インデックスには部分一致が使用されます)。単一のインデックスで多次元構造にインデックスを付ける場合、x[[i]]
またはは の番目の連続要素をx[i]
返します。i
x
リストの場合、通常、 を使用
[[
して単一の要素を選択します[
が、選択した要素のリストを返します。この
[[
形式では、整数または文字のインデックスを使用して 1 つの要素のみを選択[
できますが、ベクトルによるインデックス付けは可能です。ただし、リストの場合、インデックスをベクトルにすることができ、ベクトルの各要素がリスト、選択されたコンポーネント、そのコンポーネントの選択されたコンポーネントなどに順番に適用されることに注意してください。結果はまだ単一の要素です。
2 つのメソッドの大きな違いは、抽出に使用されたときに返されるオブジェクトのクラスと、代入時に値の範囲または単一の値を受け入れるかどうかです。
次のリストのデータ抽出のケースを考えてみましょう。
foo <- list( str='R', vec=c(1,2,3), bool=TRUE )
bool によって格納された値を foo から抽出し、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"
ここに追加するだけで、 recursive indexing[[
も装備されています。
これは@JijoMatthewの回答で示唆されましたが、調査されていません。
に示されているように、 、 where 、?"[["
などの構文は次のように解釈されます。x[[y]]
length(y) > 1
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"]]
いたので、添え字が範囲外エラーになります。
これらのエラーの両方で同じメッセージが表示された場合、おそらくもう少し役立つ/一貫性があります。
用語的には、[[
演算子はリストから要素を抽出しますが、演算子はリストのサブセット[
を取ります。
どちらもサブセット化の方法です。単一のブラケットは、それ自体がリストになるリストのサブセットを返します。つまり、複数の要素を含む場合と含まない場合があります。一方、二重括弧はリストから 1 つの要素だけを返します。
-単一のブラケットでリストが表示されます。リストから複数の要素を返したい場合は、単一のブラケットを使用することもできます。次のリストを検討してください。
>r<-list(c(1:10),foo=1,far=2);
ここで、リストを表示しようとしたときにリストが返される方法に注意してください。r と入力してエンターを押します。
>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 個の要素のベクトルがあり、次に foo という名前の要素が 2 つ以上あります。そして遠く。単一のブラケットへの入力として、単一のインデックスまたは要素名を指定することもできます。例えば、:
> r[1]
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
この例では、1 つのインデックス「1」を指定し、代わりに 1 つの要素 (10 個の数値の配列) を持つリストを取得しました。
> r[2]
$foo
[1] 1
上記の例では、1 つのインデックス "2" を指定し、代わりに 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
さらに別の具体的な使用例として、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"