使用`subset`函数按列名对矩阵进行子集筛选。

3
考虑以下模拟代码片段:
k <- 1:5
x <- seq(0,10,length.out =  100)
dsts <- lapply(1:length(k), function(i) cbind(x=x, distri=dchisq(x,k[i]),i) )
dsts <- do.call(rbind,dsts)

为什么这段代码会抛出错误(dsts 是矩阵):
subset(dsts,i==1)
#Error in subset.matrix(dsts, i == 1) : object 'i' not found

甚至包括这一个:

colnames(dsts)[3] <- 'iii'
subset(dsts,iii==1)

但不是这个(将矩阵强制转换为数据框):
subset(as.data.frame(dsts),i==1)

这个示例可以在 x 已经被定义的情况下工作:

subset(dsts,x> 500)

错误出现在这一行的subset.matrix()函数中:
else if (!is.logical(subset)) 

这是应该向R Core报告的错误吗?

2
列名评估仅适用于数据框,而不适用于矩阵。这就是 subset 设计的工作方式。文档中有描述。这不是一个错误。 - MrFlick
1
您会很高兴听到,此函数不建议用于非交互式使用:这是一个方便的函数,旨在用于交互使用。 对于编程而言,最好使用标准的子集函数(如[),特别是参数子集的非标准评估可能会产生意想不到的后果。 - Roman Luštrik
1
@aichao,你的示例如何工作并不清楚。原帖中已经有一个包含定义变量的列,应该用于子集化。 - Roman Luštrik
1
这里的教训是,除非你需要进行矩阵运算,否则最好将数据存储在 data.frame 中。这是 R 的方式。你可以使用 cbind.data.frame 更加明确。 - MrFlick
1
@MrFlick 我认为你应该把你的评论表述成一个完整的答案。 - Roman Luštrik
显示剩余7条评论
1个回答

4
您所描述的行为是设计上的,并在?subset帮助页面中有所记录。
从帮助页面中可以得知:
对于数据框,subset参数适用于行。请注意,subset将在数据框中进行评估,因此可以在表达式中(参见示例)引用列名称作为变量。
在R中,data.frames和matrices是非常不同的对象类型。如果这会导致问题,那么您可能正在使用错误的数据结构。矩阵仅在需要矩阵运算时才是必需的。如果您将列视为行观察的不同属性,则应首先在data.frame中存储数据。您可以将所有值存储在简单向量中,其中每三个值表示一个观察结果,但这也是数据结构的差选择。我不确定您是否尝试通过选择矩阵来更有效率,但似乎只是错误的选择。
数据框以命名列表的形式存储,而矩阵以维度化向量的形式存储。列表可用作环境,这使得在该上下文中评估变量名称变得容易。两者之间最大的区别在于数据框可以持有不同类别(数字、字符、日期)的列,而矩阵只能持有完全相同数据类型的值。您不能总是轻松地在两者之间转换而不丢失信息。
$这样的东西也仅适用于数据框。
dd <- data.frame(x=1:10)
dd$x
mm <- matrix(1:10, ncol=1, dimnames=list(NULL, "x"))    
mm$x # Error

如果你想对矩阵进行子集操作,最好使用标准的[子集操作符,而不是子集操作函数。
dsts[ dsts[,"i"]==1, ]

这种行为已经成为R语言的一部分很长时间了。对这种行为的任何更改都可能会在现有依赖于在特定上下文中评估变量的代码上引入破坏性的变化。我认为问题出在告诉你首先使用矩阵的人身上。你应该使用data.frame()而不是cbind()


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接