繁体   English   中英

将对单个.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 脚本来为我做这件事,但我想知道如何将这组操作应用于同一目录中的 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)

通过在尝试创建目录之前检查目录是否存在,我们消除了该脚本第二次和后续运行时出现的错误。

接下来,我们列出输入目录中的文件。 因为我们稍后在脚本中使用inputDirectoryoutputDirectory对象来手动构建每个输入和 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()中文件名中的点未正确呈现,因此以下子目录的屏幕截图表明代码确实按我的预期工作。

在此处输入图像描述

嗨,我为你做了一些编码来回答你的问题。

  1. 首先设置工作目录
  2. 列出您需要处理的所有文件。 我的假设是所有文件都以“Hongjiao_Medium_High”开头,然后有一些数字
  3. 使用 FOR 循环遍历文件名列表
  4. 通过一些调整将您的代码粘贴到 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=",")
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM