Всеобъемлющий обзор типов вещей в R. "mode", "class" и "typeof" недостаточен
язык R смущает меня. Сущности имеют режимы и классы, но даже этого недостаточно для полного описания сущности.
этой ответ говорит
в R каждый "объект" имеет режим и класс.
Итак, я провел эти эксперименты:
> class(3)
[1] "numeric"
> mode(3)
[1] "numeric"
> typeof(3)
[1] "double"
справедливо до сих пор, но затем я прошел в векторе вместо этого:
> mode(c(1,2))
[1] "numeric"
> class(c(1,2))
[1] "numeric"
> typeof(c(1,2))
[1] "double"
это не имеет смысла. Конечно вектор целых чисел должен иметь другой класс или другой режим, чем одно целое число? Мои вопросы:
- все ли в R есть (ровно один)класс ?
- все ли в R есть (ровно один)режим ?
- что, если что-нибудь, говорит нам "typeof"?
- какая другая информация необходима для полного описания сущности? (Где 'vectorness' хранится, пример?)
обновление: по-видимому, литерал 3 - это просто вектор длины 1. Скаляров нет. ОК но... Я пытался!--2--> и получил "character"
, заставляя меня думать, что строка была вектором символов. Но если это правда, то это должно быть правдой, но это не так! c('h','i') == "hi"
4 ответов
я согласен, что система типов в R довольно странно. Причина этого в том, что он эволюционировал в течение (долгого) времени...
обратите внимание, что вы пропустили еще одну функцию типа,storage.mode
, и еще одна классовая функция,oldClass
.
и mode
и storage.mode
- старый стиль (где storage.mode
точнее), и typeof
более новая, даже более точная версия.
mode(3L) # numeric
storage.mode(3L) # integer
storage.mode(`identical`) # function
storage.mode(`if`) # function
typeof(`identical`) # closure
typeof(`if`) # special
затем class
это совсем другая история. class
в основном просто class
атрибут объекта (это именно то, что oldClass
returns). Но когда атрибут class не установлен,class
функция составляет класс из типа объекта и атрибута dim.
oldClass(3L) # NULL
class(3L) # integer
class(structure(3L, dim=1)) # array
class(structure(3L, dim=c(1,1))) # matrix
class(list()) # list
class(structure(list(1), dim=1)) # array
class(structure(list(1), dim=c(1,1))) # matrix
class(structure(list(1), dim=1, class='foo')) # foo
наконец, класс может возвращать более одной строки, но только если атрибут class похож на это. Первое строковое значение тогда вид главный класс, и следующие из них, что он наследует от. Составленные классы всегда длины 1.
# Here "A" inherits from "B", which inherits from "C"
class(structure(1, class=LETTERS[1:3])) # "A" "B" "C"
# an ordered factor:
class(ordered(3:1)) # "ordered" "factor"
вот некоторый код, чтобы определить, что четыре типа функций,класс, режим, typeof на и хранения.режим вернуться для каждого из видов объекта R.
library(methods)
library(dplyr)
library(xml2)
setClass("dummy", representation(x="numeric", y="numeric"))
types <- list(
"logical vector" = logical(),
"integer vector" = integer(),
"numeric vector" = numeric(),
"complex vector" = complex(),
"character vector" = character(),
"raw vector" = raw(),
factor = factor(),
"logical matrix" = matrix(logical()),
"numeric matrix" = matrix(numeric()),
"logical array" = array(logical(8), c(2, 2, 2)),
"numeric array" = array(numeric(8), c(2, 2, 2)),
list = list(),
pairlist = .Options,
"data frame" = data.frame(),
"closure function" = identity,
"builtin function" = `+`,
"special function" = `if`,
environment = new.env(),
null = NULL,
formula = y ~ x,
expression = expression(),
call = call("identity"),
name = as.name("x"),
"paren in expression" = expression((1))[[1]],
"brace in expression" = expression({1})[[1]],
"S3 lm object" = lm(dist ~ speed, cars),
"S4 dummy object" = new("dummy", x = 1:10, y = rnorm(10)),
"external pointer" = read_xml("<foo><bar /></foo>")$node
)
type_info <- Map(
function(x, nm)
{
data_frame(
"spoken type" = nm,
class = class(x),
mode = mode(x),
typeof = typeof(x),
storage.mode = storage.mode(x)
)
},
types,
names(types)
) %>% bind_rows
knitr::kable(type_info)
вот вывод:
|spoken type |class |mode |typeof |storage.mode |
|:-------------------|:-----------|:-----------|:-----------|:------------|
|logical vector |logical |logical |logical |logical |
|integer vector |integer |numeric |integer |integer |
|numeric vector |numeric |numeric |double |double |
|complex vector |complex |complex |complex |complex |
|character vector |character |character |character |character |
|raw vector |raw |raw |raw |raw |
|factor |factor |numeric |integer |integer |
|logical matrix |matrix |logical |logical |logical |
|numeric matrix |matrix |numeric |double |double |
|logical array |array |logical |logical |logical |
|numeric array |array |numeric |double |double |
|list |list |list |list |list |
|pairlist |pairlist |pairlist |pairlist |pairlist |
|data frame |data.frame |list |list |list |
|closure function |function |function |closure |function |
|builtin function |function |function |builtin |function |
|special function |function |function |special |function |
|environment |environment |environment |environment |environment |
|null |NULL |NULL |NULL |NULL |
|formula |formula |call |language |language |
|expression |expression |expression |expression |expression |
|call |call |call |language |language |
|name |name |name |symbol |symbol |
|paren in expression |( |( |language |language |
|brace in expression |{ |call |language |language |
|S3 lm object |lm |list |list |list |
|S4 dummy object |dummy |S4 |S4 |S4 |
|external pointer |externalptr |externalptr |externalptr |externalptr |
типы объектов, доступных в R, обсуждаются в R Определение Языка руководство. Есть несколько типов, не упомянутых здесь: вы не можете тестировать объекты типа "promise", "...", и "Любой", "байт-код" и "weakref" доступны только на уровне C.
таблица доступных типов в источнике R -здесь.
добавление к одному из ваших под-вопросов:
- какая другая информация необходима для полного описания сущности?
кроме class
, mode
, typeof
, attributes
, str
и так далее is()
также стоит отметить.
is(1)
[1] "numeric" "vector"
хотя это полезно, это также неудовлетворительно. В этом примере 1
больше, чем просто это; это также атомарный, конечный и двойной. Следующая функция должна показывать все, что объект в соответствии со всеми доступными is.(...)
функции:
what.is <- function(x, show.all=FALSE) {
# set the warn option to -1 to temporarily ignore warnings
op <- options("warn")
options(warn = -1)
on.exit(options(op))
list.fun <- grep(methods(is), pattern = "<-", invert = TRUE, value = TRUE)
result <- data.frame(test=character(), value=character(),
warning=character(), stringsAsFactors = FALSE)
# loop over all "is.(...)" functions and store the results
for(fun in list.fun) {
res <- try(eval(call(fun,x)),silent=TRUE)
if(class(res)=="try-error") {
next() # ignore tests that yield an error
} else if (length(res)>1) {
warn <- "*Applies only to the first element of the provided object"
value <- paste(res,"*",sep="")
} else {
warn <- ""
value <- res
}
result[nrow(result)+1,] <- list(fun, value, warn)
}
# sort the results
result <- result[order(result$value,decreasing = TRUE),]
rownames(result) <- NULL
if(show.all)
return(result)
else
return(result[which(result$value=="TRUE"),])
}
Итак, теперь мы получаем более полную картину:
> what.is(1)
test value warning
1 is.atomic TRUE
2 is.double TRUE
3 is.finite TRUE
4 is.numeric TRUE
5 is.vector TRUE
> what.is(CO2)
test value warning
1 is.data.frame TRUE
2 is.list TRUE
3 is.object TRUE
4 is.recursive TRUE
вы также получаете больше информации с аргументом show.all=TRUE
. Я не вставив ни одного примера как результат более 50 строк.
наконец, это означает дополнительный источник информации, а не замену какой-либо из других упомянутых функций ранее.
редактировать
чтобы включить еще больше функций "is", согласно комментарию @Erdogan, вы можете добавить этот бит в функцию:
# right after
# list.fun <- grep(methods(is), pattern = "<-", invert = TRUE, value = TRUE)
list.fun.2 <- character()
packs <- c('base', 'utils', 'methods') # include more packages if needed
for (pkg in packs) {
library(pkg, character.only = TRUE)
objects <- grep("^is.+\w$", ls(envir = as.environment(paste('package', pkg, sep = ':'))),
value = TRUE)
objects <- grep("<-", objects, invert = TRUE, value = TRUE)
if (length(objects) > 0)
list.fun.2 <- append(list.fun.2, objects[sapply(objects, function(x) class(eval(parse(text = x))) == "function")])
}
list.fun <- union(list.fun.1, list.fun.2)
# ...and continue with the rest
result <- data.frame(test=character(), value=character(),
warning=character(), stringsAsFactors = FALSE)
# and so on...
все ли в R имеет (точно один) класс ?
точно один определенно не прав:
> x <- 3
> class(x) <- c("hi","low")
> class(x)
[1] "hi" "low"
все имеет (по крайней мере, один) класс.
все ли в R имеет (точно один) режим ?
не уверен, но подозреваю, что да.
что, если что-нибудь, говорит нам "typeof"?
typeof
дает внутренний тип объекта. Возможное значение согласно ?typeof
являются:
векторные типы "логические", "целочисленные", "двойные", " сложные", "символ", " raw " и "list", "NULL", "closure" (функция), " special" и " builtin "(основные функции и операторы), "окружающая среда", " S4" (некоторые объекты S4) и другие, которые вряд ли будут видны пользователю уровень ("символ", "pairlist", "обещание", "язык", "char","...", "любой", "выражение", "externalptr"," байт-код " и "weakref").
mode
полагается на оператора typeof. От ?mode
:
режимы имеют тот же набор имен, что и типы (см. typeof), за исключением типы "integer" и "double"возвращаются как "numeric". типы "special" и "builtin"возвращаются как "функция". тип "символ" называется режимом "имя". тип "language" возвращается как " ("или " call".
какая другая информация необходима для полного описания сущности? (Где в 'listness' хранить, например?)
список имеет список классов:
> y <- list(3)
> class(y)
[1] "list"
вы имеете в виду векторизацию? length
должно быть достаточно для большинства целей:
> z <- 3
> class(z)
[1] "numeric"
> length(z)
[1] 1
думать 3
как числовой вектор длины 1, а не как некоторый примитивный числовой тип.
вывод
вы можете получить, просто отлично с class
и length
. К тому времени, когда вам понадобятся другие вещи, у вас, вероятно, не будет спросить, для чего они нужны :-)