如何制作数据框的列表?

如何制作dataframe列表,以及如何从列表中访问每个dataframe? 我无法find这个简单的例子。

所以我告诉我我的post太短了,所以我会通过把一些数据框放在一个列表中来让它滚动。

d1<-data.frame(y1<-c(1,2,3),y2<-c(4,5,6)) d2<-data.frame(y1<-c(3,2,1),y2<-c(6,5,4)) 

这与你的问题没有关系,但你想在函数调用中使用=而不是<- 。 如果你使用<- ,你将最终在你所处的任何环境中创buildvariablesy1y2

 d1<-data.frame(y1<-c(1,2,3),y2<-c(4,5,6)) y1 # [1] 1 2 3 y2 # [1] 4 5 6 

这将不会在数据框中创build列名称的表面效果:

 d1 # y1....c.1..2..3. y2....c.4..5..6. # 1 1 4 # 2 2 5 # 3 3 6 

另一方面, =运算符将会将您的向量与参数关联到data.frame

至于你的问题,制作数据框清单很简单:

 d1 <- data.frame(y1=c(1,2,3),y2=c(4,5,6)) d2 <- data.frame(y1=c(3,2,1),y2=c(6,5,4)) my.list <- list(d1, d2) 

您可以像访问任何其他列表元素一样访问数据框架:

 my.list[[1]] # y1 y2 # 1 1 4 # 2 2 5 # 3 3 6 

其他答案显示了如何已经有一堆数据框架的情况下创builddata.frames列表,例如d1d2 ,…。按顺序命名的数据框架是一个问题,并将它们放在列表中是一个很好的解决scheme,但最好的做法是避免有一堆data.frames不在列表中的第一位。

其他的答案给了如何将数据框分配给列表元素,访问它们等详细信息,我们也会在这里介绍一点,但是要点是不要等到你有一堆data.frames将它们添加到列表。 从列表开始。

如果他们是一个奇怪的分类(这是不寻常的),你可以简单地分配他们:

 mylist <- list() mylist[[1]] <- mtcars mylist[[2]] <- data.frame(a = rnorm(50), b = runif(50)) ... 

