Использовать параметр в кавычках в качестве имени переменной для создания экземпляра? - PullRequest
2 голосов
/ 09 апреля 2020

Я написал большую часть своего вопроса в виде комментариев в моем представлении. Я пытаюсь улучшить семантику моего кода и ответить на конкретный вопрос c относительно переменных в кавычках в качестве параметров функций, подобных замыканию.

library(tidyverse)

# A df of file-paths split so all basenames
# are in the same column, but parent-dirs
# are spread across an abritary number of columns
# and filled with NA's.
dat <- tibble(
  ref01 = rep("analysis", 5),
  ref02 = c(NA, NA, "next", "next", "next"),
  ref03 = c(NA, NA, NA, NA, "last"),
  target = c("analysis.test1", "analysis.test2",
             "next.test3", "next.test4",
             "last.test5")
)

# For example this reprex df shows file-paths
# from a file-tree that looks like:
# analysis
# ├── next
# │   ├── last
# │   │   └── last.test5
# │   ├── next.test3
# │   └── next.test4
# ├── analysis.test1
# └── analysis.test2
dat
#> # A tibble: 5 x 4
#>   ref01    ref02 ref03 target        
#>   <chr>    <chr> <chr> <chr>         
#> 1 analysis <NA>  <NA>  analysis.test1
#> 2 analysis <NA>  <NA>  analysis.test2
#> 3 analysis next  <NA>  next.test3    
#> 4 analysis next  <NA>  next.test4    
#> 5 analysis next  last  last.test5

Эта функция очищает «целевые» тестовые базовые имена. Всем именам тестов предшествуют его имя «parent-dir» и точка. (например, 'last.test5')

Эта функция принимает столбец "target" и произвольное количество столбцов parent-dir. Он переворачивает список parent-dirs и находит первое не-NA значение. Затем он сопоставляет это значение с целевым значением и удаляет его.

Мой вопрос заключается в этой функции:

  1. Есть ли более semanti c способ построения этой функции, чтобы это может быть выражено внутри функции `mutate () '?
  2. В настоящее время функция replace_pattern() основана на том факте, что столбец .key называется« target »и жестко закодирован как входной параметр.

    Это связано с тем, что pmap работает, беря аргументы p-num из списка и сопоставляя аргументы с именами.

    Поскольку я хочу, чтобы эта функция работала для сколь угодно глубоких путей к файлам Мне нужно найти способ обработки различных .key имен.

    Есть ли способ заключить в кавычки .key переменную, чтобы это было имя первого параметра функции replace_pattern()?

trim_target <- function(.tbl, .key, ...){
  key <- tidyselect::eval_select(expr(c(!!enquo(.key))), .tbl)
  loc <- tidyselect::eval_select(expr(c(...)), .tbl)

  # First param has to be "target" since that's the name
  # of the .key column.
  replace_pattern <- function(target, ...){
    args <- c(...)
    pattern <- args %>% 
      rev() %>% 
      discard(is.na) %>% 
      first() %>% 
      paste0("\\.")

    unlist(str_remove(target, pattern))
  }

  pmap(.tbl[,c(key, loc)], replace_pattern) %>% 
    unlist()
}

Ожидаемый результат: работает должным образом, но не масштабируется. Также, что касается вопроса 01, я должен передать dat в вызов функции mutate(); что я не вижу, как правило, сделано.

dat %>% 
  mutate(target = trim_target(dat, target, ref01:ref03))
#> # A tibble: 5 x 4
#>   ref01    ref02 ref03 target
#>   <chr>    <chr> <chr> <chr> 
#> 1 analysis <NA>  <NA>  test1 
#> 2 analysis <NA>  <NA>  test2 
#> 3 analysis next  <NA>  test3 
#> 4 analysis next  <NA>  test4 
#> 5 analysis next  last  test5

Создано в 2020-04-08 пакетом prepx (v0.3.0)

1 Ответ

0 голосов
/ 27 апреля 2020

Ответ на вопрос 1

Когда вы говорите, что обычно не видите, что dat передано mutate(), это потому, что большинству функций обычно не требуется контекст фрейма данных. Например, когда вы видите

mtcars %>% mutate( cyl = sqrt(cyl) )

, функция sqrt() работает напрямую со значениями, переданными ей, без какой-либо заботы о происхождении этих значений. В вашем случае вам нужен контекст фрейма данных, чтобы помочь разрешить выражение ref01:ref03. По этой причине более подходящим шаблоном было бы поместить операцию mutate() в вашей функции и вернуть вместо нее результирующий фрейм данных.

Ответ на вопрос 2

pmap() соответствует только именам аргументов, если вход является именованным списком. Если список не назван, сопоставление выполняется по позиции. Таким образом, вы можете либо 1) отменить имя списка аргументов:

.tbl[,c(key, loc)] %>% as.list() %>% unname %>% pmap_chr(replace_pattern)

или 2), так как вы уже устанавливаете в столбцы [, превратите его в правильный шаблон select и переименуйте выбранный столбец соответственно:

.tbl %>% select( target={{.key}}, ... ) %>% pmap_chr( replace_pattern )

Собираем все вместе

С учетом двух моментов, я бы переписал вашу функцию:

mutate_target <- function(.tbl, .key, ...){

  # No change from the OP
  replace_pattern <- function(target, ...){
    args <- c(...)
    pattern <- args %>%
      rev() %>%
      discard(is.na) %>%
      first() %>%
      paste0("\\.")

    unlist(str_remove(target, pattern))
  }

  result <- .tbl %>% select( target={{.key}}, ... ) %>% pmap_chr( replace_pattern )
  .tbl %>% mutate( {{.key}} := result )
}

Обратите внимание, что я снял ваши откровенные eval_select() звонки. Вы можете передать точки ... непосредственно глаголам dplyr, используя фигурные-кудрявые ({{, что сокращенно для !!enquo) для особых столбцов. Вот как бы вы использовали новую функцию:

dat %>% mutate_target( target, ref01:ref03 )                           # Works
dat %>% rename( abc = target ) %>% mutate_target( abc, ref01:ref03 )   # Also works
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...