#r #file #loops #csv
#r #файл #петли #csv
Вопрос:
У меня есть папка, содержащая кучу CSV-файлов с названиями «yob1980», «yob1981», «yob1982» и т.д.
Я должен использовать цикл for, чтобы просмотреть каждый файл и поместить его содержимое во фрейм данных — столбцы в фрейме данных должны быть «1980», «1981», «1982» и т.д.
Вот что у меня есть:
file_list <- list.files()
temp = list.files(pattern="*.txt")
babynames <- do.call(rbind,lapply(temp,read.csv, FALSE))
names(babynames) <- c("Name", "Gender", "Count")
Я чувствую, что мне нужен цикл for, но я не уверен, как перебирать файлы. Кто-нибудь укажет мне правильное направление?
Комментарии:
1. Являются ли CSV-файлы файлами с одним столбцом и без заголовков? И соответствуют ли они одним и тем же идентификаторам записей?
2. То, что у вас уже есть, выполняет цикл по всем файлам (
lapply
выполняет неявныйfor
цикл по всем файлам). И вы уже создаете один фрейм данных (do.call(rbind, ....)
). В чем вопрос?3. @Parfait файлы CSV не имеют заголовков, и внутри них есть три столбца, которые содержат имя, пол и количество этого имени
4. @MichaelGriffiths Я пытаюсь добавить столбец в фрейм данных, который включает год, которому соответствует имя.
5.
file_list
Для чего это нужно?
Ответ №1:
Мой любимый способ сделать это — использовать ldply
из plyr
пакета. Его преимущество заключается в возврате фрейма данных, поэтому вам не нужно выполнять шаг rbind после этого:
library( plyr )
babynames <- ldply( .data = list.files(pattern="*.txt"),
.fun = read.csv,
header = FALSE,
col.names=c("Name", "Gender", "Count") )
В качестве дополнительного преимущества вы можете очень легко выполнять многопоточный импорт, что значительно ускоряет импорт больших наборов данных из нескольких файлов:
library( plyr )
library( doMC )
registerDoMC( cores = 4 )
babynames <- ldply( .data = list.files(pattern="*.txt"),
.fun = read.csv,
header = FALSE,
col.names=c("Name", "Gender", "Count"),
.parallel = TRUE )
Слегка изменив вышесказанное, чтобы включить Year
столбец в результирующий фрейм данных, вы можете сначала создать функцию, а затем выполнить эту функцию внутри ldply
таким же образом, как вы бы выполнили read.csv
readFun <- function( filename ) {
# read in the data
data <- read.csv( filename,
header = FALSE,
col.names = c( "Name", "Gender", "Count" ) )
# add a "Year" column by removing both "yob" and ".txt" from file name
data$Year <- gsub( "yob|.txt", "", filename )
return( data )
}
# execute that function across all files, outputting a data frame
doMC::registerDoMC( cores = 4 )
babynames <- plyr::ldply( .data = list.files(pattern="*.txt"),
.fun = readFun,
.parallel = TRUE )
Это предоставит вам ваши данные в сжатом и аккуратном виде, и именно так я бы рекомендовал двигаться дальше. Хотя затем можно разделить данные за каждый год на отдельные столбцы, это, вероятно, не лучший способ.
Примечание: в зависимости от ваших предпочтений, может быть хорошей идеей преобразовать Year
столбец, скажем, integer
в class . Но это зависит от вас.
Комментарии:
1. Этот способ создает фрейм данных вместо списка — у меня возникли проблемы с преобразованием метода Майкла из списка в фрейм данных. Однако, как мне добавить годы в новый столбец в мой фрейм данных? Вроде как добавление в python
2. Вы включили последнюю строку
rbind
метода @Michael Griffiths? Это должно привести к преобразованию во фрейм данных.3. То, о чем вы просите, звучит не как an
append
, а как новый столбец для каждого файла. Для большинства наборов данных это не очень хорошая идея. Являются ли вашиname
gender
столбцы и одинаковыми для каждого файла?4.
doMC
у меня это не сработало, ноdoFuture::registerDoFuture(); future::plan("multisession", workers = 8)
сработало.
Ответ №2:
Использование purrr
library(tidyverse)
files <- list.files(path = "./data/", pattern = "*.csv")
df <- files %>%
map(function(x) {
read.csv(paste0("./data/", x))
}) %>%
reduce(rbind)
Ответ №3:
Рассмотрим анонимную функцию в lapply()
:
files = list.files(pattern="*.txt")
dfList <- lapply(files, function(i) {
df <- read.csv(i, header=FALSE, col.names=c("Name", "Gender", "Count"))
df$Year <- gsub("yob", "", i)
return(df)
})
finaldf <- do.call(rbind, dflist)
Ответ №4:
for
Цикл может быть более подходящим, чем lapply
в этом случае.
file_list = list.files(pattern="*.txt")
data_list <- vector("list", "length" = length(file.list))
for (i in seq_along(file_list)) {
filename = file_list[[i]]
# Read data in
df <- read.csv(filename, header = FALSE, col.names = c("Name", "Gender", "Count"))
# Extract year from filename
year = gsub("yob", "", filename)
df[["Filename"]] = year
# Add year to data_list
data_list[[i]] <- df
}
babynames <- do.call(rbind, data_list)
Комментарии:
1. Я изменил # Extract year из filename year = gsub(«yob», «», filename) df[[«Filename»]] = year, чтобы вручную увеличить год, потому что .txt был конечным, но спасибо за помощь!