繁体   English   中英

有效地为具有相同“整洁”格式和大小的输入csv文件的数量创建data.frames

[英]Efficiently create data.frames for a changing number of input csv files with identical 'tidy' format and size

我无法弄清楚如何:

  1. 使用rbind或其他方式有效地创建data.frame编译csv派生的data.frame ,其编号因不同的项目而异。 或类似地:
  2. 高效地创建一个data.frame一个csv衍生“基准情景”的值和那些的基于CSV-替代方案的其余部分之间的差异的。

csvs是水文模型输出的时间序列,已经是长,“整洁”的格式,它们在格式,大小和顺序上都是相同的 - 对于不同的项目,它们只有不同的数量。 总有至少两个,一个基线和一个替代,但通常有不少。 例如,项目A可能有四个csvs / scenario,而Project B可能有三十个csvs / scenario。

我希望有一个代码模板可以有效地容纳具有任意数量场景的项目。 如果没有一种有效的方法,我需要添加或删除相当多的行以匹配我每天的场景数量,所以这是一个我想避免的耗时步骤。 创建dfdf_diff后,两者都用于以后的摘要和绘图。

我会手动输入场景的名称,因为它们总是不同,例如:

library(dplyr)
scenarios <- c("baseline", "alt1", "alt1b", "no dam")

length(scenarios)将始终与给定项目的CSV数相匹配。

读入csvs(每个方案一个csv)并保持不变,以便以后单独处理:

#In my case these csv#s are from a separate file's list of csvs,
#eg csv1 <- read.csv("baseline.csv")
#   csv2 <- read.csv("alt1.csv"), etc - all tidy monthly timeseries of many variables

#For reproducibility, simplyfying:

csv1 <- data.frame("variable" = "x", "value" = 13)  #baseline scenario                                                    
csv2 <- data.frame("variable" = "x", "value" = 5)   #"alternative 1"
csv3 <- data.frame("variable" = "x", "value" = 109) #"alternative 1b"
csv4 <- data.frame("variable" = "x", "value" = 11)  #"dam removal"
#csv5 <- data.frame("variable" = "x", "value" = 2.5) #"100 extra flow for salmon sep-dec" 
#...
#csv30 <- data.frame("variable" = "x", "value" = 41) #"alternative H3" 

复制csv并将数据连接到方案:

baseline  <- csv1 %>% mutate(scenario = as.factor(paste0(scenarios[1])))
scen2     <- csv2 %>% mutate(scenario = as.factor(paste0(scenarios[2])))
scen3     <- csv3 %>% mutate(scenario = as.factor(paste0(scenarios[3])))
scen4     <- csv4 %>% mutate(scenario = as.factor(paste0(scenarios[4])))  

df <- rbind(baseline, scen2, scen3, scen4)   #data.frame #1 I'm looking for.
#eg, if csv1-csv30 were included, how to compile in df efficiently, w/o needing the "scen" lines?

在此输入图像描述

在这种情况df$scenario有4种情况,所以df$scenario有4个级别。 来到这里

现在为第二个“差异” data.frame

bslnevals <-  baseline  %>% select(value)
scen2vals <-  scen2     %>% select(value)
scen3vals <-  scen3     %>% select(value)
scen4vals <-  scen4     %>% select(value)

scen2diff  <- (scen2vals -  bslnevals)  %>% transmute(value_diff = value, 
              scenario_diff = as.factor(paste0(scenarios[2], " - baseline"))) %>% 
              data.frame(scen2)  %>% select(-value, -scenario)
scen3diff  <- (scen3vals -  bslnevals)  %>% transmute(value_diff = value, 
              scenario_diff = as.factor(paste0(scenarios[3], " - baseline"))) %>% 
              data.frame(scen3) %>% select(-value, -scenario)
scen4diff  <- (scen4vals -  bslnevals)  %>% transmute(value_diff = value, 
              scenario_diff = as.factor(paste0(scenarios[4], " - baseline"))) %>% 
              data.frame(scen4) %>% select(-value, -scenario)

df_diff <- rbind(scen2diff, scen3diff, scen4diff) #data.frame #2 I'm looking for.
#same as above, if csv1 - csv30 were included, how to compile in df_diff efficiently, w/o
#needing the  "scen#vals" and "scen#diff" lines?

在此输入图像描述

rm(baseline, scen2, scen3, scen4) #declutter - now unneeded (but csv1, csv2, etc orig csv#s needed later)
rm(bslnevals, scen2vals, scen3vals, scen4vals) #unneeded
rm(scen2diff, scen3diff, scen4diff) #unneeded

有4个场景,与基线有3个不同,因此df_diff$scenario有3个等级。

所以,如果我有4个csvs(1个基线,3个替代品)或30个CSVs(1个基线,29个替代品),我试图编写函数和循环,分配scen2scen3 ... scen28 ,以及scen2diffscen3diff 。 .. scen28diff等,动态变量,但我失败了。 所以,我正在寻找一种有效的方法,当应用于具有任意数量场景的项目时,不需要太多修改。 我只是想以一种干净的方式为用户创建dfdf_diff ,但是对于给定的项目,碰巧会给我或许多场景(即csvs)。

任何帮助是极大的赞赏。

我无法测试你的情况,但这可能是重构你的代码的一个很好的起点。 我使用case_when生成规则以将CSV文件的名称映射到场景。 我从每个场景中的值中减去基线值。

library(dplyr)
library(readr)
library(purrr)
library(tidyr)

baseline_df <- read_csv("baseline.csv") %>% 
  mutate(id = row_number())

# list all csv files (in current directory), then read them all, and row-bind them.
# use case_when to apply rules to change filenames to "scenarios" (grepl to check presence of string)
# join with baseline df (by scenario row number) for easy subtracting.
# calculate differences values.
# remove baseline-baseline rows (diff is 0)

diff_df <- list.files(path = getwd(), pattern = "*.csv", full.names = TRUE) %>% 
  tibble(filename = .) %>%
  mutate(data = map(filename, read_csv)) %>%
  unnest() %>% 
  mutate(scenario = case_when(
    grepl("baseline", filename) ~ "baseline",
    grepl("alternative1", filename) ~ "alt1",
    grepl("alternative2", filename) ~ "alt2",
    grepl("dam_removal", filename) ~ "no dam",
    TRUE ~ "other"
  )) %>% 
  group_by(scenario) %>% 
  mutate(id = row_number()) %>% 
  left_join(baseline_df, by = "id", suffix = c("_new", "_baseline")) %>% 
  mutate(Value_diff = Value_new - Value_baseline) %>% 
  filter(scenario != "baseline")

暂无
暂无

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

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