循环遍历向量并检查是否存在同名数据框。

3

正如标题所述,我正在尝试循环遍历一个包含字符串的向量,这些字符串可能是数据框的名称。实际上它不需要是向量,而是一个数据框,我从中提取了一列。

以下是我尝试过的:

tables <- as.vector(df.stattributes.run[,1])

这里提供了

表格 [1] "ttest" "ttest2" "mtcars"

然后我开始循环。

for (i in 1:length(tables))
  {try(if(!is.data.frame(as.name(tables[i])) == TRUE) stop(paste("Table",tables[i],"doesn't exist.")) else print(paste("Table",tables[i],"found")))}

尽管mtcars是一个已存在的数据框架,但这总是返回"Table ... not found."。我该如何修改才能让它正常工作?谢谢!

1个回答

5
您可以使用 mget(),并在其后加上inherits=Tifnotfound=list(NULL)(或任何非数据框值),然后对每个应用is.data.frame()
sapply(mget(tables,inherits=T,ifnotfound=list(NULL)),is.data.frame);
##  ttest ttest2 mtcars
##  FALSE  FALSE   TRUE

inherits=T在这里是必须的,因为mtcars不位于全局环境中,当您在顶级运行mget()时,默认情况下会在全局环境中查找。它实际上位于内置数据集包的公共环境中。您可以使用find()来确定对象所在的位置:

find('mtcars');
## [1] "package:datasets"

此外,这里有一些误解需要澄清。函数 as.name()as.symbol() 是完全等价的。这些函数将给定的参数强制转换为符号类型。
符号类型是 R 语言本身的一部分,或者说是 R 解析树使用的 R 数据类型。换句话说,您可以说它是 R 的数据模型的一部分。有关此信息,请参见我在此处的答案。
大多数时候,大多数 R 程序员不需要使用符号,因为它们不需要“计算语言”,通常称为(意味着它们不需要操作 R 解析树)。
在您的代码中,您使用 as.name()tables[i] 中的字符串值强制转换为符号类型,然后将结果符号对象传递给 is.data.frame()。这是不正确的。在符号对象上调用 is.data.frame() 总是会返回 false,因为符号不是 data.frame。通常,is.* 函数作用于给定对象的类型;它们不执行任何“解析”、“查找”或“搜索”以查找参数所引用的最终对象;参数就是 is.* 函数正在测试类型的对象。
第二点,您不需要执行 == TRUE。如果您已经有了逻辑值,那么它将已经为 true,在这种情况下,比较将使其保持为 true;或者它已经是 false,在这种情况下,比较将使其保持为 false(或者它已经是 NA,在这种情况下,比较将使其保持为 NA)。
有趣的是,在写完上面的解释后,我意识到有一种替代方法可以获得存储在字符串值中的名称的对象,它实际上涉及到我上面有些忽视的 as.symbol()/as.name() 函数。我说的是在符号对象上调用 eval()
head(eval(as.symbol(tables[3L])));
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
is.data.frame(eval(as.symbol(tables[3L])));
## [1] TRUE

所以我们可以说你通过调用as.name()是正确的。


非常感谢,这显然有效。有趣的是我也尝试过使用eval,但没有想到将两个表达式组合起来 :) - mariego

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