我有一堆csv文件,我试图一次读取到R中,csv中的每个数据帧都成为列表的一个元素。循环在很大程度上起作用,但它们不断覆盖列表元素。因此,例如,如果我在前两个文件上循环,则列表[[1]]和列表[[2]]中的数据帧都将包含第二个文件的数据帧。
#function to open one group of files named with "cores"
open_csv_core<- function(year, orgtype){
file<- paste(year, "/coreco.core", year, orgtype, ".csv", sep = "")
df <- read.csv(file)
names(df) <- tolower(names(df))
df <- df[df$ntee1 %in% c("C","D"),]
df<- df[!(df$nteecc %in% c("D20","D40", "D50", "D60", "D61")),]
return(df)
}
#function to open one group of files named with "nccs"
open_csv_nccs<- function(year, orgtype){
file2<- paste(year, "/nccs.core", year, orgtype, ".csv", sep="")
df2 <- read.csv(file2)
names(df2) <- tolower(names(df2))
df2 <- df2[df2$ntee1 %in% c("C","D"),]
df2<- df2[!(df2$nteecc %in% c("D20","D40", "D50", "D60", "D61")),]
return(df2)
}
#############################################################################
yrpc<- list()
yrpf<- list()
yrco<- list()
fname<- vector()
file_yrs<- as.character(c(1989:2019))
for(i in 1:length(file_yrs)){
fname<- list.files(path = file_yrs[i], pattern = NULL)
#accessing files in a folder and assigning to the proper function to open them based on how the file is named
for(j in 1:length(fname)){
if(grepl("pc.csv", fname[j])==T) {
if(grepl("nccs", fname[j])==T){
a <- open_csv_nccs(file_yrs[j], "pc")
yrpc[[paste0(file_yrs[i], "pc")]] <- a
} else {
b<- open_csv_core(file_yrs[j], "pc")
yrpc[[paste0(file_yrs[i], "pc")]] <- b
}
} else if (grepl("pf.csv", fname[j])==T){
if(grepl("nccs", fname[j])==T){
c <- open_csv_nccs(file_yrs[j], "pf")
yrpf[[paste0(file_yrs[i], "pf")]] <- c
} else {
d<- open_csv_core(file_yrs[j], "pf")
yrpf[[paste0(file_yrs[i], "pf")]] <- d
}
} else {
if(grepl("nccs", fname[j])==T){
e<- open_csv_nccs(file_yrs[j], "co")
yrco[[paste0(file_yrs[i], "co")]] <- e
} else {
f<- open_csv_core(file_yrs[j], "co")
yrco[[paste0(file_yrs[i], "co")]] <- f
}
}
}
}
实际上,两个csv读取函数的作用完全相同,除了路径不同之外。
如果你找到了一种方法,用抽象路径而不是相对路径列出你的文件路径(只是文件名),您不需要像可以。这可以通过list.files()
中的full.names = TRUE
实现。
第二点是,似乎从来没有来自同一年份和同一类型的a";nccs.core";除了"文件"之外;coreco.core";文件所以他们是相互的独家因此,没有必要用逻辑来区分这些情况,这简化了我们的代码。
第三点是,您只想按文件类型("pc"、"pf"、"co")和年份来分隔数据帧。
我不会为每种类型创建3个列表,而是创建一个res-ults列表,其中为每一种类型包含一个内部列表。
我会这样解决这个问题:
years <- c(1989:2019)
path_to_type <- function(path) gsub(".*(pc|pf|co)\.csv", "\1", path)
res <- list("pc" = list(),
"pf" = list(),
"co" = list())
lapply(years, function(year) {
files <- list.files(path = year, pattern = "\.csv", full.names = TRUE)
dfs <- lapply(files, function(path) {
print(path) # just to signal that the path is getting processed
df <- read.csv(path)
file_type <- path_to_type(path)
names(df) <- tolower(names(df))
df <- df[df$ntee1 %in% c("C", "D"), ]
df <- df[!(df$nteecc %in% c("D20", "D40", "D50", "D60", "D61")), ]
res[[file_type]][[year]] <- df
})
})
现在,您可以按file_type和年份从结果列表中调用例如:
res[["co"]][[1995]]
res[["pf"]][[2018]]
等等。
实际上,在这种情况下lapply()
调用的结果是不感兴趣。只是res
的内容。。。(结果列表)。
似乎在for(j in 1:length(fname)){...
中创建了4个变量a
、b
、c
或d
中的一个。您正在重用这些变量名,因此它们会被覆盖。
";正确的";实现这一点的方法是使用CCD_ 10来代替CCD_。将文件列表和所需函数(如open_csv_core
等)传递给lapply
,返回的返回值是结果列表。