在 R 中使用 ... 编写函数并扩展到 dplyr::recode 中的命名替换
Writing a function using ... and expanding to named replacements in dplyr::recode in R
我发现自己经常进行相同的数据转换,唯一的区别是名称和列数。例如,
library(tidyverse)
test.data <- tribble(
~id.num, ~site, ~value1, ~value2, ~value3,
"10-01", "log", 1.5, 2.5, 3.5,
"10-02", "branch", 0.7, 2, 3.24,
"10-03", "branch", 3.2, 2.3, 7.7
)
test.data <-
gather(
test.data,
key = "test.code",
value = "values",
"value1",
"value2",
"value3"
) %>%
mutate(
test.code.order = recode(
test.code,
"value1" = 1,
"value2" = 2,
"value3" = 3
)
) %>%
arrange(id.num, test.code.order)
在我的实际数据中,通常会收集 16-30 列而不是 3 列。目前我最终为 mutate 创建命名对的做法是
c(
"value1",
"value2",
"value3"
) -> columns
cat(paste0('"', columns, '" = ', 1:length(columns)), sep = ",\n")
并将输出复制并粘贴到代码中。
但是,我希望能够创建一个函数,使得
test.data <- wide.to.long(test.data, "value1", "value2", "value3")
给我的结果与上面的 gather
、mutate
、arrange
管道相同。我不确定如何将字符串从 "value1"
扩展到 "value1" = 1
等
我想它看起来像这样,
wide.to.long <- function(df, key = "test.code", value = "values", id = "id.num", ...) {
test.order.numbers <- missing.code.here
gather(df, key, value, ...) %>%
mutate(test.code.order = recode(key, test.order.numbers)) %>%
arrange(id, test.code.order)
}
但当然 cat
不起作用,我尝试过的任何版本的 paste
都会给我错误:"Argument 2 must be named, not unnamed"
。我错过了什么?
wide.to.long <- function(df, ..., key = "test.code",
value = "values", id = "id.num") {
v <- quos(...)
key <- rlang::sym(key)
key <- enquo(key)
id <- rlang::sym(id)
id <- enquo(id)
test.order.numbers <- setNames(seq_along(v), sapply(v, quo_name))
gather(df, !! key, !! value, !!! v) %>%
mutate(test.code.order = recode(!! key, !!! test.order.numbers)) %>%
arrange(!! id, test.code.order)
}
wide.to.long(test.data, "value1", "value2", "value3")
# # A tibble: 9 x 5
# id.num site test.code values test.code.order
# <chr> <chr> <chr> <dbl> <int>
# 1 10-01 log value1 1.50 1
# 2 10-01 log value2 2.50 2
# 3 10-01 log value3 3.50 3
# 4 10-02 branch value1 0.70 1
# 5 10-02 branch value2 2.00 2
# 6 10-02 branch value3 3.24 3
# 7 10-03 branch value1 3.20 1
# 8 10-03 branch value2 2.30 2
# 9 10-03 branch value3 7.70 3
或者你可以直接传递裸变量名:wide.to.long(test.data, value1, value2, value3)
.
我发现自己经常进行相同的数据转换,唯一的区别是名称和列数。例如,
library(tidyverse)
test.data <- tribble(
~id.num, ~site, ~value1, ~value2, ~value3,
"10-01", "log", 1.5, 2.5, 3.5,
"10-02", "branch", 0.7, 2, 3.24,
"10-03", "branch", 3.2, 2.3, 7.7
)
test.data <-
gather(
test.data,
key = "test.code",
value = "values",
"value1",
"value2",
"value3"
) %>%
mutate(
test.code.order = recode(
test.code,
"value1" = 1,
"value2" = 2,
"value3" = 3
)
) %>%
arrange(id.num, test.code.order)
在我的实际数据中,通常会收集 16-30 列而不是 3 列。目前我最终为 mutate 创建命名对的做法是
c(
"value1",
"value2",
"value3"
) -> columns
cat(paste0('"', columns, '" = ', 1:length(columns)), sep = ",\n")
并将输出复制并粘贴到代码中。
但是,我希望能够创建一个函数,使得
test.data <- wide.to.long(test.data, "value1", "value2", "value3")
给我的结果与上面的 gather
、mutate
、arrange
管道相同。我不确定如何将字符串从 "value1"
扩展到 "value1" = 1
等
我想它看起来像这样,
wide.to.long <- function(df, key = "test.code", value = "values", id = "id.num", ...) {
test.order.numbers <- missing.code.here
gather(df, key, value, ...) %>%
mutate(test.code.order = recode(key, test.order.numbers)) %>%
arrange(id, test.code.order)
}
但当然 cat
不起作用,我尝试过的任何版本的 paste
都会给我错误:"Argument 2 must be named, not unnamed"
。我错过了什么?
wide.to.long <- function(df, ..., key = "test.code",
value = "values", id = "id.num") {
v <- quos(...)
key <- rlang::sym(key)
key <- enquo(key)
id <- rlang::sym(id)
id <- enquo(id)
test.order.numbers <- setNames(seq_along(v), sapply(v, quo_name))
gather(df, !! key, !! value, !!! v) %>%
mutate(test.code.order = recode(!! key, !!! test.order.numbers)) %>%
arrange(!! id, test.code.order)
}
wide.to.long(test.data, "value1", "value2", "value3")
# # A tibble: 9 x 5
# id.num site test.code values test.code.order
# <chr> <chr> <chr> <dbl> <int>
# 1 10-01 log value1 1.50 1
# 2 10-01 log value2 2.50 2
# 3 10-01 log value3 3.50 3
# 4 10-02 branch value1 0.70 1
# 5 10-02 branch value2 2.00 2
# 6 10-02 branch value3 3.24 3
# 7 10-03 branch value1 3.20 1
# 8 10-03 branch value2 2.30 2
# 9 10-03 branch value3 7.70 3
或者你可以直接传递裸变量名:wide.to.long(test.data, value1, value2, value3)
.