Odpowiedzi:
Definicja języka R jest przydatna w przypadku odpowiedzi na tego rodzaju pytania:
R ma trzy podstawowe operatory indeksowania, a składnia jest wyświetlana w poniższych przykładach
x[i] x[i, j] x[[i]] x[[i, j]] x$a x$"a"
W przypadku wektorów i macierzy
[[
formy są rzadko używane, chociaż mają one pewne nieznaczne różnice semantyczne w stosunku do[
formy (np. Upuszcza wszelkie atrybuty nazw lub dimnames, a indeksowanie znaków stosuje się częściowe dopasowanie). Podczas indeksowania struktur wielowymiarowych za pomocą jednego indeksux[[i]]
lubx[i]
zwrócii
th kolejny elementx
.W przypadku list zwykle używa się
[[
do wyboru dowolnego pojedynczego elementu, a[
zwraca listę wybranych elementów.
[[
Forma pozwala tylko jeden element, który jest zaznaczony za pomocą liczb całkowitych lub postaci wskaźników, przy czym[
umożliwia indeksowanie wektorów. Należy jednak pamiętać, że dla listy indeksem może być wektor, a każdy element wektora jest stosowany kolejno do listy, wybranego komponentu, wybranego komponentu tego komponentu i tak dalej. Wynik jest nadal jednym elementem.
[
zawsze zwróci listę środków, które można uzyskać tę samą klasę wyjściowy dla x[v]
niezależnie od długości v
. Na przykład, może chcieć lapply
ponad podzbiór listy: lapply(x[v], fun)
. Gdyby [
upuścić listę wektorów o długości 1, zwróciłoby to błąd, ilekroć v
ma długość 1.
Istotne różnice między dwiema metodami to klasa obiektów, które zwracają, gdy są używane do ekstrakcji, oraz to, czy mogą zaakceptować zakres wartości, czy tylko jedną wartość podczas przypisywania.
Rozważ przypadek ekstrakcji danych na poniższej liście:
foo <- list( str='R', vec=c(1,2,3), bool=TRUE )
Powiedzmy, że chcielibyśmy wyodrębnić wartość przechowywaną przez bool z foo i użyć jej w if()
instrukcji. Zilustruje to różnice między wartościami zwracanymi []
i [[]]
kiedy są one używane do ekstrakcji danych. W []
sposób powraca Przedmiotem liście klasy (lub data.frame jeśli foo był data.frame), natomiast[[]]
powraca Sposób przedmioty, których klasa jest określana przez rodzaj ich wartości.
Tak więc użycie tej []
metody powoduje:
if( foo[ 'bool' ] ){ print("Hi!") }
Error in if (foo["bool"]) { : argument is not interpretable as logical
class( foo[ 'bool' ] )
[1] "list"
Wynika to z tego, że []
metoda zwróciła listę, a lista nie jest prawidłowym obiektem do przekazania bezpośrednio do if()
instrukcji. W tym przypadku musimy użyć, [[]]
ponieważ zwróci „nagi” obiekt przechowywany w 'bool', który będzie miał odpowiednią klasę:
if( foo[[ 'bool' ]] ){ print("Hi!") }
[1] "Hi!"
class( foo[[ 'bool' ]] )
[1] "logical"
Druga różnica polega na tym, że []
operator może być użyty do uzyskania dostępu do zakresu szczelin na liście lub kolumnach w ramce danych, podczas gdy [[]]
operator jest ograniczony do dostępu do pojedynczego slotu lub kolumny. Rozważ przypadek przypisania wartości za pomocą drugiej listy bar()
:
bar <- list( mat=matrix(0,nrow=2,ncol=2), rand=rnorm(1) )
Powiedzmy, że chcemy zastąpić ostatnie dwa miejsca foo danymi zawartymi w takcie. Jeśli spróbujemy użyć [[]]
operatora, dzieje się tak:
foo[[ 2:3 ]] <- bar
Error in foo[[2:3]] <- bar :
more elements supplied than there are to replace
Jest tak, ponieważ [[]]
ogranicza się do uzyskania dostępu do pojedynczego elementu. Musimy użyć []
:
foo[ 2:3 ] <- bar
print( foo )
$str
[1] "R"
$vec
[,1] [,2]
[1,] 0 0
[2,] 0 0
$bool
[1] -0.6291121
Zwróć uwagę, że podczas gdy przypisanie zakończyło się powodzeniem, sloty w foo zachowały swoje oryginalne nazwy.
Podwójne nawiasy otwierają dostęp do elementu listy , a pojedynczy nawias zwraca listę z jednym elementem.
lst <- list('one','two','three')
a <- lst[1]
class(a)
## returns "list"
a <- lst[[1]]
class(a)
## returns "character"
Od Hadley Wickham:
Moja (kiepsko wyglądająca) modyfikacja do wyświetlania za pomocą tidyverse / purrr:
[]
wyodrębnia listę, [[]]
wyodrębnia elementy na liście
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"
Wystarczy dodać tutaj, że [[
jest on również przystosowany do indeksowania rekurencyjnego .
Wskazano na to w odpowiedzi @JijoMatthew, ale nie zostało to zbadane.
Jak zaznaczono w ?"[["
, składnia typu jak x[[y]]
, gdzie length(y) > 1
jest interpretowana jako:
x[[ y[1] ]][[ y[2] ]][[ y[3] ]] ... [[ y[length(y)] ]]
Zauważ, że to nie zmienia tego, co powinno być twoim głównym wynosieniem różnicy między [
i [[
- mianowicie, że ten pierwszy służy do podzbioru , a drugi do wyodrębniania pojedynczych elementów listy.
Na przykład,
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
Aby uzyskać wartość 3, możemy:
x[[c(2, 1, 1, 1)]]
# [1] 3
Wracając do powyższej odpowiedzi @ JijoMatthew, przypomnij sobie r
:
r <- list(1:10, foo=1, far=2)
W szczególności wyjaśnia to błędy, które często popełniamy przy niewłaściwym użyciu [[
, a mianowicie:
r[[1:3]]
Błąd w
r[[1:3]]
: indeksowanie rekurencyjne nie powiodło się na poziomie 2
Ponieważ ten kod faktycznie próbował ocenić r[[1]][[2]][[3]]
, a zagnieżdżanie r
zatrzymań na poziomie pierwszym, próba wyodrębnienia za pomocą indeksowania rekurencyjnego zakończyła się niepowodzeniem [[2]]
, tj. Na poziomie 2.
Błąd w
r[[c("foo", "far")]]
: indeks dolny poza granicami
Tutaj R szukał r[["foo"]][["far"]]
, który nie istnieje, więc uzyskujemy błąd indeksu poza granicami.
Prawdopodobnie byłoby trochę bardziej pomocne / spójne, gdyby oba te błędy dawały ten sam komunikat.
Oba są sposobami podzbioru. Pojedynczy nawias zwróci podzbiór listy, który sam w sobie będzie listą. tzn .: może zawierać więcej niż jeden element. Z drugiej strony podwójny nawias zwróci tylko jeden element z listy.
-Jeden wspornik da nam listę. Możemy również użyć pojedynczego nawiasu, jeśli chcemy zwrócić wiele elementów z listy. rozważ następującą listę:
>r<-list(c(1:10),foo=1,far=2);
Teraz zwróć uwagę na sposób zwracania listy, gdy próbuję ją wyświetlić. Wpisuję r i naciskam Enter
>r
#the result is:-
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
$foo
[1] 1
$far
[1] 2
Teraz zobaczymy magię pojedynczego nawiasu: -
>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
co jest dokładnie takie samo, jak gdy próbowaliśmy wyświetlić wartość r na ekranie, co oznacza, że użycie pojedynczego nawiasu zwróciło listę, gdzie w indeksie 1 mamy wektor 10 elementów, a następnie mamy dwa kolejne elementy o nazwach foo i daleko. Możemy również podać pojedynczy indeks lub nazwę elementu jako dane wejściowe do pojedynczego nawiasu. na przykład:
> r[1]
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
W tym przykładzie podaliśmy jeden indeks „1”, aw zamian otrzymaliśmy listę z jednym elementem (którym jest tablica 10 liczb)
> r[2]
$foo
[1] 1
W powyższym przykładzie podaliśmy jeden indeks „2”, aw zamian otrzymaliśmy listę z jednym elementem
> r["foo"];
$foo
[1] 1
W tym przykładzie przekazaliśmy nazwę jednego elementu, aw zamian zwrócono listę z jednym elementem.
Możesz także przekazać wektor nazw elementów, takich jak:
> x<-c("foo","far")
> r[x];
$foo
[1] 1
$far
[1] 2
W tym przykładzie przekazaliśmy wektor o dwóch nazwach elementów „foo” i „far”
W zamian otrzymaliśmy listę z dwoma elementami.
Krótko mówiąc, pojedynczy nawias zawsze zwraca kolejną listę z liczbą elementów równą liczbie elementów lub liczbie indeksów, które przekazujesz do pojedynczego nawiasu.
Natomiast podwójny nawias zawsze zwraca tylko jeden element. Przed przejściem do podwójnego nawiasu należy pamiętać o tym.
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.
Przedstawię kilka przykładów. Zapisz pogrubioną czcionkę i wróć do niej po zakończeniu poniższych przykładów:
Podwójny nawias zwróci rzeczywistą wartość w indeksie ( NIE zwróci listy)
> r[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
>r[["foo"]]
[1] 1
w przypadku podwójnych nawiasów, jeśli spróbujemy wyświetlić więcej niż jeden element, przekazując wektor, spowoduje to błąd tylko dlatego, że nie został zbudowany, aby zaspokoić tę potrzebę, ale po prostu zwrócić pojedynczy element.
Rozważ następujące
> 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
Aby pomóc początkującym w poruszaniu się po ręcznej mgle, pomocne może być postrzeganie [[ ... ]]
notacji jako funkcji zwijania - innymi słowy, to wtedy, gdy chcesz po prostu „pobrać dane” z nazwanego wektora, listy lub ramki danych. Dobrze jest to zrobić, jeśli chcesz wykorzystać dane z tych obiektów do obliczeń. Te proste przykłady to zilustrują.
(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]]
Tak więc z trzeciego przykładu:
> 2 * x[1]
x
1 2
> 2 * x[[1]]
[1] 2
iris[[1]]
zwraca wektor, podczas gdy iris[1]
zwraca data.frame
Będąc terminologicznym, [[
operator wyodrębnia element z listy, podczas gdy [
operator pobiera podzbiór listy.
W jeszcze innym konkretnym przypadku użycia użyj podwójnych nawiasów, aby wybrać ramkę danych utworzoną przez split()
funkcję. Jeśli nie wiesz, split()
grupujesz ramkę listy / danych w podzbiory na podstawie pola klucza. Jest to przydatne, jeśli chcesz operować na wielu grupach, wykreślić je itp.
> 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"
Proszę zapoznać się ze szczegółowym wyjaśnieniem poniżej.
Użyłem wbudowanej ramki danych w języku R, zwanej mtcars.
> 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 ...
............
Górny wiersz tabeli nazywa się nagłówkiem, który zawiera nazwy kolumn. Każda linia pozioma następnie oznacza wiersz danych, który zaczyna się od nazwy wiersza, a następnie następuje rzeczywiste dane. Każdy element danych wiersza jest nazywany komórką.
Aby pobrać dane z komórki, wprowadzilibyśmy współrzędne jej wiersza i kolumny w operatorze „[]” z pojedynczym nawiasiem kwadratowym. Dwie współrzędne są oddzielone przecinkiem. Innymi słowy, współrzędne zaczynają się od pozycji wiersza, po której następuje przecinek, a kończy na pozycji kolumny. Kolejność jest ważna.
Np. 1: - Oto wartość komórki z pierwszego wiersza, drugiej kolumny mtcars.
> mtcars[1, 2]
[1] 6
Np. 2: - Ponadto możemy użyć nazw wierszy i kolumn zamiast współrzędnych numerycznych.
> mtcars["Mazda RX4", "cyl"]
[1] 6
Odwołujemy się do kolumny ramki danych za pomocą operatora podwójnego nawiasu kwadratowego „[[]]”.
Np. 1: - Aby pobrać dziewiąty wektor wbudowanego zestawu danych mtcars, piszemy mtcars [[9]].
mtcars [[9]] [1] 1 1 1 0 0 0 0 0 0 0 0 ...
Np. 2: - Możemy pobrać ten sam wektor kolumny według jego nazwy.
mtcars [["am"]] [1] 1 1 1 0 0 0 0 0 0 0 0 ...
Dodatkowo:
Oto mały przykład odnoszący się do następującego punktu:
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])