Extraire une colonne tbl dplyr en tant que vecteur


175

Existe-t-il un moyen plus succinct d'obtenir une colonne d'un tbl dplyr en tant que vecteur, à partir d'un tbl avec une base de données principale (c'est-à-dire que la trame / table de données ne peut pas être directement sous-ensemble)?

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

Cela aurait été trop facile, alors

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

Mais cela semble un peu maladroit.


est collect(iris2)$Speciesmoins maladroit?
CJ Yetman

Réponses:


178

Avec dplyr 0.7.0, vous pouvez utiliser pullpour obtenir un vecteur à partir d'un fichier 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

Selon le commentaire de @nacnudus, il semble qu'une pullfonction a été implémentée dans dplyr 0.6:

iris2 %>% pull(Species)

Pour les anciennes versions de dplyr, voici une fonction intéressante pour rendre l'extraction d'une colonne un peu plus agréable (plus facile à taper et plus facile à lire):

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

Cela vous permet de faire l'une des choses suivantes:

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

Résultant en...

 [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

Et cela fonctionne également très bien avec les trames de données:

> 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

Une bonne façon de faire cela dans la v0.2 de dplyr:

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

Ou si vous préférez:

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

Ou si votre table n'est pas trop grande, tout simplement ...

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

2
J'aime votre fonction pull. Je voudrais simplement ajouter une simplification pour les cas où il n'y a qu'une seule variable: 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]] }vous pouvez donc y aller aveciris2 %>% pull()
Rappster

7
Vous pouvez également utiliser l' magrittropérateur d'exposition ( %$%) pour extraire un vecteur d'un bloc de données. ie iris2 %>% select(Species) %>% collect() %$% Species.
Seasmith

@ Luke1018, vous devriez créer une réponse à partir de ce commentaire
rrs

pull()sera implémenté dans la version 0.6 de dplyr github.com/tidyverse/dplyr/commit/…
nacnudus

72

Vous pouvez également utiliser unlistce que je trouve plus facile à lire car vous n'avez pas besoin de répéter le nom de la colonne ou de spécifier l'index.

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

1
Cela semble la méthode la plus polyvalente car elle fonctionne de manière identique avec les vecteurs et les data.frames, c'est-à-dire qu'elle permet aux fonctions d'être plus agnostiques.
geotheory

Je cherchais juste une réponse à cette question exacte et unlistc'est précisément ce dont j'avais besoin. Merci!
Andrew Brēza

unlistpeut également extraire des valeurs de plusieurs colonnes (combinant toutes les valeurs dans un seul vecteur), tout en dplyr::pullétant limité à une seule colonne.
filups21

21

J'utiliserais la extract2fonction de commodité de magrittr:

library(magrittr)
library(dplyr)

iris2 %>%
  select(Species) %>%
  extract2(1)  

Vouliez-vous utiliser collect()entre selectet extract2?
nacnudus

10
use_series(Species)est peut-être encore plus lisible. Merci de m'avoir alerté sur ces fonctions, il y en a plusieurs autres pratiques d'où cela vient.
nacnudus

20

J'écrirais probablement:

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

Puisque dplyr est conçu pour travailler avec des tbls de données, il n'y a pas de meilleur moyen d'obtenir une seule colonne de données.


Je ne peux pas dire plus juste que ça. Il est apparu de manière interactive dans la console lorsque j'ai essayé d'utiliser unique (table $ column) pour vérifier les valeurs fausses.
nacnudus

4
@nacnudus pour ce cas, vous pouvez également le fairegroup_by(column) %.% tally()
hadley

12
Un argument drop = TRUEde dplyr::selectserait incroyable pour les très nombreux cas d'utilisation où nous avons réellement besoin pour extraire les vecteurs.
Antoine Lizée

C'était la seule façon pour moi d'obtenir une colonne de mon Sparklyr sdf. Pull ne fonctionnait pas pour moi sur la version 0.7.8.
Meep

16

@ Luke1018 a proposé cette solution dans l'un des commentaires:

Vous pouvez également utiliser l' magrittropérateur d'exposition ( %$%) pour extraire un vecteur d'un bloc de données.

Par exemple:

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

J'ai pensé qu'il méritait sa propre réponse.


Je cherchais ceci.
Diego-MX

Comment ferais-je cela si je ne veux pas transmettre le nom de la colonne lui-même mais une variable de chaîne qui le contient?
mzuba

@mzuba tibble(x = 1:10, y = letters[1:10]) %>% select_("x") %>% unlist()et vous pouvez également en ajouter un autre %>% unname()à la fin si vous le souhaitez, mais pour mes besoins, je n'ai pas trouvé que le dernier maillon de la chaîne de tuyaux était nécessaire. Vous pouvez également spécifier use.names = FALSEdans la unlist()commande, qui fait la même chose que l'ajout unname()sur la chaîne de tuyaux.
Mark White

1
@mzuba J'utiliserais la pullcommande maintenant. Ma solution a été écrite avant la dplyrversion 0.6.
rrs

1
Notez que les %$%travaux sur une liste, alors que pull()ne le fait pas
wint3rschlaefer

3

Si vous avez l'habitude d'utiliser des crochets pour l'indexation, une autre option consiste simplement à envelopper l'approche d'indexation habituelle dans un appel à deframe () , par exemple:

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

Cela et pull () sont tous deux de très bons moyens d'obtenir une colonne tibble.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.