[英]Efficiently create data.frames for a changing number of input csv files with identical 'tidy' format and size
我无法弄清楚如何:
rbind
或其他方式有效地创建data.frame
编译csv派生的data.frame
,其编号因不同的项目而异。 或类似地: data.frame
一个csv衍生“基准情景”的值和那些的基于CSV-替代方案的其余部分之间的差异的。 csvs是水文模型输出的时间序列,已经是长,“整洁”的格式,它们在格式,大小和顺序上都是相同的 - 对于不同的项目,它们只有不同的数量。 总有至少两个,一个基线和一个替代,但通常有不少。 例如,项目A可能有四个csvs / scenario,而Project B可能有三十个csvs / scenario。
我希望有一个代码模板可以有效地容纳具有任意数量场景的项目。 如果没有一种有效的方法,我需要添加或删除相当多的行以匹配我每天的场景数量,所以这是一个我想避免的耗时步骤。 创建df
和df_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个替代品),我试图编写函数和循环,分配scen2
和scen3
... scen28
,以及scen2diff
, scen3diff
。 .. scen28diff
等,动态变量,但我失败了。 所以,我正在寻找一种有效的方法,当应用于具有任意数量场景的项目时,不需要太多修改。 我只是想以一种干净的方式为用户创建df
和df_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.