【问题标题】:Unexpected behavior with n_distinct inside pipe管道内 n_distinct 的意外行为
【发布时间】:2020-05-01 06:57:08
【问题描述】:

我正在尝试在函数的管道内使用来自dplyrn_distinct 函数,并且发现它以一种我没有预料到的方式对我选择的语法很敏感。这是一个玩具示例。

# 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

好的,现在假设我想在该数据框中选定列的名称上迭代一个函数(幽默)。在这里,我将使用所选列中的值来过滤初始数据集,计算剩余的唯一 ID 的数量,并将结果作为单行 tibble 返回,然后我将其绑定到新的 tibble。当我在函数中创建一个新的 tibble,然后将 n_distinct 应用到该 tibble 中的选定列作为其自己的步骤时,我会从 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 放在管道中并使用 . 来引用过滤后的 tibble,那么代码会执行,但我会得到不同且不正确的结果。

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 有什么时髦之处吗?

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    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)
    
    })
    

    【讨论】:

      【解决方案2】:

      这是我认为您所看到的最小示例。

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

      第一个选项实际上是这样做的。 .$Species 是多余的。

      n_distinct(iris, iris$Species)
      # 149
      

      我认为在不做奇怪的语法的情况下使用它来管道它。

      iris %>%
        distinct(Species) %>% 
        count()
      # 3
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-04
        • 2017-12-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多