it-swarm.com.de

Der Unterschied zwischen Klammern [] und Doppelklammern [[]] für den Zugriff auf die Elemente einer Liste oder eines Datenrahmens

R bietet zwei verschiedene Methoden, um auf die Elemente einer Liste oder eines Datenrahmens zuzugreifen: die Operatoren [] und [[]].

Was ist der Unterschied zwischen den beiden? In welchen Situationen sollte ich eine über der anderen verwenden?

442
Sharpie

Die R-Sprachdefinition ist praktisch, um diese Arten von Fragen zu beantworten:

R verfügt über drei grundlegende Indexierungsoperatoren. Die folgenden Beispiele zeigen die Syntax

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

Für Vektoren und Matrizen werden die [[-Formen selten verwendet, obwohl sie geringfügige semantische Unterschiede zur [-Form aufweisen (z. B. löscht sie alle Attribute für Namen oder dimnames, und diese teilweise Übereinstimmung wird für Zeichenindizes verwendet). Wenn Sie mehrdimensionale Strukturen mit einem einzigen Index indexieren, gibt x[[i]] oder x[i] das ith sequentielle Element von x zurück.

Für Listen verwendet man im Allgemeinen [[, um ein einzelnes Element auszuwählen, während [ eine Liste der ausgewählten Elemente zurückgibt.

.__ Das Formular [[ ermöglicht die Auswahl eines einzelnen Elements anhand von Ganzzahl- oder Zeichenindizes, während [ die Indizierung nach Vektoren ermöglicht. Beachten Sie jedoch, dass der Index für eine Liste ein Vektor sein kann und jedes Element des Vektors der Reihe nach auf die Liste, die ausgewählte Komponente, die ausgewählte Komponente dieser Komponente usw. angewendet wird. Das Ergebnis ist immer noch ein einzelnes Element .

283
ars

Die wesentlichen Unterschiede zwischen den beiden Methoden sind die Klasse der Objekte, die sie zurückgeben, wenn sie zum Extrahieren verwendet werden, und ob sie möglicherweise einen Wertebereich akzeptieren oder nur einen einzelnen Wert während der Zuweisung.

Betrachten Sie den Fall der Datenextraktion in der folgenden Liste:

foo <- list( str='R', vec=c(1,2,3), bool=TRUE )

Angenommen, wir möchten den von bool gespeicherten Wert aus foo extrahieren und in einer if()-Anweisung verwenden. Dies veranschaulicht die Unterschiede zwischen den Rückgabewerten von [] und [[]], wenn diese zur Datenextraktion verwendet werden. Die []-Methode gibt Objekte der Klassenliste zurück (oder data.frame, wenn foo ein data.frame war), während die [[]]-Methode Objekte zurückgibt, deren Klasse vom Typ ihrer Werte bestimmt wird. 

Die Verwendung der []-Methode führt also zu folgenden Ergebnissen:

if( foo[ 'bool' ] ){ print("Hi!") }
Error in if (foo["bool"]) { : argument is not interpretable as logical

class( foo[ 'bool' ] )
[1] "list"

Dies liegt daran, dass die []-Methode eine Liste zurückgegeben hat und eine Liste kein gültiges Objekt ist, das direkt an eine if()-Anweisung übergeben werden kann. In diesem Fall müssen wir [[]] verwenden, da das in "bool" gespeicherte "bare" -Objekt zurückgegeben wird, das die entsprechende Klasse hat:

if( foo[[ 'bool' ]] ){ print("Hi!") }
[1] "Hi!"

class( foo[[ 'bool' ]] )
[1] "logical"

Der zweite Unterschied ist, dass der []-Operator verwendet werden kann, um auf einen Bereich von Slots in einer Liste oder Spalten in einem Datenrahmen zuzugreifen, während der [[]]-Operator auf den Zugriff auf einen single slot oder eine Spalte beschränkt ist. Betrachten Sie den Fall der Bewertung anhand einer zweiten Liste, bar():

bar <- list( mat=matrix(0,nrow=2,ncol=2), Rand=rnorm(1) )

Angenommen, wir möchten die letzten beiden Slots von foo mit den in bar enthaltenen Daten überschreiben. Wenn wir versuchen, den Operator [[]] zu verwenden, geschieht Folgendes:

foo[[ 2:3 ]] <- bar
Error in foo[[2:3]] <- bar : 
more elements supplied than there are to replace

Dies liegt daran, dass [[]] auf den Zugriff auf ein einzelnes Element beschränkt ist. Wir müssen [] verwenden:

foo[ 2:3 ] <- bar
print( foo )

$str
[1] "R"

$vec
     [,1] [,2]
[1,]    0    0
[2,]    0    0

$bool
[1] -0.6291121

Beachten Sie, dass bei der erfolgreichen Zuweisung die Slots in foo ihre ursprünglichen Namen beibehalten haben.

156
Sharpie

Doppelte Klammern greifen auf eine Liste Element zu, während eine einzelne Klammer eine Liste mit einem einzelnen Element zurückgibt.

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

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

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

[] extrahiert eine Liste, [[]] extrahiert Elemente innerhalb der Liste

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"
43
user143339

Von Hadley Wickham:

 From Hadley Wickham

Meine (schäbige aussehende) Modifikation, um mit Tidyverse/Purrr zu zeigen:

 enter image description here

33
jzadra

Fügen Sie hier nur hinzu, dass [[ auch für die rekursive Indizierung geeignet ist.

Dies wurde in der Antwort von @JijoMatthew angedeutet, aber nicht untersucht.

Wie in ?"[[" angegeben, wird Syntax wie x[[y]], wobei length(y) > 1, wie folgt interpretiert:

x[[ y[1] ]][[ y[2] ]][[ y[3] ]] ... [[ y[length(y)] ]]

Beachten Sie, dass dieses nichts ändert, was Ihr Hauptaugenmerk auf den Unterschied zwischen [ und [[ sein soll, dh dass ersteres für subsetting und letzteres für extrahieren einzelne Listenelemente.

Zum Beispiel,

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

Um den Wert 3 zu erhalten, können wir Folgendes tun:

x[[c(2, 1, 1, 1)]]
# [1] 3

Zurück zu @ JijoMatthews Antwort, erinnern Sie sich an r:

r <- list(1:10, foo=1, far=2)

Dies erklärt insbesondere die Fehler, die wir bekommen, wenn Sie [[ falsch verwenden, nämlich:

r[[1:3]]

Fehler in r[[1:3]]: Rekursive Indexierung auf Ebene 2 fehlgeschlagen

Da dieser Code tatsächlich versucht hat, r[[1]][[2]][[3]] auszuwerten, und die Verschachtelung von r auf Ebene 1 stoppt, ist der Versuch, durch rekursive Indizierung zu extrahieren, bei [[2]] fehlgeschlagen, d. H. Auf Ebene 2.

Fehler in r[[c("foo", "far")]]: Index außerhalb der Grenzen

Hier hat R nach r[["foo"]][["far"]] gesucht, der nicht existiert, also bekommen wir den Index aus dem Bound-Error.

Es wäre wahrscheinlich ein bisschen hilfreicher/konsistenter, wenn beide Fehler die gleiche Meldung gaben.

17
MichaelChirico

Um Neulingen dabei zu helfen, durch den manuellen Nebel zu navigieren, kann es hilfreich sein, die [[ ... ]]-Notation als collapsing - Funktion zu sehen - mit anderen Worten, wenn Sie einfach nur die Daten von einem benannten Vektor, einer Liste oder von einer Liste erhalten möchten Datenrahmen. Dies ist sinnvoll, wenn Sie Daten aus diesen Objekten für Berechnungen verwenden möchten. Diese einfachen Beispiele werden veranschaulichen.

(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]]

Also aus dem dritten Beispiel:

> 2 * x[1]
  x
1 2
> 2 * x[[1]]
[1] 2
12
Redfoot

Beide sind Möglichkeiten der Teileinstellung .. Die einzelne Klammer gibt eine Teilmenge der Liste zurück, die an sich eine Liste ist. Das heißt: Es kann oder darf nicht mehr als ein Element enthalten . Andererseits wird eine doppelte Klammer nur ein einzelnes Element aus der Liste zurückgeben.

-Einfache Halterung gibt uns eine Liste. Wir können auch eine einzelne Klammer verwenden, wenn wir mehrere Elemente aus der Liste zurückgeben möchten Betrachten Sie die folgende Liste: -

>r<-list(c(1:10),foo=1,far=2);

Beachten Sie jetzt die Art und Weise, wie die Liste zurückgegeben wird, wenn ich versuche, sie anzuzeigen. Ich gebe r ein und drücke die Eingabetaste

>r

#the result is:-

[[1]]

 [1]  1  2  3  4  5  6  7  8  9 10

$foo

[1] 1

$far

[1] 2

Jetzt werden wir die Magie der einzelnen Klammern sehen: -

>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

dies ist genau das gleiche wie bei dem Versuch, den Wert von r auf dem Bildschirm anzuzeigen. Dies bedeutet, dass bei Verwendung einer einzelnen Klammer eine Liste zurückgegeben wurde. Bei Index 1 haben wir einen Vektor mit 10 Elementen. Dann haben wir zwei weitere Elemente mit Namen foo und far . Wir können auch einen einzelnen Index- oder Elementnamen als Eingabe für die einzelne Klammer ..__ angeben. Beispiel:

> r[1]

[[1]]

 [1]  1  2  3  4  5  6  7  8  9 10

In diesem Beispiel haben wir einen Index "1" angegeben und im Gegenzug eine Liste mit einem Element (das ein Array von 10 Zahlen ist) erhalten.

> r[2]

$foo

[1] 1

Im obigen Beispiel haben wir einen Index "2" angegeben und dafür eine Liste mit einem Element erhalten

> r["foo"];

$foo

[1] 1

In diesem Beispiel haben wir den Namen eines Elements übergeben und im Gegenzug wurde eine Liste mit einem Element zurückgegeben.

Sie können auch einen Vektor von Elementnamen übergeben:

> x<-c("foo","far")

> r[x];

$foo

[1] 1

$far
[1] 2

In diesem Beispiel haben wir einen Vektor mit zwei Elementnamen "foo" und "far" übergeben.

Dafür haben wir eine Liste mit zwei Elementen erhalten.

Kurz gesagt: Eine einfache Klammer gibt immer eine andere Liste mit der Anzahl der Elemente zurück, die der Anzahl der Elemente oder der Anzahl der Indizes entspricht, die Sie in die einzige Klammer übergeben.

Im Gegensatz dazu wird bei einer doppelten Klammer immer nur ein Element zurückgegeben. Bevor eine Doppelklammer verwendet wird, muss eine Notiz beachtet werdenNOTE: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.

Ich werde einige Beispiele vorstellen. Bitte notieren Sie sich die fettgedruckten Wörter und kehren Sie zu den folgenden Beispielen zurück:

Die doppelte Klammer gibt Ihnen den tatsächlichen Wert am Index zurück (es wirdNICHTeine Liste zurückgeben).

  > r[[1]]

     [1]  1  2  3  4  5  6  7  8  9 10


  >r[["foo"]]

    [1] 1

Bei doppelten Klammern führt der Versuch, mehr als ein Element durch Übergeben eines Vektors anzuzeigen, zu einem Fehler, nur weil er nicht dafür entwickelt wurde, sondern nur ein einzelnes Element zurückgibt.

Folgendes berücksichtigen

> 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
12
Jijo Mathew

Als terminologische [[ Operator Auszüge das Element aus einer Liste, während [ Operator nimmt Teilmenge einer Liste.

11
submartingale

Verwenden Sie für einen weiteren konkreten Anwendungsfall doppelte Klammern, wenn Sie einen Datenrahmen auswählen möchten, der mit der Funktion split() erstellt wurde. Wenn Sie nicht wissen, gruppiert split() eine Liste/einen Datenrahmen basierend auf einem Schlüsselfeld in Teilmengen. Dies ist nützlich, wenn Sie mehrere Gruppen bearbeiten, plotten usw. möchten.

> 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"
7
Peter

In Ergänzung:

Nach dem L I N K des A N S W E R hier. 

Hier ist ein kleines Beispiel, das den folgenden Punkt behandelt:

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])
0
Andre Elrico