Использование тильды (~) и точки (.) В R - PullRequest
0 голосов
/ 20 июня 2020

Я перебираю цикл с помощью tidyverse и purrr, используя книгу Hadley R4DS, и меня немного смущает точное использование символа тильды ~ и символа периода. map (), вместо того, чтобы записывать function (), похоже, вы можете использовать вместо него символ тильды ~.

Это относится только к циклам for?

так, как показано ниже ...

models <- mtcars %>% 
  split(.$cyl) %>% 
  map(~lm(mpg ~ wt, data = .))

Кроме того, период, который мне было сказано, можно использовать «для ссылки на текущий элемент списка» . Но я не понимаю, что это значит. Означает ли это, что только в цикле точка означает, что он относится к элементу в списке, который выполняется в цикле? Чем он отличается от трубопровода? Когда вы передаете по конвейеру, вы передаете результат одной строки в следующую строку кода.

Итак, в приведенном выше случае mtcars передается на вторую строку с помощью split (), но используется точка. Почему?

Приведенный ниже случай резюмирует мою путаницу:

x <- c(1:10)

detect(x, ~.x > 5)

используя функцию обнаружения, которая находит первое совпадение, я думал, что могу просто использовать

detect(x, x >5)

но я получаю сообщение об ошибке, что x> 5 не является функцией. Итак, я добавляю тильду

detect(x, ~ x > 5)

и получаю сообщение об ошибке, в котором говорится, что он ожидает одного ИСТИНА или ЛОЖЬ, а не 10. Итак, если вы добавите точку

detect(x, ~.x >5) 

, он внезапно будет работать как цикл . Итак, каково отношение / использование ~ и. вот и как. по сравнению с простым трубопроводом?

1 Ответ

4 голосов
/ 20 июня 2020

Этот итог известен как tidyverse нестандартная оценка (NSE). Вероятно, вы узнали, что ~ также используется в формулах , чтобы указать, что левая часть зависит от правой.

В tidyverse NSE, ~ указывает function(...). Таким образом, эти два выражения эквивалентны.

x %>% detect(function(...) ..1 > 5)
#[1] 6

x %>% detect(~.x > 5)
#[1] 6

~ автоматически присваивает каждому аргументу функции .; .x, .y; и специальные символы ..1, ..2 ..3. Обратите внимание, что только первый аргумент становится ..

map2(1, 2, function(x,y) x + y)
#[[1]]
#[1] 3

map2(1, 2, ~.x + .y)
#[[1]]
#[1] 3

map2(1, 2, ~..1 + ..2)
#[[1]]
#[1] 3

map2(1, 2, ~. + ..2)
#[[1]]
#[1] 3

map2(1, 2, ~. + .[2])
#[[1]]
#[1] NA

Это автоматическое c присваивание может быть очень полезным, когда есть много переменных.

mtcars %>% pmap_dbl(~ ..1/..4)
# [1] 0.19090909 0.19090909 0.24516129 0.19454545 0.10685714 0.17238095 0.05836735 0.39354839 0.24000000 0.15609756
#[11] 0.14471545 0.09111111 0.09611111 0.08444444 0.05073171 0.04837209 0.06391304 0.49090909 0.58461538 0.52153846
#[21] 0.22164948 0.10333333 0.10133333 0.05428571 0.10971429 0.41363636 0.28571429 0.26902655 0.05984848 0.11257143
#[31] 0.04477612 0.19633028

Но в дополнение ко всем из отмеченных выше специальных символов аргументы также присваиваются .... Как и все R, ... является своего рода именованным списком аргументов, поэтому вы можете использовать его вместе с with:

mtcars %>% pmap_dbl(~ with(list(...), mpg/hp))
# [1] 0.19090909 0.19090909 0.24516129 0.19454545 0.10685714 0.17238095 0.05836735 0.39354839 0.24000000 0.15609756
#[11] 0.14471545 0.09111111 0.09611111 0.08444444 0.05073171 0.04837209 0.06391304 0.49090909 0.58461538 0.52153846
#[21] 0.22164948 0.10333333 0.10133333 0.05428571 0.10971429 0.41363636 0.28571429 0.26902655 0.05984848 0.11257143
#[31] 0.04477612 0.19633028

Другой способ подумать о том, почему это работает, - это потому, что data.frame - это просто list с некоторыми именами строк:

a <- list(a = c(1,2), b = c("A","B"))
a
#$a
#[1] 1 2
#$b
#[1] "A" "B"
attr(a,"row.names") <- as.character(c(1,2))
class(a) <- "data.frame"
a
#  a b
#1 1 A
#2 2 B
...