【问题标题】:Vectorize loop of read.csv on filenames文件名上的 read.csv 循环矢量化
【发布时间】:2014-04-23 14:13:25
【问题描述】:

我对 R 很陌生,如果编程看起来很糟糕,请见谅。

目标是基于公共前缀创建文件名,即给定前缀循环 x 次以生成前缀 1、前缀 2、前缀 3。然后使用这些文件名读取.csv(prefix-1,prefix-2,prefix-3)。

我已经让代码工作了,但是下面的效率很低:

name <- vector(mode="character", length=0)
for (i in 1:numruns)name[i] <- paste(prefix, "-", i, ".log", sep="")

if (numruns == 1) {
        raw_data_1 <-read.csv(name[1], header=F, sep="\t", skip=11)
}

if (numruns == 2) {
        raw_data_1 <-read.csv(name[1], header=F, sep="\t", skip=11)
        raw_data_2 <-read.csv(name[2], header=F, sep="\t", skip=11)
}

if (numruns == 3) {
        raw_data_1 <-read.csv(name[1], header=F, sep="\t", skip=11)
        raw_data_2 <-read.csv(name[2], header=F, sep="\t", skip=11)
        raw_data_3 <-read.csv(name[3], header=F, sep="\t", skip=11)     #import files
}

我正在尝试学习如何提高效率,以上内容符合我的目的,但我觉得我应该能够将其包含在生成名称的初始循环中。当我尝试修改原始循环时,我无法让它工作......

for (i in 1:numruns){
        name[i] <- paste(prefix, "-", i, ".log", sep="")
        raw_data <- paste("raw_data_", i, sep="")
        print(raw_data)
        raw_data <- read.csv(name[i], header=F, sep="\t", skip=11)
}

而不是获取 raw_data_1,raw_data_2,raw_data_3... 我得到“raw_data”。我很困惑,因为 print(raw_data) 实际上正确打印了“raw_data_1-3”(但只有“raw_data”实际上包含任何信息)。

感谢您对我的代码的任何帮助或批评,以使其更高效。

【问题讨论】:

  • 正如@tonytonov 所说,vectorization 是将循环转换为矢量化代码的通用术语。使用该标签标记、搜索等任何此类问题。

标签: r vectorization read.csv


【解决方案1】:

您应该尽早开始使用本机矢量化。一开始可能会令人困惑,但最终你会看到它的所有力量和美丽。请注意,许多基本函数都是矢量化的,因此对参数进行循环通常是多余的(请参阅下面的 paste 用法)。了解有关apply 家族的更多信息,它从一开始就是必不可少的工具(请参阅lapply 电话)。

由于读取多个文件是一项常见任务,因此这里是我经常使用的链。我们首先根据已知模式构建所有文件名。然后我们一次读完它们,没有任何循环。最后,我们可能希望将文件列表合并到一个数据框中。

n <- 4
prefix <- 'some_prefix'
file_names <- paste0(prefix, '-', seq_len(n), '.log')
#[1] "some_prefix-1.log" "some_prefix-2.log" "some_prefix-3.log" "some_prefix-4.log"
# a list of data frames
df_list <- lapply(file_names, function(x) read.csv(x, head=F, sep='\t', skip=11))
# total data frame (if all data frames are compatible)
df_total <- do.call(cbind, df_list)

【讨论】:

  • 这是很棒的信息!感谢您花时间为我发布此内容。我一直在努力理解 apply 的使用以及一般的函数使用。我认为从长远来看,不依赖循环的东西也更有意义。非常感谢您的回答。
  • 我发现自己正在做我在 OP 中开始做的事情。当然,我很高兴使用您的上述技术。但是,我没有使用 read.csv,而是使用了自定义函数。它似乎不起作用,有什么想法吗?
  • 我相信您应该将自定义功能的问题作为另一个问题发布,并将其链接到这个问题。注释不是特别方便排查问题。
【解决方案2】:

做到这一点的一种方法是将它们放在一个列表中,如下所示:

raw_data <- vector(mode = "list", length = numruns) #allocate space for list
for (i in 1:numruns){ raw_data[[i]] <- read.csv(name[i], header=F, sep="\t", skip=11)}

您可以使用 lapply 在一个命令中执行此操作 - 将来可能值得一读。

您的代码不起作用的原因是您将字符串“raw_data_1”分配给 raw_data,然后用文件中的数据覆盖它。如果您真的想走有很多变量的路线,请查看assign()get()

【讨论】:

  • 啊。我想我现在明白了。我仍在学习,但这是非常有用的信息。将那堵代码减少到几行,感觉非常令人满意!我仍然需要更多的练习来理解列表等,希望很快就会到来。
猜你喜欢
  • 2012-09-24
  • 2020-10-02
  • 2021-03-04
  • 1970-01-01
  • 1970-01-01
  • 2016-02-11
  • 2014-09-25
  • 1970-01-01
  • 2021-03-01
相关资源
最近更新 更多