[英]Pass column names into a function using apply or map
我想對同一個 dataframe 應用多個函數。但是,我無法成功地將列名作為參數傳遞給purrr::imap
。 我不斷收到以下錯誤:
UseMethod(“select”)中的錯誤:“select”沒有適用的方法應用於 class“字符”的 object
我已經嘗試了很多組合來進行評估(例如,使用!!!
、 [[
、 enquo
、 sys.lang
)。 當我將 function(例如check_1
)直接應用於 dataframe 時, select
工作正常。 但是,當我嘗試使用imap
和exec
將列名作為參數傳遞時,它不起作用。列名的格式是問題的一部分(例如1.1.
),但我嘗試了引號和單引號等。
這是上一篇文章的后續,但該文章和解決方案側重於將多個函數應用於各個列。 現在,我需要應用多個函數,其中使用了 dataframe 中的多個列; 因此,需要在 function 中指定列名。
最小的例子
數據
df <- structure(
list(
`1.1.` = c("Andrew", "Max", "Sylvia", NA, "1",
NA, NA, "Jason"),
`1.2.` = c(1, 2, 2, NA, 4, 5, 3, NA),
`1.2.1.` = c(
"cool", "amazing", "wonderful", "okay",
NA, NA, "chocolate", "fine"
)
),
class = "data.frame",
row.names = c(NA, -8L)
)
我試過的
library(purrr)
library(dplyr)
check_1 <- function(x, col1, col2) {
x %>%
dplyr::select(col1, col2) %>%
dplyr::mutate(row.index = row_number()) %>%
dplyr::filter(col1 == "Jason" & is.na(col2) == TRUE) %>%
dplyr::select(row.index) %>%
unlist() %>%
as.vector()
}
check_2 <- function(x, col1, col2) {
index <- x %>%
dplyr::select(col1, col2) %>%
dplyr::mutate(row.index = row_number()) %>%
dplyr::filter(col1 >= 3 & col1 <= 5 & is.na(col2) == TRUE) %>%
dplyr::select(row.index) %>%
unlist() %>%
as.vector()
return(index)
}
checks <-
list("df" = list(fn = check_1, pars = list(col1 = "1.1.", col2 = "1.2.")),
"df" = list(fn = check_2, pars = list(col1 = "1.2.", col2 = "1.2.1.")))
results <-
purrr::imap(checks, ~ exec(.x$fn, x = .y,!!!.x$pars))
預計 Output
> results
$df
[1] 8
$df
[1] 5 6
除了“類字符”錯誤之外,當我嘗試單獨測試check_2
function 時,我還遇到了一個額外的錯誤,它沒有返回預期值。
[1] 1.2. 1.2.1. row.index
<0 rows> (or 0-length row.names)
我看過許多其他類似的 SO 帖子(例如, 這個),但沒有一個能為我解決這個問題。
第一個問題是您傳遞了 dataframe 的名稱,而不是 dataframe 本身。 這就是為什么在嘗試從字符串中select
時出現第一個錯誤的原因。 要解決此問題,請將 dataframe 添加到您循環訪問的列表中。
第二個問題是,當您將列名作為字符串傳遞時,您必須告訴dplyr
這些字符引用數據中的列。 這可以通過例如使用.data
代詞來實現。
最后,您可以簡單地使用dplyr::pull
代替select + unlist + as.vector
:
library(purrr)
library(dplyr)
check_1 <- function(x, col1, col2) {
x %>%
dplyr::select(all_of(c(col1, col2))) %>%
dplyr::mutate(row.index = row_number()) %>%
dplyr::filter(.data[[col1]] == "Jason" & is.na(.data[[col2]]) == TRUE) %>%
dplyr::pull(row.index)
}
check_2 <- function(x, col1, col2) {
x %>%
dplyr::select(all_of(c(col1, col2))) %>%
dplyr::mutate(row.index = row_number()) %>%
dplyr::filter(.data[[col1]] >= 3 & .data[[col1]] <= 5 & is.na(.data[[col2]]) == TRUE) %>%
dplyr::pull(row.index)
}
checks <-
list(df = list(df = df, fn = check_1, pars = list(col1 = "1.1.", col2 = "1.2.")),
df = list(df = df, fn = check_2, pars = list(col1 = "1.2.", col2 = "1.2.1.")))
purrr::map(checks, ~ exec(.x$fn, x = .x$df, !!!.x$pars))
#> $df
#> [1] 8
#>
#> $df
#> [1] 5 6
使用 select({{col1}},{{col2}}) 這最有可能幫助你
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.