【问题标题】:Apply a function to a list of csv files将函数应用于 csv 文件列表
【发布时间】:2020-02-13 07:35:32
【问题描述】:

我在名为 myFolder 的文件夹中有 45 个 csv 文件。每个 csv 文件有 13 列和 640 行。

我想读取每个 csv 并将列 7:12 除以 10 并将其保存在一个名为“我的文件夹”的新文件夹中。这是我的方法 正在使用简单的 for 循环。

library(data.table)
dir.create('newFolder')

allFiles <- list.files(file.path('myFolder'), pattern = '.csv')

for(a in seq_along(allFiles)){

    fileRef <- allFiles[a]
    temp <- fread(file.path('myFolder', fileRef)
    temp[, 7:12] <- temp[, 7:12]/10
    fwrite(temp, file.path('myFolder', paste0('new_',fileRef)))
 }

有没有更简单的解决方案在一两行中使用 datatable 和 apply 函数来实现这一点?

【问题讨论】:

  • 您也许可以将for 循环替换为apply 函数,但apply 的匿名函数看起来与您当前的for 循环体几乎相同。
  • 你的目标是什么?只是为了减少您输入的代码量?您实际上并没有执行不必要的步骤,并且“将某些列除以 10 并另存为新文件”不是一个足够常见的过程,无法为您提供一个功能。
  • 是的。我想减少代码量,以防万一,我有一些非常大的 csv 文件需要大量时间来读取,也许更高效的代码会有用?
  • 如果您的代码没有问题并且您寻求紧凑、优雅或重构,请在CodeReview 上提问。当我们试图反对不幸的 R 神话时:for 循环没有错。

标签: r for-loop data.table sapply


【解决方案1】:

您的代码已经很不错了,但可以进行以下改进:

  • 预先定义输入和输出文件夹以实现模块化
  • 使用full.names = TRUE 以便allFiles 包含完整路径
  • 使用.csv$ 作为将其锚定到文件名末尾的模式
  • 遍历全名而不是索引
  • 使用fwrite中的basename从路径名中提取出基名

然后是代码

library(data.table)

myFolder <- "myFolder"
newFolder <- "newFolder"

dir.create(newFolder)
allFiles <- list.files(myFolder, pattern = '.csv$', full.names = TRUE)

for(f in allFiles) {
    temp <- fread(f)
    temp[, 7:12] <- temp[, 7:12] / 10
    fwrite(temp, file.path(newFolder, paste0('new_', basename(f))))
}

【讨论】:

    【解决方案2】:

    如果您想提高代码的可读性并摆脱循环,可以使用purrr::walk

    allFiles <- list.files(file.path('myFolder'), pattern = '.csv')
    
    purrr::walk(allFiles, function(x){
      temp <- fread(file.path('myFolder', x)
      temp[, 7:12] <- temp[, 7:12]/10
      fwrite(temp, file.path('myFolder', paste0('new_',fileRef)))
    })
    

    来自purrr::walk的参考页:

    walk() 返回输入 .x(不可见)

    不过,我认为这对速度没有帮助。

    【讨论】:

      猜你喜欢
      • 2020-10-01
      • 2021-05-30
      • 1970-01-01
      • 1970-01-01
      • 2015-08-25
      • 1970-01-01
      • 1970-01-01
      • 2022-08-14
      • 2014-03-17
      相关资源
      最近更新 更多