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

StackOverflow https://stackoverflow.com/questions/1169456

Вопрос

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

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

Это было полезно?

Решение

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

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

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

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

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

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

Другие советы

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

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

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

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

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 сохранили свои первоначальные названия.

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

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

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

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

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

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"

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

From Hadley Wickham

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

enter image description here

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

На это намекнул @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[["foo"]][["far"]], которого не существует, поэтому мы получаем ошибку выхода за пределы нижнего индекса.

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

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

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

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

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

>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

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

(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

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

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

Кроме того:

После СВЯЗЬ принадлежащий ОТВЕЧАТЬ здесь.

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top