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.frame
、as.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") 的区别的主要内容,如果未能解决你的问题,请参考以下文章
as.data.frame 将嵌套列表展平为单行,而不是为每条记录创建行 [重复]
as.data.frame.default(dtm) 中的错误:无法将类 "c("DocumentTermMatrix", "simple_triplet_ma