【问题标题】:For loop question in RR中的for循环问题
【发布时间】:2011-06-10 07:34:18
【问题描述】:

希望我能很好地解释我的问题以获得答案 - 任何帮助将不胜感激。

如果数据文件需要合并为一个,我有一个编号。我使用 for 循环来执行此操作并添加一个列来指示它是哪个文件。

在这种情况下,有 6 个文件,每个文件最多包含 100 个数据条目。

当有 6 个文件时,我可以毫无问题地运行它。

但是当数量减少时,我就有问题了。

我想做的是使用 for 循环来测试文件,并使用 for 循环变量来组装一个引用存在文件的向量。

我似乎无法让新变量在 for 循环变量通过循环时组合它的新值。

这是我目前编写的示例代码。

for ( rloop1 in 1 : 6) {
ReadFile=paste(rloop1,SampleName,"_",FileName,"_Stats.csv", sep="")
if (file.exists(ReadFile))
**files_found <- c(rloop1)**
}

我正在寻找的是 files_found 将包含那些 1...6 对找到的文件有效的文件。

问候 史蒂夫

【问题讨论】:

    标签: r file for-loop


    【解决方案1】:

    我认为有更好的解决方案(例如,您可以使用 list.files() 扫描文件夹,然后循环返回对象的长度),但这应该(我没有尝试过)可以解决问题(使用您的示例代码):

    files.found <- ""    
    for (rloop1 in 1 : 6) {
        ReadFile=paste(rloop1,SampleName,"_",FileName,"_Stats.csv", sep="")
        if (file.exists(ReadFile)) files_found <- c(files.found, rloop1)
    }
    

    或者,您可以通过以下方式获取文件名(除了它们的索引):

    files.found <- ""    
    for (rloop1 in 1 : 6) {
        ReadFile=paste(rloop1,SampleName,"_",FileName,"_Stats.csv", sep="")
        if (file.exists(ReadFile)) files_found <- c(files.found, ReadFile)
    }
    

    最后,在您的情况下,list.files 可能看起来像这样:

    files.found <- list.files(pattern = "[[:digit:]]_SampleName_FileName_Stats.csv")
    

    【讨论】:

    • +1 表示list.files() 指针和正则表达式。在正则表达式中,SampleName 和 FileName 不是文字,而是 R 对象中的字符串,至少这是我对 Q 的解读。
    • @Gavin 我也在阅读。或许我应该澄清一下SampleName 和FileName 应该用它们的值替换,不能是变量。
    【解决方案2】:

    正如 Henrik 所展示的,使用 list.files() 有一种更短的方法来执行此操作。如果您不熟悉正则表达式(请参阅?regex),您可以这样做。

    n <- 6
    Fnames <- paste(1:n,SampleName,"_",FileName,"Stats.csv",sep="")
    Filelist <- Fnames[file.exists(Fnames)]
    

    这是完全等价的。 paste 和 file.exists 都是矢量化函数,所以你最好利用它。根本不需要 for 循环。

    要获取文件名的数量(假设这是唯一的数字),您可以这样做:

    gsub("^[:digit:]","", Filelist)
    

    另见?regex

    【讨论】:

    • 是的,我同意 file.exists 的矢量化版本比 for 循环更漂亮。但是,从我的角度来看,list.files() 更好,因为您将所有内容都集中在一行中......(尽管如此 +1)
    • 是的 SampleName 和 FileName 是字符串。有一点,我希望获得与找到的每个文件相关联的编号,因为我需要为该文件中的所有记录添加一个具有该编号的文件的列。有什么想法吗?
    • @Steve 我在我的回答中添加了它。
    • @Joris - 谢谢。已经尝试过您的 gsub,我认为将数字更正为数字(这是一个拼写错误),但无论哪种方式都只能获取 Filelist 中的所有适用文件。查看了 regxex 信息,但发现它很混乱。如果您有时间看一看并指导我,那就太好了。为了澄清字符串是否为“3A_SampleName_FileName_stats.csv”,我会得到 3,如果是“2A .....”,我会得到 2 等
    • @Steve:不错,抱歉打错了。尝试gsub("^(.+?)_.+","\\1",Filelist),假设您有 3A_SampleName_... 作为文件名并再次仔细阅读 ?regex。这不是简单的材料,但是一旦掌握了它,它就会非常强大。试着找出不同的例子。在旁注中,您可能需要考虑接受一个正确的答案(使用左侧的 V 符号)。另请参阅常见问题解答
    【解决方案3】:

    列出要加载的文件可能会更好,然后遍历该列表以加载它们。 list.files 是你的朋友。我们可以使用正则表达式仅列出那些以"_Stats.csv" 结尾的文件。例如,在我当前的工作目录中,我有以下文件:

    $ ls | grep Stats
    bar_Stats.csv
    foobar_Stats.csv
    foobar_Stats.csv.txt
    foo_Stats.csv
    

    其中只有三个是我要加载的 csv 文件(.txt 文件与您显示的模式不匹配)。我们可以使用list.files()获取这些文件名:

    > list.files(pattern = "_Stats.csv$")
    [1] "bar_Stats.csv"    "foo_Stats.csv"    "foobar_Stats.csv"
    

    然后您可以遍历它并读取其中的文件。类似于:

    fnames <- list.files(pattern = "_Stats.csv$")
    for(i in seq_along(fnames)) {
        assign(paste("file_", i, sep = ""), read.csv(fnames[i]))
    }
    

    这将在全局工作区中创建一系列对象file_1、file_2、file_3 等。如果你想要列表中的文件,你可以用lapply 代替fnames:

    lapply(fnames, read.csv)
    

    如果合适,do.call 可能有助于合并列表中的文件:

    do.call(rbind, lapply(fnames, read.csv))
    

    【讨论】:

    • list.files + grep + lapply + do.call 在我的书中是一个成功的组合。
    猜你喜欢
    • 2020-02-03
    • 2018-11-02
    • 1970-01-01
    • 2015-01-19
    • 2015-01-19
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    相关资源
    最近更新 更多