将对单个 .csv 文件执行的一系列操作自动执行到 R 中同一目录中的所有 .csv 文件
Automate a series of actions done on a single .csv file to all .csv files within the same directory in R
我正在进行一个研究项目,我需要处理来自一副触觉手套的数据。导出数据后,有4行包含日期和时间,我在分析时不需要,还有很多列我也不需要。长话短说,我需要删除前 4 行,只保留列 [1,2,33,53,76,95,114,133,164,184,207,226,245]。我写了一个非常简单的 R 脚本来为我做这件事,但我想知道如何将这组操作应用于同一目录中的所有 .csv 文件?每次手动输入每个文件名是非常痛苦的。提前致谢!
# read uncleaned, raw, data
uncleaned_data<-read.csv("C:/Users/jiang/Desktop/Ready_Clean/Hongjiao_Medium_High1.csv", header = FALSE)
# remove the date and time headers
data_without_head<-uncleaned_data[-c(1,2,3,4),]
# extract the useful columns
cleaned_data<-data_without_head[,c(1,2,33,53,76,95,114,133,164,184,207,226,245)]
# write the new cleaned data into a new file name (adding "_cleaned" in the end)
write.table(cleaned_data,"C:/Users/jiang/Desktop/Ready_Clean/Hongjiao_Medium_High1_Cleaned.csv",row.names=FALSE,col.names=FALSE,sep=",")
您好,我为您编写了一些代码来回答您的问题。
- 首先设置工作目录
- 列出您需要处理的所有文件。我这里的假设是所有文件都以“Hongjiao_Medium_High”开头,然后有一些数字
- 使用 FOR 循环遍历要迭代的文件名列表
- 通过一些调整将您的代码粘贴到 FOR 循环中
下面是代码:
setwd("C:/Users/jiang/Desktop/Ready_Clean")
list_of_file_names <- list.files(pattern = "*png")
for(i in list_of_file_names){
# read uncleaned, raw, data
print(i)
uncleaned_data<-read.csv( i , header = FALSE)
# remove the date and time headers
data_without_head<-uncleaned_data[-c(1,2,3,4),]
# extract the useful columns
cleaned_data<-data_without_head[,c(1,2,33,53,76,95,114,133,164,184,207,226,245)]
# write the new cleaned data into a new file name (adding "_cleaned" in the end)
write.table(cleaned_data,paste(i,"_Cleaned.csv"),row.names=FALSE,col.names=FALSE,sep=",")
}
您可以列出目录中的所有文件,然后过滤以.csv结尾的文件:
我假设你的目录路径是“C:/Users/jiang/Desktop/Ready_Clean/”
很遗憾,我无法在我的电脑上测试代码,但如果您有任何问题,请告诉我。
library(tidyverse)
library(stringr)
#get all the .csvs present in the directory and then fabricate the new names just by appending '_cleaned' before .csv
paths <- list.files(path = "C:/Users/jiang/Desktop/Ready_Clean/") %>%
str_subset(pattern = '.csv$') #capture all the files ending in .csv
paths <- str_c("C:/Users/jiang/Desktop/Ready_Clean/", paths)
paths_cleaned <- str_replace(paths, '.csv$', '_cleaned.csv')
get_csv <- function(path, path_clean){
# read uncleaned, raw, data
uncleaned_data <- read.csv(path, header = FALSE)
# remove the date and time headers
data_without_head <- uncleaned_data[-c(1,2,3,4),]
# extract the useful columns
cleaned_data <- data_without_head[, c(1,2,33,53,76,95,114,133,164,184,207,226,245)]
# write the new cleaned data into a new file name (adding "_cleaned" in the end)
write.table(cleaned_data,
path_clean,
row.names = FALSE,
col.names = FALSE,
sep = ",")
}
#walk2 would also be an option because we only care of side-effects here.
map2(path, path_cleaned, ~get_csv(.x, .y))
Base R 解决方案如下所示。首先,我们使用list.files()
提取以.csv
结尾的文件,然后使用文件列表驱动lapply()
读取数据,对其进行子集化,并使用write.table()
写入。
theFiles <- list.files(path="C:/Users/jiang/Desktop/Ready_Clean/",
pattern="\.csv$",full.names=TRUE)
dataList <- lapply(theFiles,function(x){
y <- read.csv(x,skip = 4,header=FALSE)[c(1,2,33,53,76,95,114,133,164,184,207,226,245)]
write.table(y,paste0(x,".cleaned"))
})
请注意,我们使用 skip =
参数在读取每个文件时跳过前四行,然后立即通过 [
子集由 read.csv()
创建的 object提取运算符的形式。
在write.table()
操作中,我们使用paste0()
将.cleaned
附加到每个原始文件名,以区分清理后的文件和原始文件。
由于原始问题不包含最小的可重现示例,我们将使用我的 Pokémon Stats GitHub 存储库中的数据来说明解决方案。
Pokémon 统计数据的维度与原始问题中描述的数据有很大不同,因此我们将跳过每个文件的前四行,仅保留第 1、2、4 和 6 列。
download.file("https://raw.githubusercontent.com/lgreski/pokemonData/master/PokemonData.zip",
"pokemonData.zip",mode="wb")
unzip("pokemonData.zip",exdir="./pokemonData")
theFiles <- list.files("./pokemonData",pattern="\.csv$",full.names=TRUE)
dataList <- lapply(theFiles,function(x){
y <- read.csv(x,skip = 4,header=FALSE)[c(1,2,4,6)]
write.table(y,file=paste0(x,".cleaned"),row.names=FALSE,col.names=FALSE,sep=",")
})
可以使用其中一个原始文件的屏幕截图来验证输出。我突出显示了第 1、2、4 和 6 列,从输入的第四行开始(包括 header 行)。
..../pokemonData/gen01.csv.cleaned
前几行的输出是:
4,"Charmander","Fire",309
5,"Charmeleon","Fire",405
6,"Charizard","Fire",534
7,"Squirtle","Water",314
8,"Wartortle","Water",405
9,"Blastoise","Water",530
文件gen01.csv
包含第一代宝可梦。此文件中的前三个神奇宝贝是妙蛙种子、妙蛙草和猎豹。我们从输出中可以看出,这些神奇宝贝和原始文件中的 header 行被跳过了,所以首先观察的是神奇宝贝 4,Charmander。我们还看到第六列 Total
统计数据与输入文件中已写入输出文件的行相匹配。
正在验证写入的文件
因为我们在每个文件的末尾附加了 .cleaned
,所以我们可以使用与列出 .csv
文件相同的技术来列出 .cleaned
文件并使用read.csv()
。这使我们能够使原始文件与清理后的文件保持距离。
# now read the cleaned files
theFiles <- list.files("./pokemonData",pattern="\.cleaned$",full.names=TRUE)
dataList <- lapply(theFiles,read.csv,header=FALSE)
head(dataList[[1]])
此时dataList
object是一个list()
包含8个数据帧,每一代神奇宝贝一个。
我们使用head()
打印列表中第一个数据框的前几行,与上面的结果匹配:
> head(dataList[[1]])
V1 V2 V3 V4
1 4 Charmander Fire 309
2 5 Charmeleon Fire 405
3 6 Charizard Fire 534
4 7 Squirtle Water 314
5 8 Wartortle Water 405
6 9 Blastoise Water 530
正在将清理后的文件写入单独的目录
根据对我的回答的评论中提出的要求,这里有一个解决方案,它在最初存储文件的目录中创建一个 /cleaned
子目录,并将文件写入该目录。
首先,我们为输入和输出目录创建 objects。然后我们为输出文件创建一个新的子目录(如果它不存在)。
# solution that creates a ./cleaned subdirectory
inputDirectory <- "./pokemonData"
outputDirectory <- paste0(inputDirectory,"/cleaned")
if(!dir.exists(outputDirectory)) dir.create(outputDirectory)
通过在尝试创建目录之前检查该目录是否存在,我们消除了此脚本第二次和后续运行中的错误。
接下来,我们列出输入目录中的文件。因为我们稍后会在脚本中使用 inputDirectory
和 outputDirectory
object 来手动构建每个输入和输出文件的完整路径名,所以我们设置 full.names=
list.files()
到 FALSE
的参数。
theFiles <- list.files(inputDirectory,pattern="\.csv$",full.names=FALSE)
接下来,我们使用lapply()
读取文件,对正确的行和列进行子集化,并将清理后的文件写入输出目录。
dataList <- lapply(theFiles,function(x){
y <- read.csv(paste0(inputDirectory,"/",x),skip = 4,header=FALSE)[c(1,2,4,6)]
write.table(y,file=paste0(outputDirectory,"/",x),row.names=FALSE,col.names=FALSE,sep=",")
})
# verify that files were written to cleaned directory
list.files(outputDirectory,full.names=TRUE)
...输出:
> list.files(outputDirectory,full.names=TRUE)
[1] "./pokemonData/cleaned/gen01.csv" "./pokemonData/cleaned/gen02.csv"
[3] "./pokemonData/cleaned/gen03.csv" "./pokemonData/cleaned/gen04.csv"
[5] "./pokemonData/cleaned/gen05.csv" "./pokemonData/cleaned/gen06.csv"
[7] "./pokemonData/cleaned/gen07.csv" "./pokemonData/cleaned/gen08.csv"
>
附录
由于评论者断言 paste0()
中文件名中的点未正确呈现,因此子目录的以下屏幕截图表明代码确实按我的预期工作。
我正在进行一个研究项目,我需要处理来自一副触觉手套的数据。导出数据后,有4行包含日期和时间,我在分析时不需要,还有很多列我也不需要。长话短说,我需要删除前 4 行,只保留列 [1,2,33,53,76,95,114,133,164,184,207,226,245]。我写了一个非常简单的 R 脚本来为我做这件事,但我想知道如何将这组操作应用于同一目录中的所有 .csv 文件?每次手动输入每个文件名是非常痛苦的。提前致谢!
# read uncleaned, raw, data
uncleaned_data<-read.csv("C:/Users/jiang/Desktop/Ready_Clean/Hongjiao_Medium_High1.csv", header = FALSE)
# remove the date and time headers
data_without_head<-uncleaned_data[-c(1,2,3,4),]
# extract the useful columns
cleaned_data<-data_without_head[,c(1,2,33,53,76,95,114,133,164,184,207,226,245)]
# write the new cleaned data into a new file name (adding "_cleaned" in the end)
write.table(cleaned_data,"C:/Users/jiang/Desktop/Ready_Clean/Hongjiao_Medium_High1_Cleaned.csv",row.names=FALSE,col.names=FALSE,sep=",")
您好,我为您编写了一些代码来回答您的问题。
- 首先设置工作目录
- 列出您需要处理的所有文件。我这里的假设是所有文件都以“Hongjiao_Medium_High”开头,然后有一些数字
- 使用 FOR 循环遍历要迭代的文件名列表
- 通过一些调整将您的代码粘贴到 FOR 循环中
下面是代码:
setwd("C:/Users/jiang/Desktop/Ready_Clean")
list_of_file_names <- list.files(pattern = "*png")
for(i in list_of_file_names){
# read uncleaned, raw, data
print(i)
uncleaned_data<-read.csv( i , header = FALSE)
# remove the date and time headers
data_without_head<-uncleaned_data[-c(1,2,3,4),]
# extract the useful columns
cleaned_data<-data_without_head[,c(1,2,33,53,76,95,114,133,164,184,207,226,245)]
# write the new cleaned data into a new file name (adding "_cleaned" in the end)
write.table(cleaned_data,paste(i,"_Cleaned.csv"),row.names=FALSE,col.names=FALSE,sep=",")
}
您可以列出目录中的所有文件,然后过滤以.csv结尾的文件:
我假设你的目录路径是“C:/Users/jiang/Desktop/Ready_Clean/”
很遗憾,我无法在我的电脑上测试代码,但如果您有任何问题,请告诉我。
library(tidyverse)
library(stringr)
#get all the .csvs present in the directory and then fabricate the new names just by appending '_cleaned' before .csv
paths <- list.files(path = "C:/Users/jiang/Desktop/Ready_Clean/") %>%
str_subset(pattern = '.csv$') #capture all the files ending in .csv
paths <- str_c("C:/Users/jiang/Desktop/Ready_Clean/", paths)
paths_cleaned <- str_replace(paths, '.csv$', '_cleaned.csv')
get_csv <- function(path, path_clean){
# read uncleaned, raw, data
uncleaned_data <- read.csv(path, header = FALSE)
# remove the date and time headers
data_without_head <- uncleaned_data[-c(1,2,3,4),]
# extract the useful columns
cleaned_data <- data_without_head[, c(1,2,33,53,76,95,114,133,164,184,207,226,245)]
# write the new cleaned data into a new file name (adding "_cleaned" in the end)
write.table(cleaned_data,
path_clean,
row.names = FALSE,
col.names = FALSE,
sep = ",")
}
#walk2 would also be an option because we only care of side-effects here.
map2(path, path_cleaned, ~get_csv(.x, .y))
Base R 解决方案如下所示。首先,我们使用list.files()
提取以.csv
结尾的文件,然后使用文件列表驱动lapply()
读取数据,对其进行子集化,并使用write.table()
写入。
theFiles <- list.files(path="C:/Users/jiang/Desktop/Ready_Clean/",
pattern="\.csv$",full.names=TRUE)
dataList <- lapply(theFiles,function(x){
y <- read.csv(x,skip = 4,header=FALSE)[c(1,2,33,53,76,95,114,133,164,184,207,226,245)]
write.table(y,paste0(x,".cleaned"))
})
请注意,我们使用 skip =
参数在读取每个文件时跳过前四行,然后立即通过 [
子集由 read.csv()
创建的 object提取运算符的形式。
在write.table()
操作中,我们使用paste0()
将.cleaned
附加到每个原始文件名,以区分清理后的文件和原始文件。
由于原始问题不包含最小的可重现示例,我们将使用我的 Pokémon Stats GitHub 存储库中的数据来说明解决方案。
Pokémon 统计数据的维度与原始问题中描述的数据有很大不同,因此我们将跳过每个文件的前四行,仅保留第 1、2、4 和 6 列。
download.file("https://raw.githubusercontent.com/lgreski/pokemonData/master/PokemonData.zip",
"pokemonData.zip",mode="wb")
unzip("pokemonData.zip",exdir="./pokemonData")
theFiles <- list.files("./pokemonData",pattern="\.csv$",full.names=TRUE)
dataList <- lapply(theFiles,function(x){
y <- read.csv(x,skip = 4,header=FALSE)[c(1,2,4,6)]
write.table(y,file=paste0(x,".cleaned"),row.names=FALSE,col.names=FALSE,sep=",")
})
可以使用其中一个原始文件的屏幕截图来验证输出。我突出显示了第 1、2、4 和 6 列,从输入的第四行开始(包括 header 行)。
..../pokemonData/gen01.csv.cleaned
前几行的输出是:
4,"Charmander","Fire",309
5,"Charmeleon","Fire",405
6,"Charizard","Fire",534
7,"Squirtle","Water",314
8,"Wartortle","Water",405
9,"Blastoise","Water",530
文件gen01.csv
包含第一代宝可梦。此文件中的前三个神奇宝贝是妙蛙种子、妙蛙草和猎豹。我们从输出中可以看出,这些神奇宝贝和原始文件中的 header 行被跳过了,所以首先观察的是神奇宝贝 4,Charmander。我们还看到第六列 Total
统计数据与输入文件中已写入输出文件的行相匹配。
正在验证写入的文件
因为我们在每个文件的末尾附加了 .cleaned
,所以我们可以使用与列出 .csv
文件相同的技术来列出 .cleaned
文件并使用read.csv()
。这使我们能够使原始文件与清理后的文件保持距离。
# now read the cleaned files
theFiles <- list.files("./pokemonData",pattern="\.cleaned$",full.names=TRUE)
dataList <- lapply(theFiles,read.csv,header=FALSE)
head(dataList[[1]])
此时dataList
object是一个list()
包含8个数据帧,每一代神奇宝贝一个。
我们使用head()
打印列表中第一个数据框的前几行,与上面的结果匹配:
> head(dataList[[1]])
V1 V2 V3 V4
1 4 Charmander Fire 309
2 5 Charmeleon Fire 405
3 6 Charizard Fire 534
4 7 Squirtle Water 314
5 8 Wartortle Water 405
6 9 Blastoise Water 530
正在将清理后的文件写入单独的目录
根据对我的回答的评论中提出的要求,这里有一个解决方案,它在最初存储文件的目录中创建一个 /cleaned
子目录,并将文件写入该目录。
首先,我们为输入和输出目录创建 objects。然后我们为输出文件创建一个新的子目录(如果它不存在)。
# solution that creates a ./cleaned subdirectory
inputDirectory <- "./pokemonData"
outputDirectory <- paste0(inputDirectory,"/cleaned")
if(!dir.exists(outputDirectory)) dir.create(outputDirectory)
通过在尝试创建目录之前检查该目录是否存在,我们消除了此脚本第二次和后续运行中的错误。
接下来,我们列出输入目录中的文件。因为我们稍后会在脚本中使用 inputDirectory
和 outputDirectory
object 来手动构建每个输入和输出文件的完整路径名,所以我们设置 full.names=
list.files()
到 FALSE
的参数。
theFiles <- list.files(inputDirectory,pattern="\.csv$",full.names=FALSE)
接下来,我们使用lapply()
读取文件,对正确的行和列进行子集化,并将清理后的文件写入输出目录。
dataList <- lapply(theFiles,function(x){
y <- read.csv(paste0(inputDirectory,"/",x),skip = 4,header=FALSE)[c(1,2,4,6)]
write.table(y,file=paste0(outputDirectory,"/",x),row.names=FALSE,col.names=FALSE,sep=",")
})
# verify that files were written to cleaned directory
list.files(outputDirectory,full.names=TRUE)
...输出:
> list.files(outputDirectory,full.names=TRUE)
[1] "./pokemonData/cleaned/gen01.csv" "./pokemonData/cleaned/gen02.csv"
[3] "./pokemonData/cleaned/gen03.csv" "./pokemonData/cleaned/gen04.csv"
[5] "./pokemonData/cleaned/gen05.csv" "./pokemonData/cleaned/gen06.csv"
[7] "./pokemonData/cleaned/gen07.csv" "./pokemonData/cleaned/gen08.csv"
>
附录
由于评论者断言 paste0()
中文件名中的点未正确呈现,因此子目录的以下屏幕截图表明代码确实按我的预期工作。