【问题标题】:Extract a dplyr tbl column as a vector提取 dplyr tbl 列作为向量
【发布时间】:2014-03-04 07:32:45
【问题描述】:

有没有更简洁的方法从具有数据库后端的 tbl 中获取 dplyr tbl 的一列作为向量(即数据框/表不能直接作为子集)?

require(dplyr)
db <- src_sqlite(tempfile(), create = TRUE)
iris2 <- copy_to(db, iris)
iris2$Species
# NULL

那太容易了,所以

collect(select(iris2, Species))[, 1]
# [1] "setosa"     "setosa"     "setosa"     "setosa"  etc.

不过好像有点笨拙。

【问题讨论】:

  • collect(iris2)$Species 不那么笨拙了吗?

标签: r dplyr lazy-evaluation collect


【解决方案1】:

如果 dplyr >= 0.7.0,您可以使用 pulltbl 获取向量。


library("dplyr")
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
db <- src_sqlite(tempfile(), create = TRUE)
iris2 <- copy_to(db, iris)
vec <- pull(iris2, Species)
head(vec)
#> [1] "setosa" "setosa" "setosa" "setosa" "setosa" "setosa"

【讨论】:

    【解决方案2】:

    如果您习惯于使用方括号进行索引,另一种选择是将通常的索引方法封装在对 deframe() 的调用中,例如:

    library(tidyverse)
    
    iris2 <- as_tibble(iris)
    
    # using column name
    deframe(iris2[, 'Sepal.Length'])
    
    # [1] 5.1 4.9 4.7 4.6 5.0 5.4
    
    # using column number
    deframe(iris2[, 1])
    
    # [1] 5.1 4.9 4.7 4.6 5.0 5.4
    

    that 和 pull() 都是获取 tibble 列的好方法。

    【讨论】:

      【解决方案3】:

      根据@nacnudus 的评论,似乎在 dplyr 0.6 中实现了 pull 函数:

      iris2 %>% pull(Species)
      

      对于旧版本的 dplyr,这里有一个简洁的功能,可以让拉出一列更好一些(更容易输入,更容易阅读):

      pull <- function(x,y) {x[,if(is.name(substitute(y))) deparse(substitute(y)) else y, drop = FALSE][[1]]}
      

      这使您可以执行以下任一操作:

      iris2 %>% pull('Species')
      iris2 %>% pull(Species)
      iris2 %>% pull(5)
      

      导致...

       [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7 15.0 21.4
      

      它也适用于数据框:

      > mtcars %>% pull(5)
       [1] 3.90 3.90 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 3.92 3.07 3.07 3.07 2.93 3.00 3.23 4.08 4.93 4.22 3.70 2.76 3.15 3.73 3.08 4.08 4.43
      [28] 3.77 4.22 3.62 3.54 4.11
      

      dplyr 的 v0.2 中实现这一点的好方法:

      iris2 %>% select(Species) %>% collect %>% .[[5]]
      

      或者,如果您愿意:

      iris2 %>% select(Species) %>% collect %>% .[["Species"]]
      

      或者,如果您的桌子不是太大,只需...

      iris2 %>% collect %>% .[["Species"]]
      

      【讨论】:

      • 我喜欢你的拉取功能。对于只有一个变量的情况,我只想添加一个简化:pull &lt;- function(x, y) { if (ncol(x) == 1) y &lt;- 1 else y x[ , if (is.name(substitute(y))) deparse(substitute(y)) else y, drop = FALSE][[1]] },这样您就可以使用iris2 %&gt;% pull()
      • 您还可以使用 magrittr 展示运算符 (%$%) 从数据框中提取向量。即iris2 %&gt;% select(Species) %&gt;% collect() %$% Species.
      • @Luke1018 你应该从这个评论中创建一个答案
      • pull() 将在 dplyr 0.6 版中实现 github.com/tidyverse/dplyr/commit/…
      【解决方案4】:

      @Luke1018 在其中一个 cmets 中提出了这个解决方案:

      您还可以使用 magrittr 展示运算符 (%$%) 从数据框中提取矢量。

      例如:

      iris2 %>% select(Species) %>% collect() %$% Species
      

      我认为它应该得到自己的答案。

      【讨论】:

      • 我在找这个。
      • 如果我想传递的不是 colname 本身而是包含它的字符串变量,我该怎么做?
      • @mzuba tibble(x = 1:10, y = letters[1:10]) %&gt;% select_("x") %&gt;% unlist() 如果需要,您还可以在末尾添加另一个 %&gt;% unname(),但出于我的目的,我还没有发现最后一个管道链链接是必要的。您还可以在unlist() 命令中指定use.names = FALSE,这与将unname() 添加到管道链中的作用相同。
      • @mzuba 我现在会使用pull 命令。我的解决方案是在dplyr 0.6 版之前编写的。
      • 请注意,%$% 适用于任何列表,而 pull() 不适用
      【解决方案5】:

      您也可以使用unlist,我觉得它更易于阅读,因为您不需要重复列名或指定索引。

      iris2 %>% select(Species) %>% unlist(use.names = FALSE)
      

      【讨论】:

      • 这似乎是最通用的方法,因为它与向量和 data.frames 的工作方式相同,即它使函数更加不可知。
      • 我只是在寻找这个确切问题的答案,而unlist 正是我所需要的。谢谢!
      • unlist 还可以从多列中提取值(将所有值组合成一个向量),而dplyr::pull 仅限于一列。
      【解决方案6】:

      我会使用magrittr 中的extract2 便利功能:

      library(magrittr)
      library(dplyr)
      
      iris2 %>%
        select(Species) %>%
        extract2(1)  
      

      【讨论】:

      • 您的意思是在selectextract2 之间使用collect() 吗?
      • use_series(Species) 可能更具可读性。感谢您提醒我注意这些功能,还有其他几个方便的功能。
      【解决方案7】:

      我可能会写:

      collect(select(iris2, Species))[[1]]
      

      由于 dplyr 是为处理 tbls 数据而设计的,因此没有更好的方法来获取单列数据。

      【讨论】:

      • 不能说比这更公平了。当我尝试使用 unique(table$column) 检查虚假值时,它在控制台中以交互方式出现。
      • @nacnudus 对于这种情况,您也可以这样做 group_by(column) %.% tally()
      • drop = TRUEdplyr::select 的参数对于我们实际需要提取向量的许多用例来说将是惊人的。
      • 这是我从 Sparklyr sdf 中获取列的唯一方法。在 0.7.8 版本上,Pull 不适用于我。
      猜你喜欢
      • 2016-06-07
      • 1970-01-01
      • 2011-04-24
      • 1970-01-01
      • 2021-10-15
      • 1970-01-01
      相关资源
      最近更新 更多