Подтвердить что ты не робот

Разница между скобками [] и двойными скобками [[]] для доступа к элементам списка или фрейма данных

R предоставляет два разных метода для доступа к элементам списка или оператора data.frame - [] и [[]].

В чем разница между этими двумя? В каких ситуациях я должен использовать один над другим?

4b9b3361

Ответ 1

Определение языка R удобно для ответов на следующие вопросы:

R имеет три основных оператора индексации, синтаксис которых показан в следующих примерах

х [г]
x [i, j]
х [[я]]
x [[i, j]]
х $ а
х $ "а"

Для векторов и матриц формы [[ используются редко, хотя они имеют некоторые небольшие семантические отличия от формы [ (например, она отбрасывает любые атрибуты names или dimnames, и это частичное соответствие используется для индексов символов). При индексации многомерных структур с одним индексом, x[[i]] или x[i] вернут i й последовательный элемент x.

Для списков обычно используется [[ для выбора любого отдельного элемента, тогда как [ возвращает список выбранных элементов.

Форма [[ позволяет выбирать только один элемент, используя целочисленные или символьные индексы, тогда как [ позволяет индексировать по векторам. Обратите внимание, что для списка индекс может быть вектором, и каждый элемент вектора применяется по очереди к списку, выбранному компоненту, выбранному компоненту этого компонента и так далее. Результат по-прежнему один элемент.

Ответ 2

Значительные различия между этими двумя методами - это класс возвращаемых ими объектов при использовании для извлечения и могут ли они принимать диапазон значений или просто одно значение при назначении.

Рассмотрим случай извлечения данных в следующем списке:

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

Скажем, мы хотели бы извлечь значение, сохраненное bool из foo, и использовать его внутри оператора if(). Это иллюстрирует различия между значениями возврата [] и [[]], когда они используются для извлечения данных. Метод [] возвращает объекты списка классов (или data.frame, если foo был 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"

Второе отличие состоит в том, что оператор [] может использоваться для доступа к слотам диапазона в списке или столбцах в кадре данных, в то время как оператор [[]] ограничен доступом к одиночный слот или столбец. Рассмотрим случай присвоения значений, используя второй список, bar():

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

Скажем, мы хотим перезаписать последние два слота foo данными, содержащимися в баре. Если мы попытаемся использовать оператор [[]], то это произойдет:

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 сохранили свои оригинальные имена.

Ответ 3

Двойные скобки обращаются к элементу списка , а одна скобка возвращает вам список с одним элементом.

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

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

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

Ответ 4

[] извлекает список, [[]] извлекает элементы из списка

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"

Ответ 5

От Хэдли Уикхема:

From Hadley Wickham

Моя (дерьмовая) модификация, показывающая использование tidyverse/purrr:

enter image description here

Ответ 6

Просто добавив, что [[ также оснащен рекурсивной индексацией.

Это было намечено в ответе @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 останавливается на первом уровне, попытка извлечь из рекурсивной индексации завершилась с ошибкой [[2]], то есть на уровне 2.

Ошибка в r[[c("foo", "far")]]: индекс за пределами

Здесь R искал r[["foo"]][["far"]], которого не существует, поэтому мы получаем ошибку индекса за пределами границ.

Вероятно, было бы немного более полезно/непротиворечиво, если бы обе эти ошибки дали одно и то же сообщение.

Ответ 7

Чтобы помочь новичкам перемещаться по ручному туману, может быть полезно увидеть нотацию [[ ... ]] как функцию свертывания - другими словами, именно тогда, когда вы просто хотите "получить данные" из именованного вектора, перечислите или кадра данных. Это полезно сделать, если вы хотите использовать данные из этих объектов для расчетов. Эти простые примеры иллюстрируют.

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

Итак, из третьего примера:

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

Ответ 8

Оба они являются способами подмножества. Одиночная скобка вернет подмножество списка, которое само по себе будет списком. т.е. может содержать или не содержать более одного элемента. С другой стороны, двойная скобка вернет только один элемент из списка.

-Single скобка даст нам список. Мы также можем использовать одну скобку, если мы хотим вернуть несколько элементов из списка. рассмотрим следующий список:

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

Теперь обратите внимание, как возвращается список, когда я пытаюсь его отобразить. Я набираю r и нажимаю ввод

>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 и далеко. Мы также можем выбрать один индекс или имя элемента в качестве ввода для одной скобки. например:

> r[1]

[[1]]

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

В этом примере мы дали один индекс "1" и взамен получили список с одним элементом (который представляет собой массив из 10 чисел)

> r[2]

$foo

[1] 1

В приведенном выше примере мы дали один индекс "2" и взамен получили список с одним элементом

> r["foo"];

$foo

[1] 1

В этом примере мы передали имя одного элемента, а взамен был возвращен список с одним элементом.

Вы также можете передать вектор имен элементов, таких как: -

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

> r[x];

$foo

[1] 1

$far
[1] 2

В этом примере мы передали вектор с двумя именами элементов "foo" и "far"

Взамен мы получили список с двумя элементами.

Короче говоря, одна скобка всегда вернет вам другой список с количеством элементов, равным количеству элементов или количеству индексов, которые вы передаете в одну скобку.

Напротив, двойная скобка всегда будет возвращать только один элемент. Прежде чем переходить на двойные скобки, следует помнить. 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

Ответ 9

Будучи терминологическим, оператор [[ извлекает элемент из списка, тогда как оператор [ принимает подмножество списка.

Ответ 10

Для еще одного конкретного варианта использования используйте двойные скобки, когда вы хотите выбрать фрейм данных, созданный функцией 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"

Ответ 11

К тому же:

Следуя ССЫЛКА ОТВЕТА здесь.

Вот небольшой пример, посвященный следующему пункту:

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

Ответ 12

Пожалуйста, обратитесь к ниже подробному объяснению.

Я использовал встроенный фрейм данных в R, называемый 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 ... 
           ............

Верхняя строка таблицы называется заголовком, который содержит имена столбцов. Каждая горизонтальная линия впоследствии обозначает строку данных, которая начинается с имени строки, а затем за ней следуют фактические данные. Каждый элемент данных строки называется ячейкой.

одиночная квадратная скобка "[]"

Для извлечения данных в ячейке мы вводим его координаты строк и столбцов в одиночном квадратном скобке "[]". Две координаты разделены запятой. Другими словами, координаты начинаются с позиции строки, затем за запятой и заканчиваются позицией столбца. Порядок важен.

Например, 1: - Здесь значение ячейки из первой строки, второй столбец mtcars.

> mtcars[1, 2] 
[1] 6

Например, 2: - Кроме того, мы можем использовать имена строк и столбцов вместо числовых координат.

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

Двойная квадратная скобка "[[]]" оператор

Мы ссылаемся на столбец фреймов данных с помощью оператора двойной квадратной скобки [[]].

Например, 1: - Чтобы получить девятый вектор столбца встроенного набора данных mtcars, мы пишем 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...