У меня есть куча 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-файлов?
Существует около 100 файлов с похожими (но слегка отличающимися) соглашениями об именах. Как правило, на каждый год с 1989 по 2019 год приходится по 2-3 файла трех типов — pf, pc и co. Некоторые файлы называются с использованием «nccs», а некоторые — с использованием «core». Например, файл может называться: 2019nccspf.csv или 2019coreco.csv и т. д. Поскольку не существует согласованной структуры, в которой возможны комбинации, я написал циклы, чтобы сначала проверить тип в имени (pc, pf, co ) (чтобы я мог использовать этот тип в функции), а затем указать, есть ли в имени «nccs», чтобы получить правильный путь к файлу.
Что касается «переопределения» - скажем, у меня есть файл pf для 2018 и 2019 годов. Я хочу, чтобы pf 2018 года был фреймом данных в элементе списка [[1]], а pf 2019 года находился в том же списке, что и элемент [[ 2]]. Вместо этого я получаю 2019 pf как в [[1]], так и в [[2]].





Кажется, что в своем for(j in 1:length(fname)){... вы создаете одну из 4 переменных a, b, c или d. И вы повторно используете эти имена переменных, поэтому они перезаписываются.
«Правильный» способ сделать это — использовать lapply вместо цикла for. Передайте список файлов и требуемую функцию (например, open_csv_core и т. д.) в lapply, а возвращаемое значение — это список результатов.
На самом деле обе ваши функции чтения csv делают то же самое, разве что пути разные.
Если вы найдете способ перечислить свои файлы с абстрактными путями вместо относительных
пути (только имена файлов), вам не нужно будет восстанавливать пути, например
ты сделаешь. Это возможно с помощью full.names = TRUE в list.files().
Второй момент: кажется, никогда не бывает одного и того же года и одного типа. файл «nccs.core» в дополнение к файлу «coreco.core». Так они взаимно эксклюзив. Итак, нет никакой логики, необходимой для различения этих случаев, что упрощает наш код.
Третий момент: вы просто хотите разделить фреймы данных по типу файла ("pc", "pf", "co") и годам.
Вместо создания 3 списков для каждого типа я бы создал один список разрешение-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
})
})
Теперь вы можете вызывать из списка результатов по типу файла и году например.:
res[["co"]][[1995]]
res[["pf"]][[2018]]
И так далее.
На самом деле результаты вызовов lapply() в этом случае таковы:
не интересно. Просто содержание res ... (список результатов).
Это сработало превосходно; Спасибо большое. Единственная модификация, которую я сделал, заключалась в том, что «years<- c(1989:2019)» нужно было обернуть в as.character(), чтобы list.files работал, но в остальном бесшовно.
Это довольно много дублированного кода. Можете объяснить человеческим языком, в чем смысл кода? Все ли файлы должны читаться одинаково? Или какие отличия?