[英]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 脚本来为我做这件事,但我想知道如何将这组操作应用于同一目录中的 all.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=",")
您可以列出目录中的所有文件,然后过滤以.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))
基本 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()
to append .cleaned
到每个原始文件名,以区分清理后的文件和原始文件。
由于最初的问题不包括最小的可重现示例,我们将使用我的Pokémon Stats GitHub 存储库中的数据来说明解决方案。
Pokémon stats 数据的维度与原始问题中描述的数据有很大不同,因此我们将跳过每个文件的前四行,只保留第 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=",")
})
可以使用其中一个原始文件的屏幕截图来验证 output。 我突出显示了第 1、2、4 和 6 列,从输入的第四行开始(包括 header 行)。
...和 ./pokemonData/gen01.csv.cleaned 的前几行的./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
包含第一代神奇宝贝。 此文件中的前三个神奇宝贝是 Bulbasaur、Ivysaur 和 Vensuaur。 从 output 可以看出,这些 Pokémon 和原文件中的 header 行都被跳过了,所以第一个观察是 Pokémon 4, Charmander。 我们还看到,第六列的Total
stat 匹配输入文件中已写入 output 文件的行。
因为我们在每个文件的末尾附加.cleaned
,所以我们可以使用与列出.csv
文件并使用read.csv()
读取它们相同的技术来列出.cleaned
文件。 这使我们能够将原始文件与清理后的文件保持距离。
# 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
子目录,并将文件写入该目录。
首先,我们为输入和 output 目录创建对象。 然后我们为 output 文件创建一个新的子目录,如果它不存在的话。
# solution that creates a ./cleaned subdirectory
inputDirectory <- "./pokemonData"
outputDirectory <- paste0(inputDirectory,"/cleaned")
if(!dir.exists(outputDirectory)) dir.create(outputDirectory)
通过在尝试创建目录之前检查目录是否存在,我们消除了该脚本第二次和后续运行时出现的错误。
接下来,我们列出输入目录中的文件。 因为我们稍后在脚本中使用inputDirectory
和outputDirectory
对象来手动构建每个输入和 output 文件的完整路径名,所以我们将list.files()
的full.names=
参数设置为FALSE
。
theFiles <- list.files(inputDirectory,pattern="\\.csv$",full.names=FALSE)
接下来,我们使用lapply()
读取文件,对正确的行和列进行子集化,并将清理后的文件写入 output 目录。
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)
...和 output:
> 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()
中文件名中的点未正确呈现,因此以下子目录的屏幕截图表明代码确实按我的预期工作。
嗨,我为你做了一些编码来回答你的问题。
下面是代码:
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=",")
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.