对R中事物类型的综合调查; 'mode'和'class'和'typeof'是不够的

Aar*_*aid 43 r language-lawyer r-faq

语言R让我困惑.实体具有模式和类,但即使这不足以完全描述实体.

这个答案说

在R中,每个"对象"都有一个模式和一个类.

所以我做了这些实验:

> class(3)
[1] "numeric"
> mode(3)
[1] "numeric"
> typeof(3)
[1] "double"
Run Code Online (Sandbox Code Playgroud)

到目前为止公平,但后来我传入了一个向量:

> mode(c(1,2))
[1] "numeric"
> class(c(1,2))
[1] "numeric"
> typeof(c(1,2))
[1] "double"
Run Code Online (Sandbox Code Playgroud)

这没有意义.当然,整数向量应该具有与单个整数不同的类或不同的模式吗?我的问题是:

  • R中的所有内容都有(只有一个)类吗?
  • R中的所有内容都有(只有一种)模式吗?
  • 什么,如果有的话,'typeof'告诉我们什么?
  • 完整描述实体还需要哪些其他信息?(例如,'矢量'存储在哪里?)

更新:显然,文字3只是长度为1的向量.没有标量.好吧但是......我试过mode("string")了"character",让我觉得字符串是一个字符向量.但如果这是真的,那么这应该是真的,但事实并非如此!c('h','i') == "hi"

Tom*_*mmy 53

我同意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
Run Code Online (Sandbox Code Playgroud)

然后class是一个完全不同的故事.class主要class是对象的属性(这正是oldClass返回的属性).但是,当未设置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
Run Code Online (Sandbox Code Playgroud)

最后,该类可以返回多个字符串,但前提是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"
Run Code Online (Sandbox Code Playgroud)


Ric*_*ton 17

下面是一些代码,用于确定每种R对象的四种类型函数,类,模式,typeof和storage.mode返回值.

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)
Run Code Online (Sandbox Code Playgroud)

这是输出:

|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  |
Run Code Online (Sandbox Code Playgroud)

R语言定义手册中讨论了R中可用的对象类型.这里没有提到的几种类型:您无法测试"promise","..."和"ANY"类型的对象,"bytecode"和"weakref"仅在C级可用.

R源中可用类型的表格在这里.

  • @ coder.in.me因为此时,`mode`和`storage.mode`是S遗留下来的遗留功能。您只需要关心`class()`和`typeof()`。 (2认同)

Dom*_*ois 13

添加到您的一个子问题:

  • 完整描述实体还需要哪些其他信息?

此外class,mode,typeof,attributes,str,等,is()也是值得注意的.

is(1)
[1] "numeric" "vector"
Run Code Online (Sandbox Code Playgroud)

虽然有用,但也不令人满意.在这个例子中,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"),])
}
Run Code Online (Sandbox Code Playgroud)

所以现在我们得到一个更完整的图片:

> 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 
Run Code Online (Sandbox Code Playgroud)

您还可以获得有关参数的更多信息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...
Run Code Online (Sandbox Code Playgroud)


Ari*_*man 12

R中的所有内容都有(只有一个)类吗?

肯定是一个绝对不对:

> x <- 3
> class(x) <- c("hi","low")
> class(x)
[1] "hi"  "low"
Run Code Online (Sandbox Code Playgroud)

一切都有(至少一个)课程.

R中的所有内容都有(只有一种)模式吗?

不确定,但我怀疑.

什么,如果有的话,'typeof'告诉我们什么?

typeof给出对象的内部类型.根据的可能值?typeof是:

向量类型"逻辑","整数","双","复杂","字符","原始"和"列表","空白","封闭"(功能),"特殊"和"内置"(基本功能和操作员),"环境","S4"(一些S4对象)和其他不太可能在用户级别看到的("符号","pairlist","promise","language","char", "...","any","expression","externalptr","bytecode"和"weakref").

mode依赖于typeof.来自?mode:

模式与类型具有相同的名称集(请参阅typeof),但"integer"和"double"类型返回为"numeric".类型"特殊"和"内置"作为"功能"返回.类型"符号"称为模式"名称".类型"语言"返回为"("或"呼叫".

完整描述实体还需要哪些其他信息?(例如,'listness'存储在哪里?)

列表包含班级列表:

> y <- list(3)
> class(y)
[1] "list"
Run Code Online (Sandbox Code Playgroud)

你的意思是矢量化吗? length应该足以满足大多数目的:

> z <- 3
> class(z)
[1] "numeric"
> length(z)
[1] 1
Run Code Online (Sandbox Code Playgroud)

可以将其3视为长度为1的数字向量,而不是某些原始数字类型.

结论

你可以用class和完成length.当你需要其他东西的时候,你可能不必问他们的用途:-)

  • `attributes`也可能很方便. (4认同)
  • 正如我在答案中所示,带有`dim`属性的`list`是*not*of class"list". (2认同)