web-dev-qa-db-ja.com

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のすべてに(正確に1つ)クラスがありますか?
  • Rのすべてに(正確に1つ)モードがありますか?
  • 'typeof'は、もしあれば、何を教えてくれますか?
  • エンティティを完全に説明するには、他にどのような情報が必要ですか? (たとえば、「ベクトル性」はどこに保存されますか?)

Update:どうやら、リテラル3は長さ1の単なるベクトルです。スカラーはありません。 OKしかし...私はmode("string")を試し、_"character"_を取得したので、文字列は文字のベクトルであると思いました。しかし、それが本当なら、これは本当のはずですが、そうではありません! c('h','i') == "hi"

43
Aaron McDaid

Rの型システムはかなり奇妙だと私は同意します。そのようになっている理由は、それが(長い)時間をかけて進化してきたからです...

もう1つの型のような関数storage.modeともう1つのクラスのような関数oldClassを見逃していることに注意してください。

したがって、modestorage.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属性が設定されていない場合、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

最後に、クラスは複数の文字列を返すことができますが、クラス属性がそのようなものである場合に限ります。その場合、最初の文字列値は種類メインクラスであり、次の値はそれが継承するものです。構成されたクラスの長さは常に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"
53
Tommy

これは、4つの型関数、 classmodetypeof 、および storage.mode returnを判別するためのコードです。 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」、「...」、および「ANY」のオブジェクトをテストすることはできません。「bytecode」および「weakref」は、経営幹部レベルでのみ使用できます。

Rソースで使用可能なタイプのテーブルは ここ です。

17
Richie Cotton

サブ質問の1つに追加する:

  • エンティティを完全に説明するには、他にどのような情報が必要ですか?

classmodetypeofattributesstrなどに加えて、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行を超えるため、ここでは例を貼り付けていません。

最後に、これは補足的な情報源として意図されており、前述の他の機能の代わりとしてではありません。

[〜#〜]編集[〜#〜]

@Erdoganのコメントに従って、さらに多くの「is」関数を含めるには、次のビットを関数に追加できます。

_  # 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...
_
13
Dominic Comtois

Rのすべてに(正確に1つの)クラスがありますか?

正確に1つは間違いなく正しくありません:

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

すべてに(少なくとも1つの)クラスがあります。

Rのすべてに(正確に1つの)モードがありますか?

確かではありませんが、私はそう思う。

「typeof」は何を教えてくれますか?

typeofは、オブジェクトの内部型を示します。 ?typeofによる可能な値は次のとおりです。

ベクトルタイプ「logical」、「integer」、「double」、「complex」、「character」、「raw」、「list」、「NULL」、「closure」(関数)、「special」、「builtin」(基本的な関数と演算子)、「environment」、「S4」(一部のS4オブジェクト)など、ユーザーレベルでは表示されにくいもの(「symbol」、「pairlist」、「promise」、「language」、「char」、 「...」、「any」、「expression」、「externalptr」、「bytecode」、「weakref」)。

modeはtypeofに依存しています。 ?modeから:

モードには、タイプ「integer」と「double」が「numeric」として返されることを除いて、タイプと同じ名前のセットがあります(typeofを参照)。タイプ「special」および「builtin」は「function」として返されます。タイプ「シンボル」はモード「名前」と呼ばれます。タイプ「言語」は「(」または「呼び出し」として返されます。

エンティティを完全に説明するために必要な他の情報は何ですか?(たとえば、「リスト」はどこに保存されますか?)

リストにはクラスリストがあります。

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

ベクトル化のことですか? lengthは、ほとんどの目的に十分なはずです。

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

3は、基本的な数値型ではなく、長さ1の数値ベクトルと考えてください。

結論

classlengthでうまくいくことができます。あなたが他のものを必要とする時までに、あなたはおそらくそれらが何のためにあるのか尋ねる必要はないでしょう:-)

12
Ari B. Friedman