我有一个包含 286 项的列表。
length(l)
[1] 286
我想知道的是为每个列表的 .csv 子集创建一个单独的 .csv 文件
split_csv <- function(df, list) {
setwd("dir")
for (i in list)
#print(i)
df_temp <- df[df$club == i, ]
name <- paste0("club_", i, ".csv")
write.csv(df_temp, name)
setwd("original_dir")
}
但问题是我现在只得到 .csv 文件!奇怪的是,当我取消注释 #print(i)
时,它确实给了我列表中的所有项目(所以我假设循环正在工作。
有什么想法吗?
最佳答案
您的代码的主要问题是您没有使用大括号将多个语句放入循环内。从 R 的角度来看,只有第一行 ( df_temp <- df[df$club == i, ]
) 在循环内进行评估。程序的其余部分 - 包括实际将内容写入文件 - 仅在循环结束后完成。由于循环内创建的变量将被添加到全局环境中并在循环外可用,因此不会引发错误。但是,实际上,您的文件写入代码仅在循环的最后一次迭代中执行。
解决这个问题很简单:
set.seed(123)
l <- data.frame(club=sample(LETTERS[1:10], 286, TRUE),
visitors=as.integer(runif(286, 100, 1000))
)
split_csv <- function(df, list) {
setwd("dir")
for (i in list) {
#print(i)
df_temp <- df[df$club == i, ]
name <- paste0("club_", i, ".csv")
write.csv(df_temp, name)
}
setwd("..")
}
split_csv(l, LETTERS[1:3])
list.files("dir/")
# [1] "club_A.csv" "club_B.csv" "club_C.csv"
但是让我们以您的问题为契机,看看如何改进此代码。
by
function可用于将 data.frame 分割为给定因子(或多个因子,但让我们保持简单)中具有相同值的子集。您可以在该子集上运行任何函数 - 包括自定义(和匿名)函数。
split_csv2 <- function(df, list) {
by(df, df$club, function(x) {
# `x` is subset of df with one value in `club`
# assign current "club" value for further reference
i <- x[1, "club"]
# don't do anything else if current club is not in list of allowed clubs
if (! i %in% list) return()
name <- paste0("dir/club_", i, ".csv")
write.csv(x, name)
}
)
}
invisible(split_csv2(l, LETTERS[2:4])) # discard output - it's not helpful anyway
list.files("dir/")
# [1] "club_B.csv" "club_C.csv" "club_D.csv"
这种方法有两个主要优点:
- 我们不再将整个数据帧列与每次循环迭代中的某些值进行比较,从而使其速度显着加快。当然,对于这个数量级的数据帧,无法注意到任何差异。但有一天您可能想要对更大的数据集执行类似的操作。
- R 社区通常不赞成循环[需要引用]。感谢apply family of functions ,很少需要它们。熟悉这些函数是掌握 R 之旅中最重要的步骤之一。
另外:
- 在你的函数中,你的第二个参数将遮盖
list
function用于创建列表(基本 R 数据结构之一)。在更复杂的情况下,这可能会导致意外行为和难以调试的问题。最好完全避免这种情况。 - 这是非常主观的,但许多开发人员会告诉您,在函数内更改目录并不是一个好的做法。
关于r - 从一个数据帧创建多个 .csv 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34498277/