【问题标题】:Using lapply to apply a function over read-in list of files and saving output as new list of files使用 lapply 对读入的文件列表应用函数并将输出保存为新的文件列表
【发布时间】:2017-12-25 01:10:17
【问题描述】:

我是 R 的新手,有点坚持我认为可能是常见的操作。我有许多文件(57 个,大约 15 亿行,共 6 列),我需要在这些文件上执行基本功能。我可以读取这些文件并执行我不需要的计算,但我在最终输出中遇到了问题。我设想该功能一次处理一个文件,输出工作文件并移至下一个文件。

计算后,我想输出 57 个新的 .txt 文件,这些文件以输入数据最初来自的文件命名。到目前为止,我能够在较小的测试数据集上执行计算并吐出 1 个附加的 .txt 文件,但这不是我想要的最终输出。

#list filenames 
files <- list.files(path=, pattern="*.txt", full.names=TRUE, recursive=FALSE)

#begin looping process
loop_output = lapply(files, 
function(x) {

#Load 'x' file in
DF<- read.table(x, header = FALSE, sep= "\t")

#Call calculated height average a name
R_ref= 1647.038203

#Add column names to .las data
colnames(DF) <- c("X","Y","Z","I","A","FC")

#Calculate return
DF$R_calc <- (R_ref - DF$Z)/cos(DF$A*pi/180)

#Calculate intensity
DF$Ir_calc <- DF$I * (DF$R_calc^2/R_ref^2)

#Output new .txt with calcuated columns
write.table(DF, file=, row.names = FALSE, col.names = FALSE, append = TRUE,fileEncoding = "UTF-8")

})

我最近的代码尝试是搞乱初始的 lapply/sapply 函数:

#begin looping process
loop_output = sapply(names(files), 
function(x) {

以及输出线:

#Output new .csv with calcuated columns 
write.table(DF, file=paste0(names(DF), "txt", sep="."),
row.names = FALSE, col.names = FALSE, append = TRUE,fileEncoding = "UTF-8")

从我在 write.table 输出期间读取文件命名函数的内容来看,可能是我尚未与脚本的其余部分完全对齐的键之一。我一直在查看许多其他我认为适用的问题:

Using lapply to apply a function over list of data frames and saving output to files with different names

Write list of data.frames to separate CSV files with lapply

没有运气。我非常感谢任何关于输入 x 个文件、对每个文件执行相同功能、然后输出相同 x 个文件的正确方向的见解或路径。谢谢你。

【问题讨论】:

  • purrr 包中的 map() 对此非常有效。您可以读取文件文件夹,将它们分开,并对每个文件执行相同的操作集。我会定义一个函数来执行必要的操作,然后读入、转换,然后用map() 写入
  • 所以lapply 代码的问题只是附加的文本文件?
  • @Parfait 不,它得出了我想要的类似结论:即,它计算出我需要计算的内容并提供正确的输出。但是,我想输出 57 个单独的新文件,而不是 1 个附加文件,用于数据大小管理以及我​​想在工作流程的下一步中对文件执行的操作。
  • 然后只需调整 file= 参数,就像@Damian 在您的write.table 中显示的那样,并添加一个return(DF),这样您的lapply 就会返回一个数据帧列表而不是结果write.table()

标签: r loops for-loop lapply write.table


【解决方案1】:

输出被定向到同一个文件的原因可能是file = paste0(names(DF), "txt", sep=".") 每次迭代都返回相同的值。也就是说,DF 在每次迭代中必须具有相同的列名,因此names(DF) 将相同,paste0(names(DF), "txt", sep=".") 将相同。与append = TRUE 选项一起,结果是所有输出都写入同一个文件。

在匿名函数内部,x 是输入文件的名称。除了使用names(DF) 作为输出文件名的基础,您还可以对该字符串进行一些转换。

例子。

给定

x <- "/foo/raw_data.csv"

在函数内部你可以做这样的事情

infile <- x
outfile <- file.path(dirname(infile), gsub('raw', 'clean', basename(infile)))

outfile
[1] "/foo/clean_data.csv"

然后使用新名称进行输出,append = FALSE(除非您需要它为真)

write.table(DF, file = outfile, row.names = FALSE, col.names = FALSE, append = FALSE, fileEncoding = "UTF-8")

【讨论】:

  • 感谢您的意见和建议。事实证明这就是诀窍!在函数内部,我将“inFile”作为第一行,然后将“outFile”放在我的输出行之前,就像你写的那样(在 write.table 行中使用 append = FALSE)。在功能行使用 sapply 我的代码无法正常工作,而在功能行使用 lapply 可以。再次感谢您。
  • 很高兴为您提供帮助,如果问题得到解决,请接受答案,让其他人知道。 (参考:meta.stackexchange.com/questions/5234/…
  • 我也喜欢 gsub('raw', 'clean'... 功能。有助于解决我试图防止的覆盖问题。我会接受你的回答
【解决方案2】:

使用您的代码,这是一般的想法:

require(purrr)

#list filenames 
files <- list.files(path=, pattern="*.txt", full.names=TRUE, recursive=FALSE)


#Call calculated height average a name
R_ref= 1647.038203

dfTransform <- function(file){
  colnames(file) <- c("X","Y","Z","I","A","FC")

  #Calculate return
  file$R_calc <- (R_ref - file$Z)/cos(file$A*pi/180)

  #Calculate intensity
  file$Ir_calc <- file$I * (file$R_calc^2/R_ref^2)
  return(file)
}

output <- files %>% map(read.table,header = FALSE, sep= "\t") %>%
  map(dfTransform) %>%
  map(write.table, file=paste0(names(DF), "txt", sep="."),
  row.names = FALSE, col.names = FALSE, append = TRUE,fileEncoding = "UTF-8")

【讨论】:

  • 非常感谢您的回答并向我介绍了“purrr”包。我已经尝试了您的演练,但在 map(dfTransform) 步骤中遇到了错误。 names(x)
  • @forest_codes 检查 a) 您的所有文件具有相同数量的列,b) 您正在为名称向量 colnames(file) &lt;- c("X","Y","Z","I","A","FC") 中的每一列指定一个名称(您必须为每列)。如果这仍然不起作用,请尝试将 col.names 作为参数传递给 read.table
  • 续。这让我有点困惑,数据是 .txt 格式,用“\t”分隔,那个点应该分成 6 列。我认为这与您提供的代码没有任何关系,但我也没有很快在我的数据中看到错误(我的小型测试集有 2、5 行文件)
  • @forest_codes 您可以尝试read.delim,它默认为/t 作为分隔符,因为它具有读取制表符分隔文件的默认参数
  • 我已经更新了数据文件以更正它们,现在收到一个:“在 if (file == "") 文件 1 并且只使用第一个元素", errot
猜你喜欢
  • 1970-01-01
  • 2013-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-02
  • 2022-11-30
  • 2023-03-20
  • 1970-01-01
相关资源
最近更新 更多