这个答案的其余部分将涵盖一些常见的情况,你可能会试图创build顺序variables,并告诉你如何直接进入列表。 如果你对R中的列表不熟悉,你可能也想看看[[[在访问列表元素中有什么区别? 。


从一开始就列出

千万不要创造d1 d2 d3 ,…,首先。 用3个元素创build一个列表d

将多个文件读入数据框列表

阅读文件时,这个操作非常简单。 也许你已经有一个文件data1.csv, data2.csv, ...在一个目录中。 你的目标是一个名为mydata的数据框架列表。 你需要的第一件事是一个包含所有文件名的向量。 你可以使用粘贴(例如, my_files = paste0("data", 1:5, ".csv") )来构造这个,但是使用list.files来获取所有合适的文件可能更容易: my_files <- list.files(pattern = "\\.csv$")

在这一点上,大多数R初学者将使用for循环,并没有什么错,它工作得很好。

 my_data <- list() for (i in seq_along(my_files)) { my_data[[i]] <- read.csv(file = my_files[i]) } 

一个更像R的方式来做到这一点是lapply

 my_data <- lapply(my_files, read.csv) 

无论哪种方式,命名列表元素来匹配文件是很方便的

 names(my_data) <- gsub("\\.csv$", "", my_files) # or, if you prefer the consistent syntax of stringr names(my_data) <- stringr::str_replace(my_files, pattern = ".csv", replacement = "") 

将dataframe分割成dataframe列表

这是超级简单的,基本functionsplit()为你做。 您可以按数据的一列(或多列)进行分割,也可以通过其他任何您想要的方法进行分割

 mt_list = split(mtcars, f = mtcars$cyl) # This gives a list of three data frames, one for each value of cyl 

这也是一个很好的方式来将数据框分成多个部分进行交叉validation。 也许你想把mtcars分成训练,testing和validation片断。

 groups = sample(c("train", "test", "validate"), size = nrow(mtcars), replace = TRUE) mt_split = split(mtcars, f = groups) # and mt_split has appropriate names already! 

模拟数据框的列表

也许你正在模拟数据,如下所示:

 my_sim_data = data.frame(x = rnorm(50), y = rnorm(50)) 

但是谁只做一次模拟? 你想这样做100次,1000次,更多! 但是您希望工作空间中有10,000个数据框。 使用replicate并将它们放在一个列表中:

 sim_list = replicate(n = 10, expr = {data.frame(x = rnorm(50), y = rnorm(50))}, simplify = F) 

特别是在这种情况下,你还应该考虑你是否真的需要单独的数据框,或者是否只有一个带“组”列的数据框才能工作? 使用data.tabledplyr可以很容易地将数据框“按组”分组。

我没有把我的数据放在一个列表中:(我会下一次,但我现在能做什么?

如果你有一个模式中的数据框,例如df1df2df3 ,并且你希望他们在一个列表中,你可以得到它们,如果你可以写一个正则expression式来匹配这个名字。 就像是

 df_list = mget(ls(pattern = "df[0-9]")) # this would match any object with "df" followed by a digit in its name # you can test what objects will be got by just running the ls(pattern = "df[0-9]") # part and adjusting the pattern until it gets the right objects. 

通常, mget用于获取多个对象并将其返回到一个已命名列表中。 其对应的get用于获取单个对象并将其不返回到列表中。

将dataframe列表组合成单个dataframe

一个常见的任务是将dataframe列表组合成一个大dataframe。 如果你想把它们堆叠在一起,你可以使用rbind来配对它们,但是对于数据框的列表,这里有三个好的select:

 # base option - slower but not extra dependencies big_data = do.call(what = rbind, args = df_list) # data table and dplyr have nice functions for this # they will be faster and can also add id columns to identify # which list item they came from. They can also fill in # missing values if some data frames have more columns than others big_data = data.table::rbindlist(df_list) big_data = dplyr::bind_rows(df_list) 

(对于列同样使用cbinddplyr::bind_cols 。)

要合并(join)数据框的列表,您可以看到这些答案 。 通常,这个想法是使用Reducemerge (或其他连接函数)将它们放在一起。

为什么把数据放在列表中?

把类似的数据放在列表中,因为你想对每个数据框做类似的事情,像lapplysapply do.callpurrr包和旧的plyr l*ply函数的function可以很容易地做到这一点。 人们用列表轻松做事的例子已经结束了。

即使使用低级for循环,循环列表元素也比使用paste构造variables名称并通过get访问对象要容易得多。 更容易debugging(它会阻止这个错误 )。

想想可扩展性 。 如果你真的只需要三个variables,可以使用d1d2d3 。 但是,如果事实certificate你真的需要6,那么更多的打字。 下一次,当你需要10或20个时,你会发现自己复制和粘贴代码行,也许使用find / replace将d14更改为d15 ,而你认为这不是编程的方式 。 如果使用列表,则3个,30个和300个个案之间的差异最多只有一行代码 – 如果您的案例数自动检测到,例如,有多less.csv文件在你的目录中。

您可以命名列表中的元素,以防您想使用非数字索引来访问数据框(您可以同时使用这两个元素,这不是XORselect)。

总的来说,使用列表会导致您编写更简洁易读的代码,从而减less错误并减less混淆。

您还可以使用[[[ 。]访问每个列表元素中的特定列和值。 这里有几个例子。 首先,我们只能用lapply(ldf, "[", 1)来访问列表中每个数据框的第一列,其中1表示列号。

 ldf <- list(d1 = d1, d2 = d2) ## create a named list of your data frames lapply(ldf, "[", 1) # $d1 # y1 # 1 1 # 2 2 # 3 3 # # $d2 # y1 # 1 3 # 2 2 # 3 1 

同样,我们可以用第二列访问第一个值

 lapply(ldf, "[", 1, 2) # $d1 # [1] 4 # # $d2 # [1] 6 

然后我们也可以直接访问列值,作为一个向量, [[

 lapply(ldf, "[[", 1) # $d1 # [1] 1 2 3 # # $d2 # [1] 3 2 1 

如果您有大量按顺序命名的数据框,则可以创build所需数据框子集的列表,如下所示:

 d1 <- data.frame(y1=c(1,2,3), y2=c(4,5,6)) d2 <- data.frame(y1=c(3,2,1), y2=c(6,5,4)) d3 <- data.frame(y1=c(6,5,4), y2=c(3,2,1)) d4 <- data.frame(y1=c(9,9,9), y2=c(8,8,8)) my.list <- list(d1, d2, d3, d4) my.list my.list2 <- lapply(paste('d', seq(2,4,1), sep=''), get) my.list2 

my.list2返回一个包含第二,第三和第四数据框的列表。

 [[1]] y1 y2 1 3 6 2 2 5 3 1 4 [[2]] y1 y2 1 6 3 2 5 2 3 4 1 [[3]] y1 y2 1 9 8 2 9 8 3 9 8 

但请注意,上面列表中的数据框不再被命名。 如果你想创build一个包含数据框子集的列表并且想保留它们的名字,你可以试试这个:

 list.function <- function() { d1 <- data.frame(y1=c(1,2,3), y2=c(4,5,6)) d2 <- data.frame(y1=c(3,2,1), y2=c(6,5,4)) d3 <- data.frame(y1=c(6,5,4), y2=c(3,2,1)) d4 <- data.frame(y1=c(9,9,9), y2=c(8,8,8)) sapply(paste('d', seq(2,4,1), sep=''), get, environment(), simplify = FALSE) } my.list3 <- list.function() my.list3 

它返回:

 > my.list3 $d2 y1 y2 1 3 6 2 2 5 3 1 4 $d3 y1 y2 1 6 3 2 5 2 3 4 1 $d4 y1 y2 1 9 8 2 9 8 3 9 8 > str(my.list3) List of 3 $ d2:'data.frame': 3 obs. of 2 variables: ..$ y1: num [1:3] 3 2 1 ..$ y2: num [1:3] 6 5 4 $ d3:'data.frame': 3 obs. of 2 variables: ..$ y1: num [1:3] 6 5 4 ..$ y2: num [1:3] 3 2 1 $ d4:'data.frame': 3 obs. of 2 variables: ..$ y1: num [1:3] 9 9 9 ..$ y2: num [1:3] 8 8 8 > my.list3[[1]] y1 y2 1 3 6 2 2 5 3 1 4 > my.list3$d4 y1 y2 1 9 8 2 9 8 3 9 8 

按照给定的方式,你有一个“大量”的数据框架,它们有相似的名字(这里d#是一个正整数),下面是@ mark-miller方法的一个小改进,它会自动返回一个指定的列表的data.frames和更简洁。

关键是与ls一起使用mget 。 如果问题中提供的dataframed1和d2是环境中名称为d#的唯一对象,则

 my.list <- mget(ls(pattern="^d[0-9]+")) 

这将返回

 my.list $d1 y1 y2 1 1 4 2 2 5 3 3 6 $d2 y1 y2 1 3 6 2 2 5 3 1 4 

这个方法利用了ls中的模式参数,它允许我们使用正则expression式来更好地parsing环境中对象的名称。

正如@gregor所指出的那样 ,设置数据构build过程是一个更好的总体,以便数据框架在开始时被放入命名列表中。

数据

 d1<-data.frame(y1 = c(1,2,3),y2 = c(4,5,6)) d2<-data.frame(y1 = c(3,2,1),y2 = c(6,5,4)) 

这可能有点晚,但回到你的例子,我想我会延长答案只是一点点。

  D1 <- data.frame(Y1=c(1,2,3), Y2=c(4,5,6)) D2 <- data.frame(Y1=c(3,2,1), Y2=c(6,5,4)) D3 <- data.frame(Y1=c(6,5,4), Y2=c(3,2,1)) D4 <- data.frame(Y1=c(9,9,9), Y2=c(8,8,8)) 

然后你可以很容易地列出你的名单

 mylist <- list(D1,D2,D3,D4) 

现在你有一个列表,而不是像旧的方式访问列表

 mylist[[1]] # to access 'd1' 

你可以使用这个函数来获取和分配你select的dataframe。

 GETDF_FROMLIST <- function(DF_LIST, ITEM_LOC){ DF_SELECTED <- DF_LIST[[ITEM_LOC]] return(DF_SELECTED) } 

现在得到你想要的。

 D1 <- GETDF_FROMLIST(mylist, 1) D2 <- GETDF_FROMLIST(mylist, 2) D3 <- GETDF_FROMLIST(mylist, 3) D4 <- GETDF_FROMLIST(mylist, 4) 

希望额外的帮助。

干杯!