as.data.frame(x) 和 as(x, "data.frame") 的区别

Posted

技术标签:

【中文标题】as.data.frame(x) 和 as(x, "data.frame") 的区别【英文标题】:Difference between as.data.frame(x) and as(x, "data.frame") 【发布时间】:2015-10-09 20:29:44 【问题描述】:

我会保持简单。为什么会这样:

> as.data.frame(c('a', 'b'))
  c("a", "b")
1           a
2           b

但这不是:

> as(c('a', 'b'), "data.frame")
Error in as(c("a", "b"), "data.frame") : 
  no method or default for coercing “character” to “data.frame”

我认为后者会以某种方式简单地转换为前者,但我想不会。

【问题讨论】:

我总是将普通的 as 函数与 R 的 S4 对象系统相关联(尽管我对 S4 了解不多,但从未真正使用过它)。所以我一直认为它与as.data.frameas.integer等函数是分开的。 【参考方案1】:

也许 R 的作者认为复制第一种方法会鼓励糟糕的编码实践。第一个结果看起来并不特别值得效仿,因为列的名称不容易使用。字符值的 data.frame 方法提供了更好的行为结果,因为它是使用有效名称创建的:

> as.data.frame(c('a','b'))
  c("a", "b")
1           a
2           b

data.frame(c('a','b'))
  c..a....b..
1           a
2           b

看看当您尝试使用该列的名称提取值时会发生什么。既然每个人都知道数据帧实际上是列表对象,(对吗?)...那么期望编码人员使用列表参数会更自然:

data.frame(list(b=c('a', 'b'))  )
  b
1 a
2 b

# same as
> as.data.frame(list(f=c('a','b')))
  f
1 a
2 b

Alex 的回答将您引导至as-function 代码,该代码详细说明并确认了上面 joran 的评论。该函数不使用 S3 调度,而是查找已注册的由包创建或使用 setAs 构造的强制方法,这是一个更常用于构建 S4 方法的过程。

> setAs("character", "data.frame", function(from) to=as.data.frame.character(from))
> new=as(c('a', 'b'), "data.frame")
> new
  from
1    a
2    b

setAs 函数还允许您在输入时通过 read.* 函数使用自定义强制:How can I completely remove scientific notation for the entire R session

【讨论】:

感谢您快速而彻底的回复。我意识到这不是您通常会创建 data.frame 的方式,但此响应肯定有助于我理解 as 并回答问题。所以也许这应该是一个单独的问题,但这样做的动机是我想创建一个与另一个相同类型的对象。所以基本上像a <- as(c(1, 2, 3), class(b)) 这样的东西有什么通用的方法吗?我只是想避免写if (is.matrix(b)) a <- as.matrix(...) else ... 将一个向量变成一个矩阵唯一需要做的就是使用dim( vec) <-c(1,3)。然后,如果你运行class(vec),你会得到“矩阵”。 对不起,我对那个解释不是很清楚。这是一个有趣的用例,但我有一个对象b 和一些数据,我想使用该数据创建一个对象a,但我希望生成的类与b。所以如果b 是一个data.frame,我希望a 是一个data.frame;如果b 是一个矩阵,我希望a 是一个矩阵。我认为通过 a <- as(..., class(b)) 我可以避免一个大的 if-else 语句,但在 data.frame 的情况下不起作用。这有意义吗? 为什么不:class(a) <- class(b)【参考方案2】:

我认为这与as不是泛型函数有关,例如mean:

R> mean
function (x, ...) 
UseMethod("mean")
<bytecode: 0x000000000a617ed0>
<environment: namespace:base>

由于不是泛型,所以没有调用方法调度(即UseMethod

另一方面,as.data.frame 是一个通用函数——参见methods(class= "data.frame")as.data.frame 的源代码

如果as 上有方法分派,您的假设“后者将转换为前者”将是正确的。由于as 不是通用函数,因此您的假设是错误的。

如果您查看as 的源代码,您会发现它本质上是对许多 if-else 案例的调用,而不是对方法分派的调用。在第 52 行,您会看到返回错误的 catch:

if (is.null(asMethod)) 
        stop(gettextf("no method or default for coercing %s to %s", 
                      dQuote(thisClass), dQuote(Class)), domain = NA)

这会带来您所看到的回报。

【讨论】:

以上是关于as.data.frame(x) 和 as(x, "data.frame") 的区别的主要内容,如果未能解决你的问题,请参考以下文章

R语言怎么判断一个变量是不是包含另一个变量的元素?

r as.data.frame

as.data.frame 将嵌套列表展平为单行,而不是为每条记录创建行 [重复]

将 data.frame 转换为 ff

as.data.frame.default(dtm) 中的错误:无法将类 "c("DocumentTermMatrix", "simple_triplet_ma

非规范化数据