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.


é 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"

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"]]

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)

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)  

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.


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.


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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.