简体   繁体   English

在循环中创建 R 数据帧

[英]Creating R data frames within a loop

I have some code which uses a loop to calculate a water balance for catchments (watersheds) for 8 catchments.我有一些代码使用循环来计算 8 个集水区的集水区(分水岭)的水平衡。 I would like the loop to write it's output to a dataframe in R but the only way I can work out how to do this is to write it to csv (inside the loop), then outside of the loop read each of the csv files separately. I would like the loop to write it's output to a dataframe in R but the only way I can work out how to do this is to write it to csv (inside the loop), then outside of the loop read each of the csv files separately . I feel as though there could be a better way to do this - any ideas?我觉得好像有更好的方法来做到这一点 - 有什么想法吗?

This is my code: (note it is part of a shiny app, hence my desire to avoid reading and writing csv files)这是我的代码:(注意它是 shiny 应用程序的一部分,因此我希望避免读写 csv 文件)

WB_catchments <- function (){  
      for (i in 1:8){
        file_name <- gsub(" ", "", paste("outputs\\", Lake_name[i], "_catchment_water_balance.csv"))
        p <- pts()[[i]]
        
        Rain_in_WB <- RAIN() %>% filter(Grid_id %in% p)
        Rain_in_WB$Grid_id <- NULL  #remove Grid_id column
        Rain_in_WB <- colSums(Rain_in_WB, na.rm = TRUE)  # sum over catchment
        
        AET_out_WB <- AET() %>% filter(Grid_id %in% p)
        AET_out_WB$Grid_id <- NULL #remove Grid_id column
        AET_out_WB <- -1*colSums(AET_out_WB, na.rm = TRUE) # sum over catchment and multiply by -1 as is an output
        
        Evap_WB <- -1*EVAP_lakes[i,]
        
        SW_in_WB <- SW_in_C[i,]
        GW_in_WB <- GW_in_C[i,]
        
        SW_out_WB <- -1*SW_out_C[i,]
        GW_out_WB <- -1*GW_out_C[i,]
        
        stor_WB <- STOR[i,]
        
        out_catchment <- -1*outside[i,]
        
        bal <- as.data.frame(cbind(WY, Rain_in_WB, SW_in_WB, GW_in_WB, AET_out_WB, Evap_WB, SW_out_WB, GW_out_WB, stor_WB, out_catchment))
        bal <- mutate(bal, "res" = rowSums(bal[,2:10], na.rm = TRUE))     
        colnames(bal) <- c("WaterYear", "Rain", "SW_in", "GW_in", "AET", "Evap", "SW_out", "GW_out", "Storage", "Water_out_of_Greater_Tarawera_Catchments", "Residual")
        
        
        
        write.csv(bal, file_name)
      }
    }

WB_catchments()
    Okareka_WB_C <- read.csv("outputs\\Okareka_catchment_water_balance.csv")
    Okaro_WB_C <- read.csv("outputs\\Okaro_catchment_water_balance.csv")
    Okataina_WB_C <- read.csv("outputs\\Okataina_catchment_water_balance.csv")
    Rerewhakaaitu_WB_C <- read.csv("outputs\\Rerewhakaaitu_catchment_water_balance.csv")
    Rotokakahi_WB_C <- read.csv("outputs\\Rotokakahi_catchment_water_balance.csv")
    Rotomahana_WB_C <- read.csv("outputs\\Rotomahana_catchment_water_balance.csv")
    Tarawera_WB_C <- read.csv("outputs\\Tarawera_catchment_water_balance.csv")
    Tikitapu_WB_C <- read.csv("outputs\\Tikitapu_catchment_water_balance.csv")

Instead of posting some very special code snippets, it is in most cases to post a toy example.在大多数情况下,与其发布一些非常特殊的代码片段,不如发布一个玩具示例。 Here an artificial example how to fill a data frame in a loop.这是一个人工示例,如何在循环中填充数据框。 As R is a vectorized language, it is often to avoid a loop at all.由于 R 是一种矢量化语言,因此通常完全避免循环。 Compare the two cases below:比较以下两种情况:

## number of cases
N <- 10

### looped version =====
df <- data.frame(
  rain=rep(0, N),
  evap=rep(0, N)
)

for (i in 1:N) {
  # instead of runif, do your calculations
  # ...
  rain <- runif(1, min=0, max=10)
  evap <- runif(1, min=1, max=5)
  df[i, ] <- c(rain, evap)
}

df

### vectorized version =====
rain <- runif(N, min=0, max=10)
evap <- runif(N, min=1, max=5)

df2 <- data.frame(
  rain=rain,
  evap=evap
)

df2

If your calculations return more than one row in each iteration and you don't know beforehand how many, grow the data frame like this:如果您的计算在每次迭代中返回多于一行并且您事先不知道有多少,请像这样增长数据框:

## empty data frame
df3 <- data.frame(
  rain=NULL,
  evap=NULL
)

for (i in 1:N) {
  # instead of runif, do your calculations
  # ...
  rain <- runif(7, min=0, max=10)
  evap <- runif(7, min=1, max=5)
  df3 <- rbind(df3, cbind(rain, evap))
}

df3

Edit: Create several data frames (as elements of a list)编辑:创建几个数据框(作为列表的元素)

If separate data frames are needed, it is a good idea to put them together in a list.如果需要单独的数据框,最好将它们放在一个列表中。 INstead of a loop,l we can use lapply :我们可以使用lapply

create_df <- function(i) {
  # optionally: do something with i, e.g. select file name
  rain <- runif(7, min=0, max=10)
  evap <- runif(7, min=1, max=5)
  df <- data.frame(
    rain=rain,
    evap=evap
  )
}

## lapply does the "loop" and returns a list of data frames
df_list <- lapply(1:8, create_df)

df_list[[7]] # returns 7th data frame

Another way I got this working was by using assign(file_name, bal, envir =.GlobalEnv) instead of write.csv(bal, file_name) in the last line of my function我得到这个工作的另一种方法是在我的 function 的最后一行中使用assign(file_name, bal, envir =.GlobalEnv)而不是write.csv(bal, file_name)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM