我的最终目标是这里指定的 json 文件:Trimble Batch Geocoding JSON Spec。我引用了该规范中与地址相关的部分,希望它能澄清我正在尝试做的事情。
如何从
mutate()
内的向量中拼接默认值?
我有一个函数,它接受具有可变列数的数据帧。某些列(由
A_dots
表示)可能是不同的命名字段,并且并不总是存在(例如,来自 Trimble Geocode 链接:使用“Zip”而不是“StreetAddress”),但总会有一个或多个字段,并且我在函数中使用 ...
涵盖了它们。还有一些其他字段(由 B, C, D
表示,可能 出现在数据框中(例如“GeoList”或“Region”),但大多数情况下不会出现,并且可以默认表示函数的 formals()
中定义的值。这是我的 not-working 函数,我知道它不起作用,因为我不知道如何正确调用 mutate()
来拼接默认值 (这确实是我的问题):
library(tidyverse) # solution does not need to be tidyverse
myfun <- function(df,
...,
B = 4,
C = TRUE,
D = "a_default_value"){
vec_field_defaults <- c("B", "C", "D")
vfd_match <- intersect(vec_field_defaults, names(df))
vfd_nomatch <- setdiff(vec_field_defaults, names(df))
if (length(vfd_match) > 0){
df2 <- df[,vfd_match]
if (length(vfd_nomatch) > 0){
df2 <- mutate(df2, !!!vfd_nomatch := !!!vfd_nomatch) # I need help here
}
} else {
df2 <- data.frame(B = rep(B, nrow(df)),
C = rep(C, nrow(df)),
D = rep(D, nrow(df))) # Could this be done better?
}
return(df2)
如果我的意图从上面的函数中不清楚,你只需要阅读这一点。
这是一个起始数据框,我将把它切开以用于下面的示例。
df_baseline <- data.frame(A = c("Address1", "Address2", "Address3"),
B = c(1L, 2L, 3L),
C = c(TRUE, FALSE, FALSE),
D = c("Some", "different", "values."))
> df_baseline
A_dots B C D
1 Address1 1 TRUE Some
2 Address2 2 FALSE different
3 Address3 3 FALSE values.
A_dots
栏:myfun()
应始终删除 A_dots
列(但保留它代表输出的行数!)并填写 B, C, D
的默认值(在提供的数据框中未给出这些值的地方):
df_1 <- select(df_baseline, A_dots)
> myfun(df_1)
B C D
1 4 TRUE a_default_value
2 4 TRUE a_default_value
3 4 TRUE a_default_value
A_dots, B
列:df_2 <- select(df_baseline, A_dots, B)
myfun(df_2) # function breaks, but showing intended output:
B C D
1 1 TRUE a_default_value
2 2 TRUE a_default_value
3 3 TRUE a_default_value
A_dots, B, C
列:df_3 <- select(df_baseline, A_dots, B, C)
myfun(df_3) # function breaks, but showing intended output:
B C D
1 1 TRUE a_default_value
2 2 FALSE a_default_value
3 3 FALSE a_default_value
A_dots, B, C, D
列:df_4 <- select(df_baseline, A_dots, B, C, D)
myfun(df_4) # function breaks, but showing intended output:
B C D
1 1 TRUE Some
2 2 FALSE different
3 3 FALSE values.
我认为我的问题只是如何为缺少的默认值调用
!!!
,但我不确定,如果有任何帮助,我将不胜感激。谢谢你。
这是一个有点 hacky 的版本,它使用 rlang::fn_fmls 来获取默认参数列表并使用它们。
library(dplyr)
myfun <- function(df,
...,
B = 4,
C = TRUE,
D = "a_default_value"){
vec_field_defaults <- c("B", "C", "D")
vfd_match <- intersect(vec_field_defaults, names(df))
vfd_nomatch <- setdiff(vec_field_defaults, names(df))
# get a named list of the default arguments that are missing
list_of_needed_defaults <- rlang::fn_fmls()
list_of_needed_defaults <- list_of_needed_defaults[vfd_nomatch]
if (length(vfd_match) > 0){
df2 <- df[,vfd_match, drop = FALSE]
if (length(vfd_nomatch) > 0){
# create a df with the missing default arguments and add them to the
# remaining df
df_temp <- do.call(bind_cols, list_of_needed_defaults)
df_temp <- df_temp[rep(1, nrow(df)), ]
df2 <- bind_cols(df2, df_temp)
}
} else {
df2 <- data.frame(B = rep(B, nrow(df)),
C = rep(C, nrow(df)),
D = rep(D, nrow(df)))
}
return(df2)
}
df_baseline <- data.frame(A_dots = c("Address1", "Address2", "Address3"),
B = c(1L, 2L, 3L),
C = c(TRUE, FALSE, FALSE),
D = c("Some", "different", "values."))
df_2 <- select(df_baseline, A_dots, B)
myfun(df_2)
#> B C D
#> 1 1 TRUE a_default_value
#> 2 2 TRUE a_default_value
#> 3 3 TRUE a_default_value
由 reprex 包于 2023 年 9 月 1 日创建(v1.0.0)
我们可以使用命名列表在
mutate
中创建新列。创建此列表的一种方法是在列名称的命名向量上使用 lapply
并使用参数中的默认值:get
其中 lapply(vec_field_defaults2, \(x) rep(get(x), nrow(df)))
是
vec_field_defaults2
。或者,我们可以使用 setNames(vec_field_defaults, nm = vec_field_defaults)
,它会自动以其自身命名输入向量。这是完整的代码。
purrr::set_names(vec_field_defaults)