【问题标题】:Append data frames together in a for loop在 for 循环中将数据帧附加在一起
【发布时间】:2015-06-06 19:01:41
【问题描述】:

我有一个for loop,它会在每次迭代后生成一个数据框。我想将所有数据帧附加在一起,但发现很难。以下是我 正在尝试,请建议如何解决它:

d = NULL
for (i in 1:7) {

  # vector output
  model <- #some processing

  # add vector to a dataframe
  df <- data.frame(model)

}

df_total <- rbind(d,df)

【问题讨论】:

    标签: r


    【解决方案1】:

    你应该试试这个:

    df_total = data.frame()
    for (i in 1:7){
        # vector output
        model <- #some processing
    
        # add vector to a dataframe
        df <- data.frame(model)
        df_total <- rbind(df_total,df)
    }
    

    【讨论】:

    • 它在单列中逐帧附加。如何将所有数据框附加到单独的列中?
    • 使用 cbind() 代替 rbind()
    • 使用cbind() 导致Error in data.frame(..., check.names = FALSE) : arguments imply differing number of rows: 0, 18262
    • 您是否在重新执行循环之前重置了 df_total = data.frame()?
    • 不重置,for loop 的每次迭代都会给出相同的行数
    【解决方案2】:

    同样,马丁是正确的,但要使其正常工作,您必须从一个已经有至少一列的数据框开始

    model <- #some processing
    df <- data.frame(col1=model)
    
    for (i in 2:17)
    {
         model <- # some processing
         nextcol <-  data.frame(model)
         colnames(nextcol) <- c(paste("col", i, sep="")) # rename the comlum
         df <- cbind(df, nextcol)
    }
    

    【讨论】:

    • 它可以工作,但会将数据附加到单个列中。我希望所有数据框都在单独的列中
    【解决方案3】:

    不要在循环内这样做。列一个列表,然后在循环外将它们组合起来。

    datalist = list()
    
    for (i in 1:5) {
        # ... make some data
        dat <- data.frame(x = rnorm(10), y = runif(10))
        dat$i <- i  # maybe you want to keep track of which iteration produced it?
        datalist[[i]] <- dat # add it to your list
    }
    
    big_data = do.call(rbind, datalist)
    # or big_data <- dplyr::bind_rows(datalist)
    # or big_data <- data.table::rbindlist(datalist)
    

    这是一种更像 R 的做事方式。它也可以大大加快,特别是如果您使用dplyr::bind_rowsdata.table::rbindlist 进行数据帧的最终组合。

    【讨论】:

    • 它也可以,但我想将所有列表写入单独的列
    • @Ibe 你真的应该编辑你的问题。提供示例数据和所需的输出(请参阅我在马丁的回答中的评论)并把rbind 排除在您的问题之外,因为所有rbind 所做的都是将行绑定在一起。
    • 刚刚将代码中的rbind 替换为cbind。它有效,现在我将所有列表放在单独的列中
    • 同样,如果这一步你觉得慢,试试dplyr::bind_cols()
    • do.call(rbind, datalist) 是一种很好的写作方式rbind(datalist[[1]], datalist[[2]], datalist[[3]], ...)
    【解决方案4】:

    在 Coursera 课程“R 编程简介”中,对这项技能进行了测试。 他们给所有学生 332 个单独的 csv 文件,并要求他们以编程方式组合几个文件来计算污染物的平均值。

    这是我的解决方案:

      # create your empty dataframe so you can append to it.
      combined_df <- data.frame(Date=as.Date(character()),
                        Sulfate=double(),
                        Nitrate=double(),
                        ID=integer())
      # for loop for the range of documents to combine
      for(i in min(id): max(id)) {
        # using sprintf to add on leading zeros as the file names had leading zeros
        read <- read.csv(paste(getwd(),"/",directory, "/",sprintf("%03d", i),".csv", sep=""))
        # in your loop, add the files that you read to the combined_df
        combined_df <- rbind(combined_df, read)
      }
    

    【讨论】:

    • 将它们全部读入一个列表然后将它们全部组合起来会更有效。
    【解决方案5】:

    尝试使用rbindlist 方法而不是rbind,因为它非常非常快。

    例子:

    library(data.table)
    
    ##### example 1: slow processing ######
    
    table.1 <- data.frame(x = NA, y = NA)
    time.taken <- 0
    for( i in 1:100) {
      start.time = Sys.time()
      x <- rnorm(100)
      y <- x/2 +x/3
      z <- cbind.data.frame(x = x, y = y)
    
      table.1 <- rbind(table.1, z)
      end.time <- Sys.time()
      time.taken  <- (end.time - start.time) + time.taken
    
    }
    print(time.taken)
    > Time difference of 0.1637917 secs
    
    ####example 2: faster processing #####
    
    table.2 <- list()
    t0 <- 0
    for( i in 1:100) {
      s0 = Sys.time()
      x <- rnorm(100)
      y <- x/2 + x/3
    
      z <- cbind.data.frame(x = x, y = y)
    
      table.2[[i]] <- z
    
      e0 <- Sys.time()
      t0  <- (e0 - s0) + t0
    
    }
    s1 = Sys.time()
    table.3 <- rbindlist(table.2)
    e1 = Sys.time()
    
    t1  <- (e1-s1) + t0
    t1
    > Time difference of 0.03064394 secs
    

    【讨论】:

      【解决方案6】:

      这里有一些 tidyverse 和自定义函数选项,它们可能会根据您的需要起作用:

      library(tidyverse)
      
      # custom function to generate, filter, and mutate the data:
      combine_dfs <- function(i){
       data_frame(x = rnorm(5), y = runif(5)) %>% 
          filter(x < y) %>% 
          mutate(x_plus_y = x + y) %>% 
          mutate(i = i)
      }
      
      df <- 1:5 %>% map_df(~combine_dfs(.))
      df <- map_df(1:5, ~combine_dfs(.)) # both give the same results
      > df %>% head()
      # A tibble: 6 x 4
             x      y x_plus_y     i
         <dbl>  <dbl>    <dbl> <int>
      1 -0.973 0.673    -0.300     1
      2 -0.553 0.0463   -0.507     1
      3  0.250 0.716     0.967     2
      4 -0.745 0.0640   -0.681     2
      5 -0.736 0.228    -0.508     2
      6 -0.365 0.496     0.131     3
      

      如果你有一个需要合并的文件目录,你可以做类似的事情:

      dir_path <- '/path/to/data/test_directory/'
      list.files(dir_path)
      
      combine_files <- function(path, file){
        read_csv(paste0(path, file)) %>% 
          filter(a < b) %>% 
          mutate(a_plus_b = a + b) %>% 
          mutate(file_name = file) 
      }
      
      df <- list.files(dir_path, '\\.csv$') %>% 
        map_df(~combine_files(dir_path, .))
      
      # or if you have Excel files, using the readxl package:
      combine_xl_files <- function(path, file){
        readxl::read_xlsx(paste0(path, file)) %>% 
          filter(a < b) %>% 
          mutate(a_plus_b = a + b) %>% 
          mutate(file_name = file) 
      }
      
      df <- list.files(dir_path, '\\.xlsx$') %>% 
        map_df(~combine_xl_files(dir_path, .))
      

      【讨论】:

      • 函数combine_files 对单个文件进行操作并且不与任何内容组合时,它似乎很奇怪......
      【解决方案7】:
      x <- c(1:10) 
      
      # empty data frame with variables ----
      
      df <- data.frame(x1=character(),
                           y1=character())
      
      for (i in x) {
        a1 <- c(x1 == paste0("The number is ",x[i]),y1 == paste0("This is another number ", x[i]))
        df <- rbind(df,a1)
      }
      
      names(df) <- c("st_column","nd_column")
      View(df)
      

      这可能是一个很好的方法......

      【讨论】:

      • 我没有对这篇文章投票(仅编辑了它的格式),但是从代码的角度和答案的角度来看,它都有一些问题。对于代码,&lt;- 不在函数调用中命名参数(例如c()),而是赋值运算符(命名参数使用=)。从答案的角度来看,在循环中调用rbind 与西蒙的答案基本相同。
      【解决方案8】:

      对我来说,它非常简单。起初,我创建了一个空的data.frame,然后在每次迭代中我添加了一列。这是我的代码:

      df <- data.frame(modelForOneIteration)
      for(i in 1:10){
        model <- # some processing
        df[,i] = model
      }
      

      【讨论】:

        【解决方案9】:

        """通过 Groupby 从唯一的 TF 生成多个 DataFrame"""

                i=0
                dfs_list=[]
                for i in range(i,len(df_CDL)):
                    df = df_CDL[i]
                    print(df,'Only 1 df_CDL')
        
                    dfs= []
                    for _, dataframe in df.groupby('TFs'):
                        print('What is going on here?15',dataframe)
                        dfs.append([dataframe])
                    dfs_list.append([dfs])
        

        #Index 任何你想要的数据框或遍历它们。随便..

               print('Test?10', dfs[1], 'Test?20')
               print('What is going on here? 1', dfs_list[5], 'What is 
               going on here again? 2')
        

        【讨论】:

          猜你喜欢
          • 2016-12-19
          • 2017-10-21
          • 2015-04-05
          • 2019-02-22
          • 2019-10-15
          • 2023-03-23
          • 1970-01-01
          • 2016-01-31
          相关资源
          最近更新 更多