【问题标题】:R vectorize S3 class constructorR矢量化S3类构造函数
【发布时间】:2016-03-10 17:30:51
【问题描述】:

我正在创建一个 S3 类,其中构造函数有多个参数。我想将等长向量传递给构造函数并取回我的新类的对象向量。

myclass <- function(number, letter) {
  this <- list(
    num = number,
    let = letter
  )
  class(this) <- append(class(this), "myclass")
  return(this)
}

df <- data.frame(a = 1:5, b = letters[1:5])

c <- myclass(df$a, df$b)

但 c 不是 myclass 类型的 5 个对象的列表,而是 2 个对象的列表:

> str(c)
List of 2
$ num: int [1:5] 1 2 3 4 5
$ let: Factor w/ 5 levels "a","b","c","d",..: 1 2 3 4 5
- attr(*, "class")= chr [1:2] "list" "myclass"

我可以更改构造函数以使其工作,还是应该使用一些应用函数来调用构造函数?

如果是后者,那么我也无法使用它 - 我认为 mapply 是解决方案,但不是..

编辑:感谢@rawr 的评论,我现在知道c &lt;- mapply(myclass, df$a, df$b, SIMPLIFY = FALSE) 是在这里使用mapply 函数的正确方法,但我们仍然面临着属于构造函数内部还是代码内部的问题调用构造函数。

> c <- mapply(myclass, df$a, df$b)
> str(c)
List of 10
$ : int 1
$ : Factor w/ 5 levels "a","b","c","d",..: 1
$ : int 2
$ : Factor w/ 5 levels "a","b","c","d",..: 2
$ : int 3
$ : Factor w/ 5 levels "a","b","c","d",..: 3
$ : int 4
$ : Factor w/ 5 levels "a","b","c","d",..: 4
$ : int 5
$ : Factor w/ 5 levels "a","b","c","d",..: 5
- attr(*, "dim")= int [1:2] 2 5
- attr(*, "dimnames")=List of 2
..$ : chr [1:2] "num" "let"
..$ : NULL
> class(c[[1]])
[1] "integer"

我认为这个显式循环给出了正确的结果:

c <- list()

for(i in 1:5) {
  c[[i]] <- myclass(df$a[i], df$b[i])
}

> str(c)
List of 5
$ :List of 2
..$ num: int 1
..$ let: Factor w/ 5 levels "a","b","c","d",..: 1
..- attr(*, "class")= chr [1:2] "list" "myclass"
$ :List of 2
..$ num: int 2
..$ let: Factor w/ 5 levels "a","b","c","d",..: 2
..- attr(*, "class")= chr [1:2] "list" "myclass"
$ :List of 2
..$ num: int 3
..$ let: Factor w/ 5 levels "a","b","c","d",..: 3
..- attr(*, "class")= chr [1:2] "list" "myclass"
$ :List of 2
..$ num: int 4
..$ let: Factor w/ 5 levels "a","b","c","d",..: 4
..- attr(*, "class")= chr [1:2] "list" "myclass"
$ :List of 2
..$ num: int 5
..$ let: Factor w/ 5 levels "a","b","c","d",..: 5
..- attr(*, "class")= chr [1:2] "list" "myclass"
> 
> class(c[[1]])
[1] "list"    "myclass"

但我会重复我认为更重要的问题: 我可以更改构造函数以使其工作,还是应该使用一些应用函数(或循环)来调用构造函数?

【问题讨论】:

  • 在你的 mapply 中使用不要使用简化? str(mapply(myclass, df$a, df$b, SIMPLIFY = FALSE))
  • 您是否希望 myclass 仅输出 2 项 length == 1 的“列表”,或者您是否有可能需要 myclass(df$a, df$b) 原样?如果是第一个,我想你必须在myclass 中添加一个循环来“矢量化”它;如果是第二个,那么在需要时添加一个循环可能会更方便,比如 rawr 的。
  • SIMPLIFY = FALSE 部分肯定修复了mapply 功能,谢谢@rawr。这个问题现在变成了设计哲学之一——它属于构造函数,还是调用构造函数的代码?
  • @alexis_laz 我不明白你所做的区分 - 你所说的“原样”是什么意思?
  • @BrianStamper :您是否正在寻找如何myclass 内循环,或者更合适的方法?如果像myclass(df$a, df$b) 这样的输出(当前在您的问题中定义的myclass)永远不可取,那么我想您需要在myclass 内添加循环以避免每次调用时调用循环函数myclass.

