其他答案向您展示了 已经拥有 一堆数据框 如何 制作数据框列表 d1
, d2
,... 拥有连续命名的数据框是一个问题,将它们放在列表中是一个很好的解决办法,但最佳做法是避免 首先 在列表中没有一堆数据框
其他答案提供了大量有关如何将数据框分配给列表元素、访问它们等的详细信息。我们也会在这里稍微介绍一下,但要点 是 不要 don't wait until you have a bunch of a data.frames
to add them to a list. Start with the list.
本回答的其余部分将介绍一些您可能想要创建顺序变量的常见情况,并向您展示如何直接进入列表。如果您是 R 中列表的新手,您可能还想阅读 What's the difference between [[
and [
in accessing elements of a list? .
从头开始列出清单
首先, d1
d2
d3
不要创建 dn
, ..., d
包含 n
元素的列表。
将多个文件读入数据框列表
在目录中 data1.csv, data2.csv, ...
有文件 mydata
。您需要的第一件事是一个包含所有文件名的向量。您可以使用粘贴(例如)来构建它 my_files = paste0("data", 1:5, ".csv")
来获取所有适当的文件 list.files
可能更容易 my_files <- list.files(pattern = "\\.csv$")
。您可以使用正则表达式来匹配文件,如果您需要帮助,请在其他问题中阅读有关正则表达式的更多信息。这样,即使它们不遵循很好的命名方案,您也可以抓取所有 CSV 文件。或者,如果您需要从一堆 CSV 文件中挑选出某些 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)
当然,可以 read.csv
适当替换其他数据导入功能。 readr::read_csv
或者 data.table::fread
会更快,或者您可能还需要针对不同文件类型使用不同的功能。
无论哪种方式,将列表元素命名为与文件匹配都很方便
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 = "")
将数据框拆分为数据框列表
这非常简单,基本函数 split()
会帮你完成。你可以按数据列(或多列)进行拆分,也可以按你想要的任何其他方式进行拆分
mt_list = split(mtcars, f = mtcars$cyl)
# This gives a list of three data frames, one for each value of cyl
这也是将数据框拆分成多个部分以进行交叉验证的好方法。也许你想将其拆分 mtcars
成训练、测试和验证部分。
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
可以很容易地对数据框进行“按组”操作。
我没有把我的数据放入列表中:(下次我会这么做,但我现在能做什么?
如果它们是奇怪的组合(这很不寻常),您可以简单地分配它们:
mylist <- list()
mylist[[1]] <- mtcars
mylist[[2]] <- data.frame(a = rnorm(50), b = runif(50))
...
如果你有以某种模式命名的数据框,例如, df1
, df2
, df3
并且你想将它们放在列表中,那么 get
只要你能编写一个正则表达式来匹配名称,就可以实现它们。例如
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
用于获取单个对象并返回它(不在列表中)。
将数据框列表组合成单个数据框
一个常见的任务是将一串数据框组合成一个大数据框。如果你想将它们堆叠在一起,你可以使用 rbind
一对数据框,但对于一串数据框,这里有三个不错的选择:
# 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)
(类似地,对列使用 cbind
或 dplyr::bind_cols
。)
要合并(连接)数据框列表,您可以查看 这些答案 。通常,想法是使用 Reduce
with merge
(或其他连接函数)将它们组合在一起。
但我确实需要按顺序命名的变量
使用它们可能很麻烦,而且几乎总是你不需要它们,但如果你确实需要它们,请尽你所能 list
,然后你可以 list2env()
将所有列表项放入一个环境中,比如你的 .GlobalEnv
.
为什么要将数据放在列表中?
将相似的数据放在列表中,因为您想对每个数据框执行类似的操作,而像 lapply
, sapply
do.call
, the purrr
package 和旧 plyr
l*ply
函数这样的函数可以轻松做到这一点。人们使用列表轻松完成操作的例子在 SO 上随处可见。
即使使用低级的 for 循环,循环遍历列表元素也比用 构造变量名 paste
和用 访问对象 get
。调试也更容易。
考虑 可扩展性 。如果您实际上只需要三个变量,那么使用就没问题 d1
, d2
, d3
。但是,如果您实际上需要 6 个变量,那么就需要输入更多内容。下次,当您需要 10 或 20 个变量时,您会发现自己正在复制和粘贴代码行,也许使用查找/替换来更改为 d14
, d15
并且您会认为 编程不应该是这样的 。如果您使用列表,3 个案例、30 个案例和 300 个案例之间的差异最多是一行代码——如果您的案例数量是通过 .csv
目录中的文件数量自动检测的,则根本没有变化。
您可以命名列表的元素,以防您想使用数字索引以外的其他东西来访问数据框(并且您可以同时使用两者,这不是 XOR 选择)。
总的来说,使用列表可以让你编写更干净、更易读的代码,从而减少错误和混乱。