Відповіді:
Визначення мови R зручно відповідати на такі типи питань:
R має три основні оператори індексації, причому синтаксис відображається наступними прикладами
x[i] x[i, j] x[[i]] x[[i, j]] x$a x$"a"
Для векторів і матриць
[[
форми рідко використовуються, хоча вони мають невеликі семантичні відмінності від[
форми (наприклад, вона випадає з будь-яких атрибутів імен чи динаміків, а часткове узгодження використовується для індексів символів). При індексації багатовимірних структур з одним індексомx[[i]]
абоx[i]
повернетьсяi
послідовний елементx
.Для списків, як правило, використовується
[[
для вибору будь-якого одного елемента, тоді як[
повертає список вибраних елементів.
[[
Форма дозволяє тільки один елемент , який буде обраний з допомогою цілочисельних або символьних індексів, в той час як[
дозволяє індексувати векторами. Зауважте, що для списку індекс може бути вектором, і кожен елемент вектора застосовується по черзі до списку, вибраного компонента, вибраного компонента цього компонента тощо. Результат - все одно єдиний елемент.
[
завжди повертати список означає , що ви отримаєте той же клас виведення для x[v]
незалежно від довжини v
. Наприклад, один може знадобитися lapply
більш ніж підмножина списку: lapply(x[v], fun)
. Якщо [
випаде список для векторів довжини один, це поверне помилку, коли v
має довжину один.
Значні відмінності між двома методами - це клас об’єктів, які вони повертають при використанні для вилучення, і чи можуть вони приймати діапазон значень або просто одне значення під час призначення.
Розглянемо випадок вилучення даних у наступному списку:
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 зберігали свої початкові назви.
Подвійні дужки отримують доступ до елемента списку , тоді як одна дужка повертає список з одним елементом.
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"
Просто додамо сюди, що [[
також обладнано для рекурсивної індексації .
Про це натякав у відповіді @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
iris[[1]]
повертає вектор, а iris[1]
повертає data.frame
Будучи термінологічним, [[
оператор вилучає елемент зі списку, тоді як [
оператор бере підмножину списку.
Для ще одного конкретного випадку використання використовуйте подвійні дужки, коли потрібно вибрати кадр даних, створений 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"
Будь ласка, зверніться до пояснення нижче.
Я використовував вбудований фрейм даних в 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 ...
На додачу:
Ось невеликий приклад щодо наступного моменту:
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])