r - 带有 dplyr 管道的 for 循环:正确使用动态和日期变量的问题
问题描述
我有以下代码和示例数据。我有两个问题:
使用 mutate 创建的新变量的名称在相应的数据帧中显示为“New_var”,而不是我在 for 循环中分配给它的字符串(例如,df1_timediff)。
根据对类似问题的回答,我在定义 New_var 变量时和管道内都尝试使用 eval、as.name 和 as.character,但没有成功。当我检查 New_var 的类时,R 告诉我它们是“字符”。我希望 New_var 变量成为当前条目与相应参与者的第一个条目之间的时差变量。我以前使用过类似的代码,但是,New_var 变量似乎与预期的不同。也就是说,返回的时间差不是条目之间的月份。Submitted_i 变量的类是日期格式,所以我很困惑为什么会这样。
代码
names.dfs <- c("df1", "df2", "df3")
for (i in names.dfs){
Submitted_i <- as.name(paste0('Submitted_', i))
New_var <- as.name(paste0(i,'_timediff'))
df_i <- get(i)
df_i <- df_i %>%
arrange(eval(Submitted_i)) %>% # Order by date
group_by(ResultsID) %>%
mutate(New_var = (time_length(difftime(eval(Submitted_i), eval(Submitted_i)[1],"months"))))
assign(paste0(i),df_i)
}
示例数据
df1 <- structure(list(ResultsID = c(1, 2, 3, 4, 2, 4, 1, 5, 3, 3), RepeatNo = c(0L,
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), Submitted_df1 = structure(c(17509,
17509, 17514, 17484, 17929, 17484, 17502, 17528, 17497, 17488
), class = "Date")), row.names = c(NA, 10L), class = "data.frame")
df2 <- structure(list(ResultsID = c(1, 5, 1, 3, 2, 4, 5), RepeatNo = c(0L,
0L, 0L, 0L, 0L, 0L, 0L), Submitted_df2 = structure(c(16856, 16858,
16869, 16861, 16875, 16888, 16891), class = "Date")), row.names = c(NA,
7L), class = "data.frame")
df3 <- structure(list(ResultsID = c(1, 2, 3, 1, 2, 4, 4, 5, 3), RepeatNo = c(0L,
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), Submitted_df3 = structure(c(17913,
17930, 17919, 17931, 17921, 17912, 17916, 17931, 17915), class = "Date")), row.names = c(NA,
-9L), groups = structure(list(.rows = structure(list(1L, 2L,
3L, 4L, 5L, 6L, 7L, 8L, 9L), ptype = integer(0), class = c("vctrs_list_of",
"vctrs_vctr", "list"))), row.names = c(NA, -9L), class = c("tbl_df",
"tbl", "data.frame")), class = c("rowwise_df", "tbl_df", "tbl",
"data.frame"))
解决方案
在我看来,您应该考虑将 data.frames 存储在 data.frames 列表中。如果您需要使用get
--assign
结构,通常有更优雅的方法。
接下来,您可以使用purrr
'map
函数将您的工作流程应用于这些数据帧。在map
函数内部,我建议重命名列以避免卷曲和as.name
结构:
library(dplyr)
library(lubridate)
library(purrr)
# create a named list of data.frames
my_list <- list(df1, df2, df3)
names(my_list) <- c("df1", "df2", "df3")
# apply your workflow
my_result_list <- my_list %>%
imap(~ .x %>%
tibble() %>%
# ungroup() %>%
`names<-`(., sub("_df.*", "", names(.))) %>%
arrange(Submitted) %>%
group_by(ResultsID) %>%
# replace / months(1) by %/% months(1) if you want full months, or use a rounding function
mutate(difftime = interval(first(Submitted), Submitted) / months(1)) %>%
rename_with(function(x) paste0("Submitted_", .y), starts_with("Submitted")) %>%
rename_with(function(x) paste0(.y, "_difftime"), ends_with("difftime")) %>%
ungroup()
)
这将返回一个 data.frames 列表,如下所示:
$df1
# A tibble: 10 x 4
ResultsID RepeatNo Submitted_df1 df1_difftime
<dbl> <int> <date> <dbl>
1 4 0 2017-11-14 0
2 4 0 2017-11-14 0
3 3 0 2017-11-18 0
4 3 0 2017-11-27 0.3
5 1 0 2017-12-02 0
6 1 0 2017-12-09 0.226
7 2 0 2017-12-09 0
8 3 0 2017-12-14 0.867
9 5 0 2017-12-28 0
10 2 0 2019-02-02 13.8
$df2
# A tibble: 7 x 4
ResultsID RepeatNo Submitted_df2 df2_difftime
<dbl> <int> <date> <dbl>
1 1 0 2016-02-25 0
2 5 0 2016-02-27 0
3 3 0 2016-03-01 0
4 1 0 2016-03-09 0.448
5 2 0 2016-03-15 0
6 4 0 2016-03-28 0
7 5 0 2016-03-31 1.13
$df3
# A tibble: 9 x 4
ResultsID RepeatNo Submitted_df3 df3_difftime
<dbl> <int> <date> <dbl>
1 4 0 2019-01-16 0
2 1 0 2019-01-17 0
3 3 0 2019-01-19 0
4 4 0 2019-01-20 0.129
5 3 0 2019-01-23 0.129
6 2 0 2019-01-25 0
7 2 0 2019-02-03 0.290
8 1 0 2019-02-04 0.581
9 5 0 2019-02-04 0
现在您可以像这样使用您的 data.frames:my_result_list[[1]]
返回您的已转换df1
、my_result_list[[2]]
返回df2
等。
推荐阅读
- godot - Godot - 如何让我的块在玩家周围生成 3 x 3 网格
- wordpress - Wordpress - 基于角色的子主题切换
- reactjs - 使用 Styled 组件和 rc-year-calendar 做出反应
- sql - 加入以获取其他表中没有值的项目会给出多个结果
- excel - 动态过滤器一直隐藏我的行 - Excel VBA
- python - 4线程和12线程CPU之间没有显着提升
- java - GSON LinkedHashMap 的泛型类
- sql-server - 在安全谓词中按 SYSTEM_USER() 过滤可避免索引并导致性能下降
- c - 在 minifilter 中获取文件读取访问的进程名称时崩溃
- ios - 为什么 iOS 上的默认 webrtc 视频捕获器方向是 90°?