从一个数据帧创建多个.csv文件

时间:2015-12-28 17:51:10

标签: r

我有一个包含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)它确实给了我列表中的所有项目(所以我假设循环正在工作。

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

您的代码的主要问题是您不使用花括号将多个语句放在循环中。从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"

这种方法有两个主要优点:

  1. 我们不再将整个数据帧列与每个循环迭代中的某些值进行比较,从而显着加快速度。当然,对于具有这个数量级的数据帧,没有办法注意到任何差异。但有一天,您可能希望对更大的数据集执行类似的操作。
  2. 在R社区 [citation needed] 中,循环通常是不受欢迎的。感谢apply family of functions,很少需要它们。熟悉这些功能是掌握R的最重要步骤之一。
  3. 此外:

    • 在你的函数中,你的第二个参数将遮蔽用于创建列表的list function,这是一个基本的R数据结构。在更复杂的情况下,这可能会导致意外行为并且难以调试问题。更好地避免这一点。
    • 这是非常主观的,但许多开发人员会告诉你,更改目录内的功能并不是一种好的做法。