Extrair uma coluna dplyr tbl como um vetor

175

Existe uma maneira mais sucinta de obter uma coluna de um dplyr tbl como vetor, de um tbl com back-end de banco de dados (ou seja, o quadro / tabela de dados não pode ser subconjunto diretamente)?

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

Isso teria sido fácil demais, então

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

Mas parece um pouco desajeitado.

nacnudus
fonte
é collect(iris2)$Speciesmenos desajeitado?
CJ Yetman #:

Respostas:

178

Com o dplyr 0.7.0, você pode usar pullpara obter um vetor de a tbl.


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"
Lorenz Walthert
fonte
96

De acordo com o comentário do @nacnudus, parece que uma pullfunção foi implementada no dplyr 0.6:

iris2 %>% pull(Species)

Para versões mais antigas do dplyr, aqui está uma função interessante para tornar a extração de uma coluna um pouco melhor (mais fácil de digitar e mais fácil de ler):

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

Isso permite que você execute um destes procedimentos:

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

Resultando em...

 [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

E também funciona bem com quadros de dados:

> 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

Uma boa maneira de fazer isso na v0.2 de dplyr:

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

Ou se você preferir:

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

Ou se sua mesa não for muito grande, simplesmente ...

iris2 %>% collect %>% .[["Species"]]
Tommy O'Dell
fonte
2
Eu gosto da sua função pull. Eu tinha acabado de adicionar uma simplificação para os casos em que há apenas uma variável: pull <- function(x, y) { if (ncol(x) == 1) y <- 1 else y x[ , if (is.name(substitute(y))) deparse(substitute(y)) else y, drop = FALSE][[1]] }assim que você pode ir comiris2 %>% pull()
Rappster
7
Você também pode usar o magrittroperador de exposição ( %$%) para extrair um vetor de um quadro de dados. ie iris2 %>% select(Species) %>% collect() %$% Species.
seasmith
@ Luke1018 você deve criar uma resposta a partir deste comentário
rrs 29/03
pull()será implementado em dplyr versão 0.6 github.com/tidyverse/dplyr/commit/...
nacnudus
72

Você também pode usar o unlistque eu acho mais fácil de ler, porque você não precisa repetir o nome da coluna ou especificar o índice.

iris2 %>% select(Species) %>% unlist(use.names = FALSE)
StanislawSwierc
fonte
1
Este parece ser o método mais versátil, pois trabalha de maneira idêntica com vetores e data.frames, ou seja, permite que as funções sejam mais independentes.
geotheory
Eu estava apenas procurando uma resposta para essa pergunta exata e unlisté exatamente o que eu precisava. Obrigado!
Andrew Brēza
unlisttambém pode extrair valores de várias colunas (combinando todos os valores em um único vetor), enquanto dplyr::pullestá limitado a uma única coluna.
usar o seguinte código
21

Eu usaria a extract2função de conveniência de magrittr:

library(magrittr)
library(dplyr)

iris2 %>%
  select(Species) %>%
  extract2(1)  
Hugh
fonte
Você queria usar collect()entre selecte extract2?
Nacnudus
10
use_series(Species)é talvez ainda mais legível. Obrigado por me alertar sobre essas funções, existem várias outras úteis de onde elas vieram.
Nacnudus
20

Eu provavelmente escreveria:

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

Como o dplyr foi projetado para trabalhar com tbls de dados, não há melhor maneira de obter uma única coluna de dados.

Hadley
fonte
Não posso dizer mais justo do que isso. Surgiu interativamente no console quando tentei usar o exclusivo (tabela $ coluna) para verificar valores espúrios.
Nacnudus
4
@nacnudus, nesse caso, você também poderia fazergroup_by(column) %.% tally()
hadley
12
Um argumento drop = TRUEpara dplyr::selectseria incrível para os muito muitos casos de uso em que realmente precisa para extrair os vetores.
Antoine Lizée
Esta foi a única maneira de obter uma coluna do meu Sparklyr sdf. O Pull não estava funcionando para mim na versão 0.7.8.
Meep
16

@ Luke1018 propôs esta solução em um dos comentários:

Você também pode usar o magrittroperador de exposição ( %$%) para extrair um vetor de um quadro de dados.

Por exemplo:

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

Eu pensei que merecia sua própria resposta.

rrs
fonte
Eu estava procurando por isso.
Diego-MX
Como eu faria isso se eu quisesse passar não o nome da coluna em si, mas uma variável de string que a contenha?
Mzuba # 7/17
@mzuba tibble(x = 1:10, y = letters[1:10]) %>% select_("x") %>% unlist()e você também pode adicionar outro %>% unname()no final, se quiser, mas para os meus propósitos, não achei o último elo da corrente do tubo necessário. Você também pode especificar use.names = FALSEno unlist()comando, que faz o mesmo que adicionar unname()na cadeia de tubos.
Mark White
1
@mzuba Eu usaria o pullcomando agora. Minha solução foi escrita antes da dplyrversão 0.6.
RRS
1
Note-se que %$%funciona em qualquer lista, enquanto pull()não
wint3rschlaefer
2

Se você está acostumado a usar colchetes para indexação, outra opção é apenas envolver a abordagem de indexação usual em uma chamada para deframe () , por exemplo:

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

Isso e pull () são maneiras muito boas de obter uma coluna de petiscos.

Keith Hughitt
fonte