リストまたはデータフレームの要素にアクセスするためのブラケット[]とダブルブラケット[[]]の違い


521

Rリストまたはdata.frameの要素にアクセスするための2つの異なる方法を提供する:[]および[[]]

2つのの違いは何ですか?

回答:


327

R言語定義は、次のタイプの質問に答えるのに便利です。

Rには3つの基本的なインデックス演算子があり、構文は次の例で表示されます。

    x[i]
    x[i, j]
    x[[i]]
    x[[i, j]]
    x$a
    x$"a"

ベクトルと行列の場合、[[フォームとの意味上の違いが少しありますが、フォームが使用されることはほとんどありません[(たとえば、名前やdimnames属性が削除され、文字インデックスに部分一致が使用されます)。単一のインデックスで多次元構造にインデックスを付ける場合、x[[i]]またはx[i]ith番目の順次要素を返しxます。

リストの場合、通常は[[任意の単一の要素を選択するために使用します[が、選択した要素のリストを返します。

この[[形式では、整数または文字インデックスを使用して単一の要素のみを選択[できますが、ベクトルによるインデックス付けは可能です。ただし、リストの場合、インデックスはベクトルにすることができ、ベクトルの各要素はリスト、選択されたコンポーネント、そのコンポーネントの選択されたコンポーネントなどに順に適用されます。結果はまだ単一の要素です。


6
[[vs [を使用して、単一の数値vsベクトルでインデックスを作成する理由は何ですか?[両方に使用しないのはなぜですか?[[を使用して単一のエントリを取得できます。[1つのインデックスで長さ1のリストが返されます。なぜ長さ1のリストを返す必要があるのでしょうか。
言葉の意味で

4
@wordsforthewise、プログラミング時に、インデックス付けに使用したい未定義の長さのベクトルを持つことができます。持って[あなたが同じ出力クラスを取得し、リスト手段返す常にx[v]かかわらずの長さのをv。たとえばlapply、リストのサブセットを上書きしたい場合がありますlapply(x[v], fun)[長さ1のベクトルのリストをドロップすると、長さが1の場合は常にエラーが返されますv
Axeman 2017

1
私は、これはより明確に説明して考えるadv-r.had.co.nz/Subsetting.html
赤エンドウ

171

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のスロットは元の名前を保持したことに注意してください。


111

二重ブラケットはリスト要素にアクセスしますが、単一ブラケットは単一要素のリストを返します。

lst <- list('one','two','three')

a <- lst[1]
class(a)
## returns "list"

a <- lst[[1]]
class(a)
## returns "character"


48

[]リストを[[]]抽出し、リスト内の要素を抽出します

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"

18

ここに追加するだけで[[再帰的なインデックス作成にも対応しています。

これは、@ JijoMatthewの回答でほのめかされましたが、調査されませんでした。

で説明したように?"[["、のような構文は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"]]存在しないを、添え字が範囲外のエラーになります。

これらのエラーの両方が同じメッセージを出力した場合、おそらくもう少し役立つ/一貫性があるでしょう。


こんにちはMicheal先生、[[]]を複数のインデックスに使用できますか?
Therii 2018年

14

どちらもサブセット化の方法です。単一のブラケットは、リストのサブセットを返します。それ自体がリストになります。つまり、複数の要素が含まれる場合と含まれない場合があります。一方、二重括弧はリストから単一の要素のみを返します。

-単一ブラケットは私達にリストを与えます。リストから複数の要素を返したい場合は、単一のブラケットを使用することもできます。次のリストを検討してください:

>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要素のベクトルがあり、さらに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

1
「ベクターを渡すと、そのニーズに応えるためにビルドされていないからといってエラーが発生する」ので、反対票が投じられました。私の新しい答えを見てください。
MichaelChirico

1
「ダブルブラケットがリストを返すことはありません」のような強い主張をしているため、反対票を投じました。それは真実ではありません-リストのリストであるオブジェクトがある場合、二重括弧は別のリストを返します。
dabsingh

[]1桁であってもリストクラスを返すという事実は非常に直感的ではありません。彼らは([])リストのような別の構文を作成する必要があり[[]]、実際の要素にアクセスすることは問題ありません。私[[]]は他の言語のように生の価値と考えるのが好きです。
TokyoToo

13

初心者が手動フォグをナビゲートできるようにするには、 [[ ... ]]表記を折りたたみ関数としてつまり、名前付きベクター、リスト、またはデータフレームから「データを取得」するだけの場合です。これらのオブジェクトのデータを計算に使用する場合は、これを行うとよいでしょう。これらの簡単な例で説明します。

(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

1
初心者として、xへの3つの割り当て(「<-」を使用)で、「<-」のターゲットであるxとの混同を避けるために、x = 1をw = 1に置き換えると役立つことがわかりました
user36800

とてもシンプルですが、私はこの説明が本当に好きです。別の簡単なデモンストレーション:iris[[1]]ベクトルをiris[1]返しますが、data.frameを返します
stevec


7

さらに別の具体的な使用例として、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"

-1

以下の詳細な説明を参照してください。

mtcarsと呼ばれるRの組み込みデータフレームを使用しました。

> mtcars 
               mpg cyl disp  hp drat   wt ... 
Mazda RX4     21.0   6  160 110 3.90 2.62 ... 
Mazda RX4 Wag 21.0   6  160 110 3.90 2.88 ... 
Datsun 710    22.8   4  108  93 3.85 2.32 ... 
           ............

テーブルの一番上の行は、列名を含むヘッダーと呼ばれます。その後の各水平線はデータ行を示し、行の名前で始まり、その後に実際のデータが続きます。行の各データメンバーはセルと呼ばれます。

単一の角かっこ「[]」演算子

セルのデータを取得するには、単一の角かっこ「[]」演算子に行と列の座標を入力します。2つの座標はコンマで区切られます。つまり、座標は行の位置で始まり、その後にコンマが続き、列の位置で終わります。順序は重要です。

例1:-これは、mtcarsの最初の行、2番目の列のセル値です。

> mtcars[1, 2] 
[1] 6

例2:-さらに、数値座標の代わりに行と列の名前を使用できます。

> mtcars["Mazda RX4", "cyl"] 
[1] 6 

二重角括弧「[[]]」演算子

二重の角括弧「[[]]」演算子を使用してデータフレーム列を参照します。

例1:組み込みデータセットmtcarsの9番目の列ベクトルを取得するには、mtcars [[9]]と記述します。

mtcars [[9]] [1] 1 1 1 0 0 0 0 0 0 0 0 ...

例2:-名前で同じ列ベクトルを取得できます。

mtcars [["am"]] [1] 1 1 1 0 0 0 0 0 0 0 0 ...


-1

加えて:

以下のLINKANSWERここでます。

以下は、次の点に対処する小さな例です。

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])
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.