将多个CSV文件读入单独的数据框架中

48
假设我们有目录 C:\R\Data 中的文件 file1.csvfile2.csv,...,file100.csv,并且我们希望将它们全部读入单独的数据框(例如 file1file2,...,file100)。
之所以这样做是因为尽管它们具有相似的名称,但它们具有不同的文件结构,因此将它们放在一个列表中并不太有用。
我可以使用 lapply,但这会返回包含 100 个数据框的单个列表。 相反,我希望将这些数据框放在全局环境中。
如何直接将多个文件读入全局环境?或者,如何将数据框列表的内容解压缩到其中?

5
请看我给@hadley的评论。请注意,我并没有问“将X个文件读入R的最佳方法是什么?”我的问题更具体,有其原因。我想我不应该说我想读取100个文件(只是试图概括),而是8个具有类似名称的不同文件。但是这里有太多人摆出高姿态。 - Fred
1
对于偶然发现这篇文章并且有一组100个结构相同(或几乎相同)的文件的人来说,最好的方法是按照Hadley和Joran在下面解释的方式将数据读入命名列表中。另外,可以看看Gregor对此帖子的回复,了解为什么这样做是有益的。 - lmo
如果它们是完全不同的结构,如何在循环中读取它们有帮助呢?无论如何它们都需要由单独的代码处理!—只需将它们分开阅读。 - Konrad Rudolph
11个回答

37

感谢大家的回复。

为了完整起见,这是我最终的答案,可以加载任意数量的(制表符)分隔文件,其中每个文件具有6列数据,其中第1列是字符,第2列是因子,其余列是数字:

##Read files named xyz1111.csv, xyz2222.csv, etc.
filenames <- list.files(path="../Data/original_data",
    pattern="xyz+.*csv")

##Create list of data frame names without the ".csv" part 
names <-substr(filenames,1,7)

###Load all files
for(i in names){
    filepath <- file.path("../Data/original_data/",paste(i,".csv",sep=""))
    assign(i, read.delim(filepath,
    colClasses=c("character","factor",rep("numeric",4)),
    sep = "\t"))
}

1
for(i in 1:length(names) - willnotburn

31

快速草稿,未经测试:

  1. 使用 list.files()dir() 动态生成文件列表。

  2. 这将返回一个向量,在 for 循环中沿着向量运行即可。

  3. 读取第 i 个文件,然后使用 assign() 将内容放入新变量 file_i 中。

这应该可以为您解决问题。


1
本地作用域与全局环境。你也可以尝试使用 i <<- read.csv(...) - Dirk Eddelbuettel
3
证明lapply在读取N个文件时更快。此外,如果不喜欢使用循环,那么你需要自己查阅*apply家族的资料。但需要注意的是,现在它们通常并不更快。 - Dirk Eddelbuettel
1
@Dirk Eddelbuettel 谢谢。我一直被告知要避免在 R 中使用循环。矢量化等等。但也许这都是传说...我想用 system.time() 很容易找出答案。 - Fred
准确无误。性能分析胜过老婆的传说。 - Dirk Eddelbuettel
9
哇,一起在回答中使用 "Yowser"、"assign" 和 "<<"?是不是有人劫持了 Dirk 的帐户? - mdsumner
显示剩余2条评论

17

通过使用包含所需数据框名称的字符变量与assign一起使用。

for(i in 1:100)
{
   oname = paste("file", i, sep="")
   assign(oname, read.csv(paste(oname, ".txt", sep="")))
}

16

这个答案旨在作为 Hadley's 答案的更有用的补充。

虽然 OP 特别想把每个文件读入他们的 R 工作空间作为单独的对象,但许多其他人可能会天真地认为这是他们想要做的,但事实上,将文件读入单个数据框列表会更好。

因此,这里记录一下如何做到这一点。

#If the path is different than your working directory
# you'll need to set full.names = TRUE to get the full
# paths.
my_files <- list.files("path/to/files")

#Further arguments to read.csv can be passed in ...
all_csv <- lapply(my_files,read.csv,...)

#Set the name of each list element to its
# respective file name. Note full.names = FALSE to
# get only the file names, not the full path.
names(all_csv) <- gsub(".csv","",
                       list.files("path/to/files",full.names = FALSE),
                       fixed = TRUE)
现在任何一个文件都可以通过my_files[["filename"]]来引用,这实际上并不比在您的工作区中有单独的filename变量更差,而且通常更方便一些。

8

这里有一种只用lapply来解压数据框列表的方法:

filenames <- list.files(path="../Data/original_data",
                        pattern="xyz+.*csv")

filelist <- lappy(filenames, read.csv)

#if necessary, assign names to data.frames
names(filelist) <- c("one","two","three")

#note the invisible function keeps lapply from spitting out the data.frames to the console

invisible(lapply(names(filelist), function(x) assign(x,filelist[[x]],envir=.GlobalEnv)))

1
您可以使用 paste0(“sheet_”,1:length(filelist)) 对命名进行“自动化”。 - NelsonGon
当我使用这个方法时,列名之间的空格被替换为“.”。例如,“Warehouse Code”列变成了“Warehouse.Code”。你知道如何保持列格式不变吗? - jb12n
嗨!我想知道如何向read.csv函数传递一些参数,而不是使用默认的参数进行调用?例如:read.csv(as.is = T, header = T, comment.char = "") - Denis

6
从文件夹中读取所有CSV文件,并创建与文件名相同的向量。
setwd("your path to folder where CSVs are")

filenames <- gsub("\\.csv$","", list.files(pattern="\\.csv$"))

for(i in filenames){
  assign(i, read.csv(paste(i, ".csv", sep="")))
}

3

从全局环境中访问列表元素的简单方法是使用attach函数。请注意,这实际上会在搜索路径上创建一个新的环境,并将列表中的元素复制到其中,因此您可能希望在附加后删除原始列表,以防止浮动两个潜在不同的副本。


我已经点赞了,但是示例代码会更好。 - PatrickT
不确定您要寻找什么。示例代码将是 attach(mylist) - Aaron left Stack Overflow
谢谢Aaron。我试图将你的回答与原始问题联系起来,看它如何与“list.files”、“assign”和其他答案中提到的内容相关联。 - PatrickT

1

我想更新Joran所提供的答案:

#If the path is different than your working directory
# you'll need to set full.names = TRUE to get the full
# paths.
my_files <- list.files(path="set your directory here", full.names=TRUE)
#full.names=TRUE is important to be added here

#Further arguments to read.csv can be passed in ...
all_csv <- lapply(my_files, read.csv)

#Set the name of each list element to its
# respective file name. Note full.names = FALSE to
# get only the file names, not the full path.
names(all_csv) <- gsub(".csv","",list.files("copy and paste your directory here",full.names = FALSE),fixed = TRUE)

#Now you can create a dataset based on each filename
df <- as.data.frame(all_csv$nameofyourfilename)

0

一个简化版本,假设你的 CSV 文件在工作目录中:

listcsv <- list.files(pattern= "*.csv") #creates list from csv files
names <- substr(listcsv,1,nchar(listcsv)-4) #creates list of file names, no .csv
for (k in 1:length(listcsv)){
  assign(names[[k]] , read.csv(listcsv[k]))
}
#cycles through the names and assigns each relevant dataframe using read.csv

-1
#copy all the files you want to read in R in your working directory
a <- dir()
#using lapply to remove the".csv" from the filename 
for(i in a){
list1 <- lapply(a, function(x) gsub(".csv","",x))
}
#Final step 
for(i in list1){
filepath <- file.path("../Data/original_data/..",paste(i,".csv",sep=""))
assign(i, read.csv(filepath))
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接