Неожиданное поведение с n_distinct внутри трубы - PullRequest
1 голос
/ 14 января 2020

Я пытаюсь использовать функцию n_distinct из dplyr внутри канала в функции и обнаружил, что она чувствительна к моему выбору синтаксиса так, как я этого не ожидал. Вот игрушечный пример.

# preliminaries
library(tidyverse)
set.seed(123)
X <- data.frame(a1 = rnorm(10), a2 = rnorm(10), b = rep(LETTERS[1:5], times = 2), stringsAsFactors = FALSE)
print(X)
            a1         a2 b
1  -0.56047565  1.2240818 A
2  -0.23017749  0.3598138 B
3   1.55870831  0.4007715 C
4   0.07050839  0.1106827 D
5   0.12928774 -0.5558411 E
6   1.71506499  1.7869131 A
7   0.46091621  0.4978505 B
8  -1.26506123 -1.9666172 C
9  -0.68685285  0.7013559 D
10 -0.44566197 -0.4727914 E

Хорошо, теперь давайте скажем, что я хочу перебрать функцию по именам выбранных столбцов в этом фрейме данных (утешите меня). Здесь я собираюсь использовать значения в выбранном столбце, чтобы отфильтровать исходный набор данных, подсчитать количество оставшихся уникальных идентификаторов и вернуть результаты в виде однорядной таблицы, которую я затем свяжу с новой таблицей. Когда я создаю новый тиббл внутри функции и затем применяю n_distinct к выбранному столбцу в этом тиббле в качестве собственного шага, я получаю ожидаемые результаты от n_distinct, 5 и 4.

bind_rows(map(str_subset(colnames(X), "a"), function(i) {

  subdf <- filter(X, !!sym(i) > 0)

  value <- n_distinct(subdf$b)

  tibble(y = i, n_uniq = value)

}))

# A tibble: 2 x 2
  y     n_uniq
  <chr>  <int>
1 a1         5
2 a2         4

Если я помещу n_distinct в трубу и использую . для ссылки на отфильтрованный тибл, однако, код выполнится, но я получу другой и неправильный результат.

bind_rows(map(str_subset(colnames(X), "a"), function(i) {

  value <- filter(X, !!sym(i) > 0) %>% n_distinct(.$b)

  tibble(y = i, n_uniq = value)

}))

# A tibble: 2 x 2
  y     n_uniq
  <chr>  <int>
1 a1         5
2 a2         7

Что с этим? Я неправильно понимаю использование . внутри трубы? Что-то напугано с n_distinct?

Ответы [ 2 ]

2 голосов
/ 14 января 2020

n_distinct принимает несколько аргументов, и здесь вы фактически передаете в качестве аргументов столбец tibble и столбец b, так как левая часть канала передается по умолчанию. Вот некоторые другие способы получения ожидаемого результата:

filter(X, !!sym(i) > 0) %>% 
  {n_distinct(.$b)}

filter(X, !!sym(i) > 0) %>% 
  with(n_distinct(b))

library(magrittr)

filter(X, !!sym(i) > 0) %$% 
  n_distinct(b)

Кроме того, не имеет прямого отношения к вашему вопросу, есть удобная функция для такого рода вещей

map_dfr(str_subset(colnames(X), "a"), function(i) {

  value <- filter(X, !!sym(i) > 0) %>% {n_distinct(.$b)}

  tibble(y = i, n_uniq = value)

})
1 голос
/ 14 января 2020

Вот минимальный пример того, что, я думаю, вы видите.

iris %>%
  n_distinct(.$Species)
# 149

n_distinct(iris$Species)
# 3

Первый вариант на самом деле делает следующее. .$Species является избыточным.

n_distinct(iris, iris$Species)
# 149

Я думаю, что это можно передать без использования странных синтаксических вещей, которые вам необходимо использовать.

iris %>%
  distinct(Species) %>% 
  count()
# 3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...