Bir liste veya veri çerçevesinin öğelerine erişmek için köşeli ayraç [] ve çift köşeli ayraç [[]] arasındaki fark


521

R, bir listenin veya veri çerçevesinin öğelerine erişmek için iki farklı yöntem sağlar: []ve [[]].

İkisi arasındaki fark nedir, hangi durumlarda birini diğerinin üzerinde kullanmalıyım?

Yanıtlar:


327

R Dil Tanımı, bu tür soruları yanıtlamak için kullanışlıdır:

R'nin aşağıdaki örneklerle sözdizimi görüntülendiği üç temel dizin oluşturma operatörü vardır

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

Vektörler ve matrisler için [[formlar , formdan bazı küçük anlamsal farklılıklara sahip olmalarına rağmen nadiren kullanılır [(örneğin, herhangi bir ad veya dimnames özniteliğini düşürür ve karakter indeksleri için kısmi eşleme kullanılır). Tek bir indeks ile çok boyutlu yapılar endekslenmesi, zaman x[[i]]ya da x[i]döner iinci ardışık eleman x.

Listelerde, genellikle [[herhangi bir öğeyi seçmek için kullanılır, oysa [seçilen öğelerin bir listesini döndürür.

[[Oysa bir şekilde, bir tam sayı veya karakter indisleri kullanılarak seçilecek tek bir eleman sağlar [vektörler tarafından endeksleme sağlar. Bununla birlikte, bir liste için indeksin bir vektör olabileceğini ve vektörün her elemanının sırayla listeye, seçilen bileşene, o bileşenin seçilen bileşenine vb. Uygulandığını unutmayın. Sonuç hala tek bir unsurdur.


6
Tek bir sayıyla vs vektörü dizine eklemek için [[vs [kullanmanın arkasındaki neden nedir? Neden sadece ikisini de kullanmıyorsunuz? Sanırım [[tek bir giriş geri almak için kullanabilirsiniz ve [bir dizin ile 1 uzunluğu bir liste döndürür ... ama neden sadece [bir liste yerine tek bir dizin ile tek bir giriş döndürmek değil? Neden bir uzunluk-1 listesinin geri gönderilmesini istesiniz?
wordsforthewise

4
@wordsforthewise, programlama sırasında indeksleme için kullanmak istediğiniz tanımsız uzunlukta bir vektörünüz olabilir. Her [zaman bir liste döndürmek x[v], uzunluğu ne olursa olsun aynı çıktı sınıfını almanız anlamına gelir v. Örneğin, bir isteyebilirsiniz lapplyBir listenin bir alt kümesini aşırı: lapply(x[v], fun). Eğer [uzunluk birinin vektörler için liste düşeceği, bu her bir hata döndürecektir vuzunluk birine sahiptir.
Axeman

1
Sanırım bu daha açık bir şekilde açıklıyor, adv-r.had.co.nz/Subsetting.html
The Red Pea

171

İki yöntem arasındaki önemli farklar, ayıklama için kullanıldıklarında döndürdükleri nesnelerin sınıfı ve bir değer aralığını mı yoksa atama sırasında yalnızca tek bir değeri mi kabul edip edemeyecekleridir.

Aşağıdaki listede veri çıkarma durumunu göz önünde bulundurun:

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

Diyelim ki bool tarafından depolanan değeri foo'dan çıkarmak ve bunu bir if()deyim içinde kullanmak istiyoruz . Bu, veri çıkarımı için dönüş değerleri []ve [[]]ne zaman kullanıldıkları arasındaki farkları gösterecektir . []İse sınıf listesine göre bir yöntem döner nesnelerin (veya data.frame foo eğer data.frame olarak) [[]]yöntemi döndürür olan sınıf değerlerinin türüne göre belirlenir nesneleri.

Bu nedenle, []yöntemi kullanmak aşağıdakileri sağlar:

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

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

Bunun nedeni, []yöntemin bir liste döndürmesi ve listenin doğrudan bir if()ifadeye iletilmesi için geçerli bir nesne olmamasıdır . Bu durumda kullanmamız gerekir, [[]]çünkü uygun sınıfa sahip olacak 'bool' içinde saklanan “çıplak” nesneyi döndürecektir:

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

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

İkinci fark, []operatörün bir veri çerçevesindeki bir liste veya sütun aralığına erişmek için kullanılabilmesi ve [[]]operatörün tek bir yuvaya veya sütuna erişimiyle sınırlı olmasıdır . İkinci bir liste kullanarak değer atama durumunu düşünün bar():

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

Diyelim ki, çubuğun içerdiği verilerle foo'nun son iki yuvasının üzerine yazmak istiyoruz. [[]]Operatörü kullanmaya çalışırsak , olan budur:

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

Bunun nedeni [[]], tek bir öğeye erişim ile sınırlıdır. Kullanmamız gerekenler []:

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

$str
[1] "R"

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

$bool
[1] -0.6291121

Atama başarılı olurken, foo'daki yuvaların orijinal adlarını koruduğunu unutmayın.


111

Çift parantez bir liste öğesine erişirken, tek bir parantez size tek bir öğeyle listeyi geri verir.

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

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

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


48

[]bir liste [[]]çıkarır, listedeki öğeleri çıkarır

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

Sadece burada tekrarlayan indeksleme[[ için donatılmış ekleme .

Bu, @JijoMatthew tarafından yanıtta ima edildi, ancak araştırılmadı.

Belirtildiği gibi ?"[[", söz dizimi gibi x[[y]], nerede length(y) > 1, şöyle yorumlanır:

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

Not Bu o değil arasındaki fark üzerinde ana paket ne olması gerektiğini değiştirmek [ve [[- yani, eski için kullanıldığını subsetting ve ikincisi kullanılır ayıklanması tek liste öğelerini.

Örneğin,

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 değerini almak için şunları yapabiliriz:

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

@ JijoMatthew'un yukarıdaki cevabına geri dönersek şunu hatırlayın r:

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

Özellikle, bu yanlış kullanım sırasında elde etme eğilimimizdeki hataları açıklar [[:

r[[1:3]]

Hata yeri r[[1:3]]: 2. düzeyde yinelemeli dizin oluşturma başarısız oldu

Bu kod gerçekte değerlendirmeye çalıştığından r[[1]][[2]][[3]]ve rdurdurmaların birinci düzeyde iç içe yerleştirilmesinden dolayı , özyinelemeli indeksleme yoluyla çıkartma girişimi [[2]], yani 2. seviyede başarısız oldu .

Hata yeri r[[c("foo", "far")]]: alt simge sınırların dışında

Burada, R arıyordu r[["foo"]][["far"]], ki bu mevcut değildi, bu yüzden alt sınırı sınır hatalarından alıyoruz.

Bu hataların her ikisi de aynı mesajı verirse, muhtemelen biraz daha yararlı / tutarlı olacaktır.


Merhaba Micheal efendim birden fazla indeksleme için [[]] kullanabilir miyiz ??
Kasım'da Therii

14

Her ikisi de alt kümelenmenin yollarıdır. Tek köşeli ayraç listenin kendi içinde bir liste olan bir alt kümesini döndürür. yani: Birden fazla eleman içerebilir veya içermeyebilir. Öte yandan, çift köşeli ayraç listeden yalnızca bir öğe döndürür.

-Tek ayraç bize bir liste verecektir. Listeden birden fazla öğe döndürmek istiyorsak, tek köşeli ayraç da kullanabiliriz. aşağıdaki listeyi göz önünde bulundurun: -

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

Şimdi listeyi görüntülemeye çalıştığımda listenin nasıl döndürüldüğüne dikkat edin. R yazıp enter tuşuna basarım

>r

#the result is:-

[[1]]

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

$foo

[1] 1

$far

[1] 2

Şimdi tek bir parantez büyüsünü göreceğiz: -

>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

Bu, ekranda r değerini görüntülemeye çalıştığımızla tamamen aynı, yani tek bir parantez kullanımı bir liste döndürdü, burada dizin 1'de 10 öğeden oluşan bir vektörümüz var, o zaman foo adlarına sahip iki öğemiz daha var ve uzak. Tek parantez içine girdi olarak tek bir dizin veya öğe adı vermeyi de seçebiliriz. Örneğin:

> r[1]

[[1]]

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

Bu örnekte bir dizin "1" verdik ve karşılığında bir öğe içeren bir liste aldık (10 sayıdan oluşan bir dizi)

> r[2]

$foo

[1] 1

Yukarıdaki örnekte bir dizin "2" verdik ve karşılığında bir öğe içeren bir liste aldık

> r["foo"];

$foo

[1] 1

Bu örnekte bir öğenin adını geçtik ve karşılığında bir öğeyle birlikte bir liste döndürüldü.

Ayrıca, aşağıdakiler gibi öğe adlarının bir vektörünü de iletebilirsiniz: -

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

> r[x];

$foo

[1] 1

$far
[1] 2

Bu örnekte "foo" ve "far" olmak üzere iki öğe adında bir vektör geçtik

Karşılığında iki unsurlu bir liste aldık.

Kısacası, tek bir parantez size her zaman eleman sayısına veya tek parantez içine ilettiğiniz indeks sayısına sahip başka bir liste döndürür.

Buna karşılık, çift köşeli parantez her zaman yalnızca bir öğe döndürür. Çift köşeli paranteze taşınmadan önce akılda tutulması gereken bir not. 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.

Birkaç örnek vereceğim. Lütfen kelimeleri kalın bir şekilde not edin ve aşağıdaki örneklerle işiniz bittikten sonra tekrar yazın:

Çift braket endeksinde size gerçek değerini döndürecektir. (Bu olacak DEĞİL listesini döndürür)

  > r[[1]]

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


  >r[["foo"]]

    [1] 1

çift ​​köşeli parantezler için, bir vektörü ileterek birden fazla öğeyi görüntülemeye çalışırsak, yalnızca bu ihtiyaca cevap vermek için tasarlanmadığı için değil, yalnızca tek bir öğeyi döndürmek için hataya neden olur.

Aşağıdakileri göz önünde bulundur

> 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
"Bir vektörün geçirilmesi ... sadece bu ihtiyaca cevap verecek şekilde inşa edilmediğinden" bir hataya neden olacağından aşağı oy verildi; yeni cevabımı gör.
MichaelChirico

1
"ÇİFT BİR BRAKET ASLA BİR LİSTEYİ DÖNMEYECEKTİR" gibi güçlü iddialarda bulunduğu için indirildi. Bu doğru değil - listeler listesi olan bir nesnemiz varsa, çift parantez başka bir liste döndürür.
dabsingh

13

Yeni başlayanların manuel siste gezinmesine yardımcı olmak için [[ ... ]]gösterimi daraltma işlevi olarak görmek yararlı olabilir - başka bir deyişle, sadece adlandırılmış bir vektör, liste veya veri çerçevesinden 'verileri almak' istersiniz. Hesaplamalar için bu nesnelerden veri kullanmak istiyorsanız bunu yapmak iyi olur. Bu basit örnekler açıklanacaktır.

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

Üçüncü örnekten:

> 2 * x[1]
  x
1 2
> 2 * x[[1]]
[1] 2

1
Bir acemi olarak, "<-" hedefi olan x ile karışıklığı önlemek için x = 1'i w = 1 ile değiştirmeyi x'e 3 atamada ("<-" kullanarak) yararlı buldum
user36800

Çok basit olmasına rağmen, bu açıklamayı gerçekten seviyorum. Başka bir basit gösteri: iris[[1]]bir vektör iris[1]döndürürken bir veri döndürür.
Çerçeve

11

Terminolojik olarak, [[operatör özler ise bir listeden öğeyi [alan operatör alt kümesi , bir liste.


7

Bir başka somut kullanım durumunda, split()fonksiyon tarafından oluşturulan bir veri çerçevesi seçmek istediğinizde çift parantez kullanın . Bilmiyorsanız, split()bir listeyi / veri çerçevesini anahtar alanına göre altkümeler halinde gruplandırır. Birden fazla grupta çalışmak, bunları çizmek vb. İçin yararlıdır.

> 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

Lütfen aşağıdaki ayrıntılı açıklamaya bakın.

R'de mtcars adı verilen yerleşik veri çerçevesini kullandım.

> 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 ... 
           ............

Tablonun en üst satırına sütun adlarını içeren başlık denir. Ardından her yatay çizgi, satır adıyla başlayan ve ardından gerçek verilerle başlayan bir veri satırını gösterir. Bir satırdaki her veri üyesine hücre denir.

tek köşeli ayraç "[]" operatörü

Bir hücredeki verileri almak için, satır ve sütun koordinatlarını tek köşeli parantez "[]" operatörüne gireriz. İki koordinat virgülle ayrılır. Başka bir deyişle, koordinatlar satır konumu ile başlar, ardından virgül ile başlar ve sütun konumu ile biter. Sıra önemlidir.

Örnek 1: - İşte ilk sıra, ikinci mtcars sütunundaki hücre değeri.

> mtcars[1, 2] 
[1] 6

Örnek 2: - Ayrıca, sayısal koordinatlar yerine satır ve sütun adlarını kullanabiliriz.

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

Çift köşeli parantez "[[]]" operatörü

Çift köşeli parantez "[[]]" operatörüyle bir veri çerçevesi sütununa başvuruyoruz.

Örnek 1: - Yerleşik veri kümesi mtcar'larının dokuzuncu sütun vektörünü almak için mtcarlar yazıyoruz [[9]].

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

Örnek 2: - Aynı sütun vektörünü adına göre alabiliriz.

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


-1

Ek olarak:

Aşağıdaki LINK ait CEVAP burada.

Aşağıdaki noktaya değinen küçük bir örnek:

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])
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.