如何制作数据框的列表?
如何制作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))
这与你的问题没有关系,但你想在函数调用中使用=
而不是<-
。 如果你使用<-
,你将最终在你所处的任何环境中创buildvariablesy1
和y2
:
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列表,例如d1
, d2
,…。按顺序命名的数据框架是一个问题,并将它们放在列表中是一个很好的解决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.table
或dplyr
可以很容易地将数据框“按组”分组。
我没有把我的数据放在一个列表中:(我会下一次,但我现在能做什么?
如果你有一个模式中的数据框,例如df1
, df2
, df3
,并且你希望他们在一个列表中,你可以得到它们,如果你可以写一个正则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)
(对于列同样使用cbind
或dplyr::bind_cols
。)
要合并(join)数据框的列表,您可以看到这些答案 。 通常,这个想法是使用Reduce
和merge
(或其他连接函数)将它们放在一起。
为什么把数据放在列表中?
把类似的数据放在列表中,因为你想对每个数据框做类似的事情,像lapply
, sapply
do.call
, purrr
包和旧的plyr
l*ply
函数的function可以很容易地做到这一点。 人们用列表轻松做事的例子已经结束了。
即使使用低级for循环,循环列表元素也比使用paste
构造variables名称并通过get
访问对象要容易得多。 更容易debugging(它会阻止这个错误 )。
想想可扩展性 。 如果你真的只需要三个variables,可以使用d1
, d2
, d3
。 但是,如果事实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)
希望额外的帮助。
干杯!