多くの試行錯誤と以前の回答との協議 裸の変数または文字列かどうかを検出する方法 自分が必要なことのほとんどは自分で行ったと思います。しかし、私が「解決策」を本番環境に移行する前に、私がいくつかの悪い仮定をしているのか、または問題に愚かに取り組んでいるのかを理解したいと思っています。
次のデータを検討してください。
library(dplyr)
library(purrr)
library(tidyselect)
set.seed(1111)
dat1 <- data.frame(Region = rep(c("r1","r2"), each = 100),
State = rep(c("NY","MA","FL","GA"), each = 10),
Loc = rep(c("a","b","c","d","e","f","g","h"),each = 5),
ID = rep(c(1:10), each = 2),
var1 = rnorm(200),
var2 = rnorm(200),
var3 = rnorm(200),
var4 = rnorm(200),
var5 = rnorm(200))
かなり多くのことを行う関数を書きたいのですが、再現可能な最小限の例から始めます。 tidied
aov
の結果を、単一のケースvar1 ~ State
またはmap2
を使用して一致するリストのペアに対して取得し、1つのリストに "結果"他の "予測子"。私の例とは異なり、使用方法と使用方法が同じになることは決してなく、starts_with
のような簡単な解決策に役立つことはめったにありません。
2つの特定の問題と一般的な質問。
問題#1-エンドユーザー(自分を含む)がそのままの変数名を渡せるようにすることをあきらめたので、後で問題が発生します。上記の参照に従って私のコードのようなものは、それらをキャッチしてユーザーに伝える最も高速で信頼できる方法ですか? (コードにコメントを入れて、どこで話しているかを示します。
問題#2-基本的にはトレイルとエラーによって、後でラベルとして使用するためにテキストを生成することに関する他の問題を解決したと思います。 map2
で関数を使用していないときに多くの解決策が見つかりましたが、これだけがmap2で機能するようです。複雑すぎて、良い選択だとは信じられないようです(ここでも、コードにコメントを付けて、場所を示しています)。
一般的な質問:あいまいなリストである可能性があるため、推奨されるtidyselect::all_of
を追加しました。なぜ、マーカーだけではなく.x
および.y
が呼び出しとして表示されないようにする必要があるのですか?反復のため?
MyFunction <- function(data,
groupvar,
var) {
# Issue #1 is this best way to warn/stop user?
lst <- as.list(match.call())
if (is.symbol(lst$groupvar) || is.symbol(lst$var)) {
stop("Please quote all variables")
}
# Issue #2 I want the group label but if I don't include
# this if logic it errors with " Error: Can't convert a call to a string"
# when I run it with purrr::map2
if (!is.call(groupvar)) {
grouplabel <- rlang::as_name(rlang::enquo(groupvar))
}
data <-
dplyr::select(
.data = data,
var = {{ var }},
groupvar = {{ groupvar }}
)
aov_object <- aov(var ~ groupvar, data = data)
aov_results <- broom::tidy(aov_object) %>%
mutate(term = if_else(term != "Residuals", grouplabel, term))
return(aov_results)
}
# Expected output
MyFunction(data = dat1, groupvar = "State", var = "var1") # works
#> # A tibble: 2 x 6
#> term df sumsq meansq statistic p.value
#> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 State 3 1.75 0.582 0.485 0.693
#> 2 Residuals 196 235. 1.20 NA NA
MyFunction(data = dat1, groupvar = State, var = var1) # warns appropriately
#> Error in MyFunction(data = dat1, groupvar = State, var = var1): Please quote all variables
# Quick test of `map2`
grouping_vars <- names(dat1[,1:3])
names(grouping_vars) <- names(dat1[,1:3])
outcome_vars <- names(dat1[,5:7])
names(outcome_vars) <- names(dat1[,5:7])
names(outcome_vars) <- paste(outcome_vars, "~", grouping_vars)
# get multiple results this is where issue #2 comes in but this is what I want it to look like.
map2(.x = outcome_vars,
.y = grouping_vars,
.f = ~ MyFunction(dat = dat1,
var = tidyselect::all_of(.x),
groupvar = tidyselect::all_of(.y)))
#> $`var1 ~ Region`
#> # A tibble: 2 x 6
#> term df sumsq meansq statistic p.value
#> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 Region 1 0.0512 0.0512 0.0427 0.836
#> 2 Residuals 198 237. 1.20 NA NA
#>
#> $`var2 ~ State`
#> # A tibble: 2 x 6
#> term df sumsq meansq statistic p.value
#> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 State 3 5.05 1.68 2.07 0.106
#> 2 Residuals 196 159. 0.814 NA NA
#>
#> $`var3 ~ Loc`
#> # A tibble: 2 x 6
#> term df sumsq meansq statistic p.value
#> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 Loc 7 5.09 0.727 0.772 0.612
#> 2 Residuals 192 181. 0.943 NA NA
問題#1を解決しました。関数は、変数名が引用符で囲まれているかどうかに関係なく機能します。
MyFunction <- function(data,
groupvar,
var) {
# Issue #1 is this best way to warn/stop user?
lst <- as.list(match.call())
if (is.symbol(lst$groupvar)) {
q <- paste0("groupvar")
varname <- expr('$'(lst,!!q))
gval <- eval_tidy(varname)
groupvarc <- as.character(gval)
}else{groupvarc <- eval_tidy(lst$groupvar)}
if (is.symbol(lst$var)) {
v <- paste0("var")
varnam <- expr('$'(lst,!!v))
vval <- eval_tidy(varnam)
varc <- as.character(vval)
}else{varc <- eval_tidy(lst$var)}
grouplabel <- groupvarc[1]
data <- dplyr::select(.data = data,
var = varc[[1]],
groupvar = groupvarc[[1]] )
aov_object <- aov(var ~ groupvar, data = data)
aov_results <- broom::tidy(aov_object) %>%
mutate(term = if_else(term != "Residuals", grouplabel, term))
return(aov_results)
}
MyFunction(data = dat1, groupvar = "State", var = "var1") # works
MyFunction(data = dat1, groupvar = State, var = var1) # Also works
複数の変数については、それを関数にしてlapply
を循環させる必要があります。また、問題1の同じコードを2回繰り返すことで整理されます。これがあなたの前進に役立つことを願っています。