Почему класс (data.frame(...)) не показывает наследование списка?
Часто говорят, что data.frame
наследуется от list
, что имеет смысл, учитывая множество общих парадигм для доступа к столбцам data.frame ($
, sapply
, так далее.).
Еще "list"
не входит в число предметов, возвращаемых в списке классов data.frame
объект:
dat <- data.frame(x=runif(100),y=runif(100),z=runif(100),g=as.factor(rep(letters[1:10],10)))
> class(dat)
[1] "data.frame"
Разоблачение data.frame
показывает, что это список:
> class(unclass(dat))
[1] "list"
И тестирование похоже на то, что метод по умолчанию будет вызываться в предпочтении перед методом list, если метода data.frame нет:
> f <- function(x) UseMethod('f')
> f.default <- function(x) cat("Default")
> f.list <- function(x) cat('List')
> f(dat)
Default
> f.data.frame <- function(x) cat('DF')
> f(dat)
DF
Тогда два вопроса:
- Есть ли неспособность иметь
data.frame
формально наследовать отlist
есть какие-то преимущества с точки зрения дизайна? - Как те функции, которые, кажется, относятся к
data.frame
Как списки знают, как обращаться с ними как со списками? Смотря наlapply
похоже, он довольно быстро переходит к внутреннему коду на C, так что, возможно, это все, но мой ум здесь немного взорван.
1 ответ
Признаюсь, что классы в R меня немного смущают. Но я помню, как однажды прочитал что-то вроде: "В R data.frames фактически являются списками векторов". Используя код из вашего примера, мы можем проверить это:
> is.list(dat)
[1] TRUE
?is.list
Обратите внимание, что мы также можем использовать [[]]
оператор для доступа к элементам (столбцам) dat
, который является обычным способом доступа к элементам списков в R:
> identical(dat$x, dat[[1]])
[1] TRUE
Мы также можем проверить, что каждый столбец на самом деле является вектором:
> is.vector(dat$x)
[1] TRUE