Почему назначение элементов в несуществующем столбце data.frame работает? - PullRequest
7 голосов
/ 22 июня 2011

Вдохновленный Q6437164 : может кто-нибудь объяснить мне, почему работает следующее:

iriscopy<-iris #or whatever other data.frame
iriscopy$someNonExistantColumn[1]<-15

Мне кажется не очевидным, как R интерпретирует это утверждение как: создать новый столбецс именем someNonExistantColumn в data.frame и установите первое значение (фактически, все значения, как кажется) на значение 15.

Ответы [ 2 ]

10 голосов
/ 22 июня 2011

Руководство по определению языка R дает нам указатель на то, как R оценивает выражения вида:

x$foo[1] <- 15

а именно, как если бы мы назвали

`*tmp*` <- x
x <- "$<-.data.frame"(`*tmp*`, name = "foo", 
                      value = "[<-.data.frame"("$.data.frame"(`*tmp*`, "foo"), 
                                               1, value = 15))
rm(`*tmp*`)

со средним битом будет легче разобраться, если мы отбросим для целей изложения фактические используемые методы:

x <- "$<-"(`*tmp*`, name = "foo", 
           value = "[<-"("$"(`*tmp*`, "foo"), 1, value = 15))

Чтобы вернуться к вашему примеру, используя iris, у нас есть что-то вроде

iris$foo[1] <- 15

Здесь функции оцениваются рекурсивно. Сначала функция извлечения "$" используется для доступа к компоненту "foo" из iris, то есть NULL:

> "$"(iris, "foo")
NULL

Затем "[<-" используется для замены первого элемента возвращенного выше объекта (NULL) значением 15, то есть вызовом:

> "[<-"(NULL, 1, value = 15)
[1] 15

Теперь этот объект используется в качестве аргумента value во внешней части нашего вызова, а именно в присваивании с использованием "$<-":

> head("$<-"(iris, "foo", value = 15))
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species foo
1          5.1         3.5          1.4         0.2  setosa  15
2          4.9         3.0          1.4         0.2  setosa  15
3          4.7         3.2          1.3         0.2  setosa  15
4          4.6         3.1          1.5         0.2  setosa  15
5          5.0         3.6          1.4         0.2  setosa  15
6          5.4         3.9          1.7         0.4  setosa  15

(здесь обернуто в head() для ограничения числа отображаемых строк.)

Это, надеюсь, объясняет, как функция вызывает прогресс. Последняя проблема, с которой приходится сталкиваться - почему весь вектор foo установлен в 15? Ответ на этот вопрос дан в разделе «Подробности» ?"$<-.data.frame":

Details:

....

         Note that there is no ‘data.frame’ method for ‘$’, so ‘x$name’
     uses the default method which treats ‘x’ as a list.  There is a
     replacement method which checks ‘value’ for the correct number of
     rows, and replicates it if necessary.

Ключевой бит - это последнее предложение. В приведенном выше примере самое внешнее назначение используется value = 15. Но на этом этапе мы хотим заменить весь компонент "foo", который имеет длину nrow(iris). Следовательно, в действительности используется value = rep(15, nrow(iris)) в самом внешнем вызове присваивания / функции.

Этот пример еще более сложен, потому что вам нужно преобразовать из удобной записи

x$foo[1] <- 15

в правильные вызовы функций с использованием "$<-"(), "[<-"() и "$"(). Пример в разделе 3.4.4 определения языка R использует этот более простой пример:

names(x)[3] <- "Three"

, что оценивается как

`*tmp*` <- x
x <- "names<-"(`*tmp*`, value="[<-"(names(`*tmp*`), 3, value="Three"))
rm(`*tmp*`)

, что немного легче разобраться, потому что names() выглядит как обычный вызов функции.

3 голосов
/ 22 июня 2011

Я думаю, что ответ в том, что это не работает.

Я считаю $newcol стандартным поведением для создания нового столбца. Например:

iris$newcol <- 1

создаст новый столбец в iris data.frame. Все значения будут равны 1 из-за повторного использования вектора.

Это создание нового столбца запускается, когда выражение оценивается как NULL. От? $<-:

  • "Когда $ <- применяется к NULL x, он сначала приводит x к list (). Это также происходит с [[<- если значение замещающего значения имеет длину больше единицы: if значение имеет длину 1 или 0, x сначала приводится к вектору нулевой длины типа значения. "</em>

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

Редактировать

Синтаксический анализ, вероятно, работает с использованием $ -assign $<-, а не скобки-присваивания [<-. Сравните:

head(`$<-`(iris, newcol, 1))
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species newcol
1          5.1         3.5          1.4         0.2  setosa      1
2          4.9         3.0          1.4         0.2  setosa      1
3          4.7         3.2          1.3         0.2  setosa      1
4          4.6         3.1          1.5         0.2  setosa      1
5          5.0         3.6          1.4         0.2  setosa      1
6          5.4         3.9          1.7         0.4  setosa      1

Но присвоение скобок выдает ошибку:

head(`[<-`(iris, newcol, 1))
Error in head(`[<-`(iris, newcol, 1)) : 
  error in evaluating the argument 'x' in selecting a method for function 'head': Error in is.atomic(value) : 'value' is missing
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...