Ben*_*Ben 171 r list dataframe r-faq
如何制作数据框列表以及如何从列表中访问每个数据框?
例如,如何将这些数据框放在列表中?
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))
Run Code Online (Sandbox Code Playgroud)
Gre*_*gor 321
其他答案告诉你如何做data.frames列表时,你已经有一堆data.frames,例如,d1,d2,...有顺序命名的数据帧是一个问题,并且把它们放在一个列表是一个很好的修复,但最好的做法是避免让一堆data.frames首先不在列表中.
其他答案提供了大量有关如何将数据框分配给列表元素,访问它们等的详细信息.我们也会在这里稍微介绍一下,但重点是说不要等到你有一堆data.frames将它们添加到列表中.从列表开始.
本答案的其余部分将介绍一些您可能想要创建顺序变量的常见情况,并向您展示如何直接进入列表.如果您对R中的列表不熟悉,您可能还想阅读列表中元素和访问元素之间的区别是什么?[[[.
首先,不要创造d1 d2 d3.......创建一个dn包含3个元素的列表.
在阅读文件时,这很容易完成.也许你d在目录中有文件.您的目标是调用的data.frames列表n.你需要的第一件事是一个包含所有文件名的向量.你可以使用paste(例如data1.csv, data2.csv, ...)来构造它,但它可能更容易mydata用来获取所有适当的文件:my_files = paste0("data", 1:5, ".csv").您可以使用正则表达式来匹配文件,如果您需要帮助,请在其他问题中阅读有关正则表达式的更多信息.
在这一点上,大多数R初学者将使用list.files循环,并且没有任何问题,它可以正常工作.
my_data <- list()
for (i in seq_along(my_files)) {
my_data[[i]] <- read.csv(file = my_files[i])
}
Run Code Online (Sandbox Code Playgroud)
更像R的方法是使用my_files <- list.files(pattern = "\\.csv$"),这是上述的快捷方式
my_data <- lapply(my_files, read.csv)
Run Code Online (Sandbox Code Playgroud)
无论哪种方式,命名列表元素以匹配文件都很方便
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 = "")
Run Code Online (Sandbox Code Playgroud)
这非常简单,基本功能for为您完成.您可以按数据的一列(或多列)或您想要的任何其他内容进行拆分
mt_list = split(mtcars, f = mtcars$cyl)
# This gives a list of three data frames, one for each value of cyl
Run Code Online (Sandbox Code Playgroud)
这也是将数据框分成多个部分以进行交叉验证的好方法.也许你想lapply分成训练,测试和验证部分.
groups = sample(c("train", "test", "validate"),
size = nrow(mtcars), replace = TRUE)
mt_split = split(mtcars, f = groups)
# and mt_split has appropriate names already!
Run Code Online (Sandbox Code Playgroud)
也许你正在模拟数据,如下所示:
my_sim_data = data.frame(x = rnorm(50), y = rnorm(50))
Run Code Online (Sandbox Code Playgroud)
但谁只进行一次模拟?你想这样做100次,1000次,更多!但是,您不希望工作区中有10,000个数据框.使用read.csv并将它们放入列表中:
sim_list = replicate(n = 10,
expr = {data.frame(x = rnorm(50), y = rnorm(50))},
simplify = F)
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您还应该考虑是否确实需要单独的数据框,或者具有"组"列的单个数据框是否也能正常工作?使用readr::read_csv或者data.table::fread很容易"按组"对数据框执行操作.
如果它们是一个奇怪的分类(这是不寻常的),你可以简单地分配它们:
mylist <- list()
mylist[[1]] <- mtcars
mylist[[2]] <- data.frame(a = rnorm(50), b = runif(50))
...
Run Code Online (Sandbox Code Playgroud)
如果你有一个模式命名的数据帧,例如split(),mtcars,replicate,和你希望他们在列表中,你可以data.table他们,如果你可以写一个正则表达式匹配的姓名.就像是
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.
Run Code Online (Sandbox Code Playgroud)
通常,dplyr用于获取多个对象并将其返回到命名列表中.它的对应物df1用于获取单个对象并将其返回(不在列表中).
一个常见的任务是将数据帧列表组合成一个大数据帧.如果你想将它们叠加在一起,你可以使用df2它们,但是对于数据帧列表,这里有三个不错的选择:
# 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 that
# - are much faster
# - add id columns to identify the source
# - fill in missing values if some data frames have more columns than others
# see their help pages for details
big_data = data.table::rbindlist(df_list)
big_data = dplyr::bind_rows(df_list)
Run Code Online (Sandbox Code Playgroud)
(类似地使用df3或get用于列.)
要合并(加入)数据框列表,您可以看到这些答案.通常情况下,这个想法是用mget与get(或其他主机加入功能),让他们在一起.
放入列表类似的数据,因为你想要做类似的事情,每个数据帧,而像功能rbind,cbind dplyr::bind_cols,的Reduce包,和老merge lapply功能可以很容易地做到这一点.使用列表轻松处理事务的人的例子都是SO.
即使你使用lowly for循环,循环遍历列表的元素要比用它构造变量名sapply和访问对象容易得多do.call.也更容易调试.
考虑可扩展性.如果你真的只需要三个变量,它的优良使用purrr,plyr,l*ply.但是如果事实证明你真的需要6,那就更多了.而下一次,当你需要10或20,你发现自己复制和粘贴代码行,也许用查找/替换改变paste对get了,你在想这是编程不应该是怎么样.如果您使用列表,3个案例,30个案例和300个案例之间的差异最多只有一行代码---如果您自动检测到案例数量,例如,d1您的文件数量是多少,则根本没有变化目录.
您可以命名列表的元素,以防您想使用数字索引以外的其他东西来访问您的数据框(并且您可以同时使用这两个,这不是XOR选择).
总的来说,使用列表将使您编写更清晰,更易于阅读的代码,从而减少错误并减少混淆.
Pey*_*ton 126
这与您的问题无关,但您想要使用=而不是<-在函数调用中.如果您使用<-,您将最终创建变量,y1并y2在您正在使用的任何环境中:
d1 <- data.frame(y1 <- c(1, 2, 3), y2 <- c(4, 5, 6))
y1
# [1] 1 2 3
y2
# [1] 4 5 6
Run Code Online (Sandbox Code Playgroud)
这不会产生在数据框中创建列名的看似期望的效果:
d1
# y1....c.1..2..3. y2....c.4..5..6.
# 1 1 4
# 2 2 5
# 3 3 6
Run Code Online (Sandbox Code Playgroud)
该=运营商,在另一方面,将您的向量与参数相关联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)
Run Code Online (Sandbox Code Playgroud)
您可以像访问任何其他列表元素一样访问数据框:
my.list[[1]]
# y1 y2
# 1 1 4
# 2 2 5
# 3 3 6
Run Code Online (Sandbox Code Playgroud)
Ric*_*ven 19
您也可以访问特定的列和值在每个列表元素与 [和[[.这里有几个例子.首先,我们只能访问列表中每个数据框的第一列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
Run Code Online (Sandbox Code Playgroud)
同样,我们可以访问第二列中的第一个值
lapply(ldf, "[", 1, 2)
# $d1
# [1] 4
#
# $d2
# [1] 6
Run Code Online (Sandbox Code Playgroud)
然后我们也可以直接访问列值,作为向量,用 [[
lapply(ldf, "[[", 1)
# $d1
# [1] 1 2 3
#
# $d2
# [1] 3 2 1
Run Code Online (Sandbox Code Playgroud)
Mar*_*ler 13
如果您有大量按顺序命名的数据框,则可以创建所需数据框子集的列表,如下所示:
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
Run Code Online (Sandbox Code Playgroud)
where my.list2返回包含第2,第3和第4个数据帧的列表.
[[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
Run Code Online (Sandbox Code Playgroud)
但请注意,上面列表中的数据框不再被命名.如果要创建包含数据框子集的列表并希望保留其名称,可以尝试以下操作:
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
Run Code Online (Sandbox Code Playgroud)
返回:
> 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
Run Code Online (Sandbox Code Playgroud)
作为给定,你有一个"大"数字的具有相似名称的数据帧(这里是d#,其中#是一些正整数),以下是@ mark-miller方法的略微改进.它更简洁并返回一个命名的data.frames列表,其中列表中的每个名称都是相应原始data.frame的名称.
关键是mget与...一起使用ls.如果问题中提供的数据框d1和d2是环境中唯一名称为d#的对象,那么
my.list <- mget(ls(pattern="^d[0-9]+"))
Run Code Online (Sandbox Code Playgroud)
哪会回来
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
Run Code Online (Sandbox Code Playgroud)
此方法利用了pattern参数ls,它允许我们使用正则表达式对环境中对象的名称进行更精细的解析.正则表达式的替代方案"^d[0-9]+$"是"^d\\d+$".
正如@gregor 指出的那样,设置数据构建过程总体上要好一些,以便在开始时将data.frames放入命名列表中.
数据
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))
Run Code Online (Sandbox Code Playgroud)
小智 7
我认为自己是一个完全的新手,但我认为我对此处未说明的原始子问题之一有一个非常简单的答案:访问数据帧或其部分。
让我们首先使用如上所述的数据框创建列表:
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)
Run Code Online (Sandbox Code Playgroud)
然后,如果您想访问其中一个数据帧中的特定值,可以通过顺序使用双括号来实现。第一组让您进入数据框,第二组让您进入特定坐标:
my.list[[1]][3, 2]
[1] 6
Run Code Online (Sandbox Code Playgroud)
for循环模拟如果我有一个for生成数据帧的循环,我会从一个空的数据帧开始list(),并在生成数据帧时附加它们。
# Empty list
dat_list <- list()
for(i in 1:5){
# Generate dataframe
dat <- data.frame(x=rnorm(10), y=rnorm(10))
# Add to list
dat_list <- append(dat_list, list(dat))
}
Run Code Online (Sandbox Code Playgroud)
请注意,它list(dat)在我们的append()通话中。
n然后从我们使用的列表中获取第一个数据帧dat_list[[n]]。您可以以正常方式访问此数据框中的数据,例如dat_list[[2]]$x。
或者,如果您想要所有数据帧中的相同部分sapply(dat_list, "[", "x")。
请参阅@Gregor Thomas的答案,了解如何在没有for循环的情况下执行此操作。
| 归档时间: |
|
| 查看次数: |
185211 次 |
| 最近记录: |