Как работает mutate_all (.funs = ~. / Sum (x))? - PullRequest
1 голос
/ 18 июня 2020

Я использовал этот код для вычисления относительной численности (ячейка / всего столбца) таблицы, которая у меня была. Я не понимаю, как. и ~ работают функции.

Ответы [ 3 ]

2 голосов
/ 18 июня 2020

Конструкция ~./sum(x) технически представляет собой особый тип объекта R, называемый формулой

class(~./sum(x))
#> [1] "formula"

Однако в функциях tidyverse, таких как mutate_all, эта формула используется и преобразован в лямбда-функцию , которая является анонимной функцией (то есть функцией, которая не имеет имени и записывается на месте как параметр, передаваемый при вызове другой функции).

Внутренне формула преобразуется в функцию с rlang::as_function. Предположим, мы хотим написать функцию, которая просто добавляет два к переменной. В базе R мы могли бы написать

add_two <- function(var){
  return(var + 2)
}

add_two(5)
#> [1] 7

В тидиверсе мы можем использовать формулу как сокращение для этой функции, где . становится сокращением для «переменной, которая была передана в качестве первого аргумента в функция ":

add_two <- rlang::as_function(~ . + 2)

add_two(5)
#> [1] 7

В таких функциях, как mutate_all, формула будет автоматически передаваться через rlang::as_function, поэтому, если бы мы хотели добавить два в каждый столбец в нашем фрейме данных, вместо того, чтобы писать :

mutate_all(.funs= function(var) {return(var + 2);})

мы могли бы написать

mutate_all(.funs=~.+2)

В вашем случае формула ~./sum(x) фактически преобразуется в

function(var) {
  return(var / sum(x))
}

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

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

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

1 голос
/ 18 июня 2020

Предположим, у нас есть этот набор данных:

dataset <- data.frame(a = c(1,2,3,4),
                      b = c(2,3,4,5),
                      c = c(3,4,5,6))

И вы хотите разделить все векторы на общее количество (ie. Для вектора a = 1/10, 2/10, 3/10, 4 / 10). Чтобы избежать записи для всех переменных, вы можете использовать mutate_all, а затем лямбду, используя .funs, который говорит, что создайте функцию, которая делит все значения в каждом векторе, представленном точкой, на сумму всех значений в этом векторе.

dataset %>% mutate_all(.funs = ~./sum(.))

Надеюсь, это поможет.

0 голосов
/ 18 июня 2020

mutate_all применяет функцию в .funs ко всем значениям. Каждое значение (.) Делится на сумму (x), чтобы получить «относительное изобилие», которое, по сути, является долей от общего значения, которая является суммой (x). Вы можете думать о ~ как о "функции от". Итак, вы говорите, что каждая ячейка в фрейме данных является функцией самой себя, деленной на общую сумму.

...