dplyr подсчитывает уникальные значения в двух столбцах без изменения формы - PullRequest
1 голос
/ 03 августа 2020

Как лучше всего подсчитать уникальные значения в двух столбцах без изменения формы, используя dplyr?

Я знаю, что добавление нескольких аргументов в n_distinct приводит к подсчету комбинаций нескольких аргументов (https://github.com/tidyverse/dplyr/issues/1084). Это не то, что я хочу.

Сначала я предполагал использовать c() в двух столбцах, но результат оказался не таким, как я ожидал. Может ли кто-нибудь объяснить, откуда берется вывод?

Одно из возможных решений - использовать union. Есть ли лучшая альтернатива?

library(dplyr)
d <- data.frame(Group = c("A", "B", "B", "C", "C", "C"),
                node1 = c("a", "b", "b", "c", "c", "c"),
                node2 = c("w", "r", "t", "z", "u", "i" )
                )



# count unique combinations
d %>%
  group_by(Group) %>%
  mutate( n = n_distinct( node1, node2))

# A tibble: 6 x 4
# Groups:   Group [3]
  Group node1 node2     n
  <fct> <fct> <fct> <int>
1 A     a     w         1
2 B     b     r         2
3 B     b     t         2
4 C     c     z         3
5 C     c     u         3
6 C     c     i         3



# what happens here?
d %>%
  group_by(Group) %>%
  mutate( n = n_distinct( c(node1, node2)))

# A tibble: 6 x 4
# Groups:   Group [3]
  Group node1 node2     n
  <fct> <fct> <fct> <int>
1 A     a     w         2
2 B     b     r         2
3 B     b     t         2
4 C     c     z         4
5 C     c     u         4
6 C     c     i         4



# count unique in node1 and node2
d %>%
  group_by(Group) %>%
  mutate( n = n_distinct( union(node1, node2)))

# A tibble: 6 x 4
# Groups:   Group [3]
  Group node1 node2     n
  <fct> <fct> <fct> <int>
1 A     a     w         2
2 B     b     r         3
3 B     b     t         3
4 C     c     z         4
5 C     c     u         4
6 C     c     i         4

Я работаю над Ubuntu:

sessionInfo() 


R version 3.6.3 (2020-02-29)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.4 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.7.1
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.7.1

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=de_CH.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=de_CH.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=de_CH.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=de_CH.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] dplyr_1.0.1

loaded via a namespace (and not attached):
 [1] fansi_0.4.0      assertthat_0.2.1 utf8_1.1.4       crayon_1.3.4     R6_2.4.0         lifecycle_0.2.0 
 [7] magrittr_1.5     pillar_1.4.2     cli_2.0.2        rlang_0.4.7      rstudioapi_0.10  vctrs_0.3.2     
[13] generics_0.0.2   tools_3.6.3      glue_1.4.1       purrr_0.3.3      compiler_3.6.3   pkgconfig_2.0.3 
[19] tidyselect_1.1.0 tibble_2.1.3 

Ответы [ 3 ]

2 голосов
/ 03 августа 2020

Альтернативой является использование c_across() после dplyr 1.0.0:

library(dplyr)

d %>%
  group_by(Group) %>%
  mutate(n = n_distinct(c_across(everything())))

# # A tibble: 6 x 4
# # Groups:   Group [3]
#   Group node1 node2     n
#   <chr> <chr> <chr> <int>
# 1 A     a     w         2
# 2 B     b     r         3
# 3 B     b     t         3
# 4 C     c     z         4
# 5 C     c     u         4
# 6 C     c     i         4

Примечание: everything() в c_across() исключает группировку переменные, то есть Group, поэтому на самом деле n_distinct() принимает c(node1, node2) в качестве входных данных. Чтобы указать переменные, вы также можете использовать

  • c_across(node1:node2)
  • c_across(starts_with('node'))
2 голосов
/ 03 августа 2020

Я думаю, что ваше решение с c и union лучше, но в качестве альтернативы вы можете использовать cur_data() из dplyr 1.0.0

library(dplyr)
d %>% group_by(Group) %>% mutate(n = n_distinct(unlist(cur_data())))


#  Group node1 node2     n
#  <chr> <chr> <chr> <int>
#1 A     a     w         2
#2 B     b     r         3
#3 B     b     t         3
#4 C     c     z         4
#5 C     c     u         4
#6 C     c     i         4

Обратите внимание, что cur_data() возвращает полные данные для каждой группы, исключая группирующие переменные. Итак, если у вас есть другие столбцы в данных и вы хотите включить только "node" столбцы в n_distinct, вам нужно сделать:

d %>%
  group_by(Group) %>%
  mutate(n = n_distinct(unlist(select(cur_data(), starts_with('node')))))
0 голосов
/ 03 августа 2020

Мы можем изменить форму до «длинного» формата, а затем выполнить группировку по n_distinct

library(dplyr)
library(tidyr)
d %>%
     pivot_longer(cols = -Group) %>% 
     group_by(Group) %>%
     summarise(n = n_distinct(value)) %>%
     left_join(d)
...