Antworten:
Die R-Sprachdefinition ist praktisch, um folgende Fragen zu beantworten:
R verfügt über drei grundlegende Indizierungsoperatoren, deren Syntax in den folgenden Beispielen dargestellt wird
x[i] x[i, j] x[[i]] x[[i, j]] x$a x$"a"
Für Vektoren und Matrizen werden die
[[
Formulare selten verwendet, obwohl sie einige geringfügige semantische Unterschiede zum[
Formular aufweisen (z. B. werden Namen oder Dimnames-Attribute gelöscht, und diese teilweise Übereinstimmung wird für Zeichenindizes verwendet). Wenn Sie mehrdimensionale Strukturen mit einem einzelnen Index indizierenx[[i]]
oderx[i]
dasi
dritte sequentielle Element von zurückgebenx
.Bei Listen wird im Allgemeinen
[[
ein einzelnes Element ausgewählt, während[
eine Liste der ausgewählten Elemente zurückgegeben wird.Das
[[
Formular ermöglicht die Auswahl nur eines einzelnen Elements mithilfe von Ganzzahl- oder Zeichenindizes, während[
die Indizierung nach Vektoren möglich ist. Beachten Sie jedoch, dass für eine Liste der Index 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.
[
immer eine Liste zurückgeben, erhalten Sie x[v]
unabhängig von der Länge von dieselbe Ausgabeklasse v
. Zum Beispiel könnte man lapply
über eine Teilmenge einer Liste gehen wollen : lapply(x[v], fun)
. Wenn [
die Liste für Vektoren der Länge eins gelöscht würde, würde dies einen Fehler zurückgeben, wenn v
die Länge eins ist.
Die signifikanten Unterschiede zwischen den beiden Methoden sind die Klasse der Objekte, die sie bei der Extraktion zurückgeben, und ob sie einen Wertebereich oder nur einen einzelnen Wert während der Zuweisung akzeptieren.
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 zeigt die Unterschiede zwischen den Rückgabewerten von []
und [[]]
wann sie für die Datenextraktion verwendet werden. Die []
Methode gibt Objekte der Klassenliste (oder data.frame, wenn foo ein data.frame war) zurück, während die [[]]
Methode Objekte zurückgibt, deren Klasse durch den 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 es das in 'bool' gespeicherte "nackte" Objekt zurückgibt, das die entsprechende Klasse hat:
if( foo[[ 'bool' ]] ){ print("Hi!") }
[1] "Hi!"
class( foo[[ 'bool' ]] )
[1] "logical"
Der zweite Unterschied besteht darin, 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 einzelnen Slot oder eine einzelne Spalte beschränkt ist. Betrachten Sie den Fall der Wertzuweisung anhand einer zweiten Liste bar()
:
bar <- list( mat=matrix(0,nrow=2,ncol=2), rand=rnorm(1) )
Angenommen, wir möchten die letzten beiden foo-Slots 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 [[]]
nur auf ein einzelnes Element zugegriffen werden kann. 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 die Slots in foo während der erfolgreichen Zuweisung ihre ursprünglichen Namen beibehalten haben.
Doppelbügel greift auf eine Liste Element , während eine einzelne Konsole gibt Ihnen eine Liste mit einem einzelnen Element zurück.
lst <- list('one','two','three')
a <- lst[1]
class(a)
## returns "list"
a <- lst[[1]]
class(a)
## returns "character"
Von Hadley Wickham:
Meine (beschissen aussehende) Modifikation zur Darstellung mit tidyverse / purrr:
[]
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"
Fügen Sie hier nur das hinzu, das [[
auch für die rekursive Indizierung ausgestattet ist .
Dies wurde in der Antwort von @JijoMatthew angedeutet, aber nicht untersucht.
Wie in erwähnt ?"[["
, wird Syntax wie x[[y]]
, wo length(y) > 1
, interpretiert als:
x[[ y[1] ]][[ y[2] ]][[ y[3] ]] ... [[ y[length(y)] ]]
Beachten Sie, dass dies nichts daran ändert, was Ihr Hauptgrund für den Unterschied zwischen [
und sein sollte [[
- nämlich, dass ersteres für die Teilmenge und letzteres für das Extrahieren einzelner Listenelemente verwendet wird.
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 oben, erinnern Sie sich r
:
r <- list(1:10, foo=1, far=2)
Dies erklärt insbesondere die Fehler, die bei Missbrauch auftreten können [[
, nämlich:
r[[1:3]]
Fehler in
r[[1:3]]
: Rekursive Indizierung auf Ebene 2 fehlgeschlagen
Da dieser Code tatsächlich versucht hat, zu bewerten r[[1]][[2]][[3]]
, und das Verschachteln von r
Stopps auf Ebene 1 fehlschlug, schlug der Versuch, durch rekursive Indizierung zu extrahieren [[2]]
, auf Ebene 2 fehl .
Fehler in
r[[c("foo", "far")]]
: Index außerhalb der Grenzen
Hier hat R gesucht r[["foo"]][["far"]]
, was nicht existiert, also bekommen wir den Index-Out-of-Bound-Fehler.
Es wäre wahrscheinlich etwas hilfreicher / konsistenter, wenn beide Fehler dieselbe Meldung liefern würden.
Beide sind Teilmengen. Die einzelne Klammer gibt eine Teilmenge der Liste zurück, die an sich eine Liste ist. dh: Es kann mehr als ein Element enthalten oder nicht. Andererseits gibt eine doppelte Klammer nur ein einzelnes Element aus der Liste zurück.
- Eine einzelne Klammer 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);
Bitte beachten Sie nun, wie die Liste zurückgegeben wird, wenn ich versuche, sie anzuzeigen. Ich tippe r 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 einer einzelnen Klammer 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 beim Versuch, den Wert von r auf dem Bildschirm anzuzeigen. Dies bedeutet, dass die Verwendung einer einzelnen Klammer eine Liste zurückgegeben hat, in der wir bei Index 1 einen Vektor mit 10 Elementen haben und dann zwei weitere Elemente mit den Namen foo und weit. Wir können auch einen einzelnen Index- oder Elementnamen als Eingabe für die einzelne Klammer angeben. z.B:
> r[1]
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
In diesem Beispiel haben wir einen Index mit "1" angegeben und im Gegenzug eine Liste mit einem Element (einem Array mit 10 Zahlen) erhalten.
> r[2]
$foo
[1] 1
Im obigen Beispiel haben wir einen Index "2" angegeben und im Gegenzug 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 mit Elementnamen übergeben wie: -
> 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.
Im Gegenzug haben wir eine Liste mit zwei Elementen erhalten.
Kurz gesagt, eine einzelne Klammer gibt Ihnen immer eine andere Liste mit der Anzahl der Elemente zurück, die der Anzahl der Elemente oder der Anzahl der Indizes entspricht, die Sie an die einzelne Klammer übergeben.
Im Gegensatz dazu gibt eine doppelte Klammer immer nur ein Element zurück. Bevor Sie zur doppelten Klammer wechseln, sollten Sie eine Notiz beachten.
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.
Ich werde einige Beispiele nennen. Bitte notieren Sie sich die fett gedruckten Wörter und kehren Sie zurück, nachdem Sie mit den folgenden Beispielen fertig sind:
Die doppelte Klammer gibt Ihnen den tatsächlichen Wert am Index zurück. (Es wird KEINE Liste zurückgegeben.)
> r[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
>r[["foo"]]
[1] 1
Wenn wir in doppelten Klammern versuchen, mehr als ein Element durch Übergeben eines Vektors anzuzeigen, führt dies zu einem Fehler, nur weil es nicht für diesen Bedarf erstellt wurde, sondern nur, um ein einzelnes Element zurückzugeben.
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
[]
eine Listenklasse zurückgegeben wird, auch wenn es sich um eine einzelne Ziffer handelt, ist sehr unintuitiv. Sie hätten eine andere Syntax wie ([])
für die Liste erstellen sollen und der [[]]
Zugriff auf das eigentliche Element ist in Ordnung. Ich stelle mir [[]]
den Rohwert lieber wie in anderen Sprachen vor.
Um Neulingen die Navigation durch den manuellen Nebel zu erleichtern, kann es hilfreich sein, die [[ ... ]]
Notation als kollabierende Funktion zu betrachten. Mit anderen Worten, wenn Sie nur die Daten von einem benannten Vektor, einer Liste oder einem Datenrahmen abrufen möchten. 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
iris[[1]]
einen Vektor zurück, während iris[1]
Als Terminologie extrahiert der [[
Operator das Element aus einer Liste, während der Operator eine Teilmenge einer Liste übernimmt .[
Verwenden Sie für einen weiteren konkreten Anwendungsfall doppelte Klammern, wenn Sie einen von der split()
Funktion erstellten Datenrahmen auswählen möchten . Wenn Sie es nicht wissen, split()
gruppieren Sie eine Liste / einen Datenrahmen basierend auf einem Schlüsselfeld in Teilmengen. Dies ist nützlich, wenn Sie mehrere Gruppen bearbeiten, zeichnen 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"
Bitte beachten Sie die unten stehende ausführliche Erklärung.
Ich habe den in R integrierten Datenrahmen namens mtcars verwendet.
> 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 ...
............
Die oberste Zeile der Tabelle wird als Header bezeichnet, der die Spaltennamen enthält. Jede horizontale Linie danach bezeichnet eine Datenzeile, die mit dem Namen der Zeile beginnt, gefolgt von den tatsächlichen Daten. Jedes Datenelement einer Zeile wird als Zelle bezeichnet.
Um Daten in einer Zelle abzurufen, geben wir ihre Zeilen- und Spaltenkoordinaten in den Operator "[]" in eckigen Klammern ein. Die beiden Koordinaten sind durch ein Komma getrennt. Mit anderen Worten, die Koordinaten beginnen mit der Zeilenposition, gefolgt von einem Komma und enden mit der Spaltenposition. Die Reihenfolge ist wichtig.
ZB 1: - Hier ist der Zellenwert aus der ersten Zeile, zweiten Spalte von mtcars.
> mtcars[1, 2]
[1] 6
Beispiel 2: - Außerdem können wir die Zeilen- und Spaltennamen anstelle der numerischen Koordinaten verwenden.
> mtcars["Mazda RX4", "cyl"]
[1] 6
Wir verweisen auf eine Datenrahmenspalte mit dem Operator "[[]]" in doppelter eckiger Klammer.
Beispiel 1: - Um den neunten Spaltenvektor des eingebauten Datensatzes mtcars abzurufen, schreiben wir mtcars [[9]].
mtcars [[9]] [1] 1 1 1 0 0 0 0 0 0 0 0 ...
Beispiel 2: - Wir können denselben Spaltenvektor anhand seines Namens abrufen.
mtcars [["am"]] [1] 1 1 1 0 0 0 0 0 0 0 0 0 ...