Всестороннее исследование типов вещей в "режиме" и "классе" и "типе" недостаточно

Язык 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"?
  • Какая еще информация необходима для полного описания объекта? (Где хранится "векторность", например?)

Обновить. По-видимому, буква 3 является всего лишь вектором длины 1. Нет скаляров. OK Но... Я пробовал mode("string") и получил "character", что заставило меня думать, что строка является вектором символов. Но если это правда, тогда это должно быть правдой, но это не так! c('h','i') == "hi"

Ответ 1

Я согласен, что система типов в 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). Но когда атрибут класса не задан, функция 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"

Ответ 2

Все ли в R есть (только один) класс?

Точно одно однозначно неверно:

> x <- 3
> class(x) <- c("hi","low")
> class(x)
[1] "hi"  "low"

У всех есть (по крайней мере один) класс.

Все ли в R есть (только один) режим?

Не уверен, но я подозреваю, что так.

Что, если что-нибудь, говорит нам "typeof"?

typeof дает внутренний тип объекта. Возможные значения в соответствии с ?typeof:

Типы векторов "логический", "целочисленный", "двойной", "сложный", "character", "raw" и "list", "NULL", "замыкание" (функция), "специальный", и "встроенные" (базовые функции и операторы), "среда", "S4", (некоторые объекты S4) и другие, которые вряд ли будут видны у пользователя ( "символ", "парный список", "обещание", "язык", "char", "...", "any", "expression", "externalptr", "bytecode" и "weakref" ).

mode полагается на typeof. От ?mode:

Режимы имеют одинаковый набор имен как типы (см. typeof), за исключением того, что типы "integer" и "double" возвращаются как "числовые". типы "специальные" и "встроенные" возвращаются как "функция". Тип "символ" называется режимом "имя". type "language" возвращается как "(" или "call".

Какая еще информация необходима для полного описания объекта? (Где хранится "список", например?)

Список имеет список классов:

> y <- list(3)
> class(y)
[1] "list"

Вы имеете в виду векторизацию? length должно быть достаточным для большинства целей:

> z <- 3
> class(z)
[1] "numeric"
> length(z)
[1] 1

Вспомните 3 как числовой вектор длины 1, а не как некоторый примитивный числовой тип.

Заключение

Вы можете отлично справиться с class и length. К тому времени, когда вам понадобятся другие вещи, вам, вероятно, не придется спрашивать, для чего они предназначены: -)

Ответ 3

Здесь некоторый код для определения функций четырех типов, class, mode, typeof и storage.mode возвращает для каждого из видов объекта 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,
  "primitive 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     |
|primitive 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 Language Definition. Существует несколько типов, не упомянутых здесь: вы не можете тестировать объекты типа "обещание", "..." и "ЛЮБОЙ", а "байт-код" и "слабый" доступны только на уровне C.

Таблица доступных типов в источнике R здесь.

Ответ 4

Добавление к одному из ваших вопросов:

  • Какая еще информация необходима для полного описания объекта?

В дополнение к 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 строк.

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