标签: r oop constructor vectorization


【解决方案1】:

您只是没有正确使用 R 类型。您需要将myclass 函数应用于每个元素(在本例中为一行)。

c1 <- apply(df, 1, function(i) myclass(i[1], i[2]))
str(c1)
List of 5
 $ :List of 2
  ..$ num: Named chr "1"
  .. ..- attr(*, "names")= chr "a"
  ..$ let: Named chr "a"
  .. ..- attr(*, "names")= chr "b"
  ..- attr(*, "class")= chr [1:2] "list" "myclass"
 $ :List of 2
  ..$ num: Named chr "2"
  .. ..- attr(*, "names")= chr "a"
  ..$ let: Named chr "b"
  .. ..- attr(*, "names")= chr "b"
  ..- attr(*, "class")= chr [1:2] "list" "myclass"
 $ :List of 2
  ..$ num: Named chr "3"
  .. ..- attr(*, "names")= chr "a"
  ..$ let: Named chr "c"
  .. ..- attr(*, "names")= chr "b"
  ..- attr(*, "class")= chr [1:2] "list" "myclass"
 $ :List of 2
  ..$ num: Named chr "4"
  .. ..- attr(*, "names")= chr "a"
  ..$ let: Named chr "d"
  .. ..- attr(*, "names")= chr "b"
  ..- attr(*, "class")= chr [1:2] "list" "myclass"
 $ :List of 2
  ..$ num: Named chr "5"
  .. ..- attr(*, "names")= chr "a"
  ..$ let: Named chr "e"
  .. ..- attr(*, "names")= chr "b"
  ..- attr(*, "class")= chr [1:2] "list" "myclass"

您可以修改您的 myclass 函数,而不是像上面那样在函数调用中使用包装器 (apply)

myclass <- function(number, letter) {
  out <- mapply(function(n, l) {
    l1 <- list(num= n, let= l)
    class(l1) <- "myclass"
    return(l1)
  }, n= number, l= letter, SIMPLIFY= FALSE)
  return(out)
} 

str(myclass(df$a, df$b))
List of 5
 $ :List of 2
  ..$ num: int 1
  ..$ let: Factor w/ 5 levels "a","b","c","d",..: 1
  ..- attr(*, "class")= chr "myclass"
 $ :List of 2
  ..$ num: int 2
  ..$ let: Factor w/ 5 levels "a","b","c","d",..: 2
  ..- attr(*, "class")= chr "myclass"
 $ :List of 2
  ..$ num: int 3
  ..$ let: Factor w/ 5 levels "a","b","c","d",..: 3
  ..- attr(*, "class")= chr "myclass"
 $ :List of 2
  ..$ num: int 4
  ..$ let: Factor w/ 5 levels "a","b","c","d",..: 4
  ..- attr(*, "class")= chr "myclass"
 $ :List of 2
  ..$ num: int 5
  ..$ let: Factor w/ 5 levels "a","b","c","d",..: 5
  ..- attr(*, "class")= chr "myclass"

【讨论】:

    【解决方案2】:

    您似乎正在努力改造一个名为 oldClass&lt;- 的现有 base-R 函数,该函数在帮助页面 ?inherits 上进行了描述。 R 中的“最低”类类型是“逻辑的”,因此制作可以添加类的原子向量的方法是使用logical

    Vec <- logical(5)
    classList <- c("numeric", "character")
    Vec2 <- logical(5)
    oldClass(Vec) <- classList  # not really a true R _list_
    > Vec
    [1] FALSE FALSE FALSE FALSE FALSE
    attr(,"class")
    [1] "numeric"   "character"
    > inherits(Vec2, "character")
    [1] FALSE
    > inherits(Vec, "character")
    [1] TRUE
    

    如果您有一个对象名称列表(通常称为列表)和一个修改函数,那么您可以使用 sapply 或 lapply 对其进行循环以返回修改后的列表:

    vList <- list(Vec, Vec2)
    vList2 <- lapply( vList, 'oldClass<-', classList)
    vList2[[2]]
    #----
    [1] FALSE FALSE FALSE FALSE FALSE
    attr(,"class")
    [1] "numeric"   "character"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多