Extrahieren Sie eine dplyr tbl-Spalte als Vektor

175

Gibt es eine prägnantere Möglichkeit, eine Spalte eines dplyr tbl als Vektor aus einem tbl mit Datenbank-Backend zu erhalten (dh der Datenrahmen / die Tabelle kann nicht direkt untergeordnet werden)?

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

Das wäre also zu einfach gewesen

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

Aber es scheint ein bisschen ungeschickt.

Nacnudus
quelle
ist collect(iris2)$Speciesweniger ungeschickt?
CJ Yetman

Antworten:

178

Mit dplyr 0.7.0 können Sie pulleinen Vektor von a erhalten 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
quelle
96

Laut dem Kommentar von @nacnudus scheint eine pullFunktion in dplyr 0.6 implementiert worden zu sein:

iris2 %>% pull(Species)

Für ältere Versionen von dplyr gibt es eine nette Funktion, um das Herausziehen einer Spalte ein bisschen schöner zu machen (einfacher zu tippen und leichter zu lesen):

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

Auf diese Weise können Sie eine der folgenden Aktionen ausführen:

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

Ergebend...

 [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

Und es funktioniert auch gut mit Datenrahmen:

> 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

Ein guter Weg, dies in Version 0.2 von zu tun dplyr:

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

Oder wenn Sie es vorziehen:

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

Oder wenn Ihr Tisch nicht zu groß ist, einfach ...

iris2 %>% collect %>% .[["Species"]]
Tommy O'Dell
quelle
2
Ich mag deine Pull-Funktion. Ich möchte nur eine Vereinfachung für Fälle hinzufügen, in denen es nur eine Variable gibt: 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]] }Sie können also mitiris2 %>% pull()
Rappster
7
Sie können auch den magrittrExpositionsoperator ( %$%) verwenden, um einen Vektor aus einem Datenrahmen zu ziehen. dh iris2 %>% select(Species) %>% collect() %$% Species.
Seeschmied
@ Luke1018 Sie sollten eine Antwort aus diesem Kommentar
erstellen
pull()wird in dplyr Version 0.6 implementiert github.com/tidyverse/dplyr/commit/…
nacnudus
72

Sie können auch verwenden, unlistwas ich leichter zu lesen finde, da Sie den Namen der Spalte nicht wiederholen oder den Index angeben müssen.

iris2 %>% select(Species) %>% unlist(use.names = FALSE)
StanislawSwierc
quelle
1
Dies scheint die vielseitigste Methode zu sein, da sie identisch mit Vektoren und Datenrahmen funktioniert, dh Funktionen ermöglicht, agnostischer zu sein.
Geotheory
Ich habe nur nach einer Antwort auf genau diese Frage gesucht und unlistbin genau das, was ich brauchte. Vielen Dank!
Andrew Brēza
unlistkann auch Werte aus mehreren Spalten extrahieren (alle Werte zu einem einzigen Vektor kombinieren), während dies dplyr::pullauf eine einzelne Spalte beschränkt ist.
Filups21
21

Ich würde die extract2Komfortfunktion von verwenden magrittr:

library(magrittr)
library(dplyr)

iris2 %>%
  select(Species) %>%
  extract2(1)  
Hugh
quelle
Wollten Sie collect()zwischen selectund verwenden extract2?
Nacnudus
10
use_series(Species)ist vielleicht noch besser lesbar. Vielen Dank, dass Sie mich auf diese Funktionen aufmerksam gemacht haben. Es gibt noch einige andere nützliche Funktionen, von denen diese stammen.
Nacnudus
20

Ich würde wahrscheinlich schreiben:

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

Da dplyr für die Arbeit mit Datenblöcken ausgelegt ist, gibt es keinen besseren Weg, um eine einzelne Datenspalte abzurufen.

Hadley
quelle
Kann nicht fairer sagen. Es trat interaktiv in der Konsole auf, als ich versuchte, mit unique (table $ column) nach falschen Werten zu suchen.
Nacnudus
4
@nacnudus für diesen Fall könnten Sie auch tungroup_by(column) %.% tally()
Hadley
12
Ein Argument drop = TRUEdafür dplyr::selectwäre erstaunlich für die vielen Anwendungsfälle, in denen wir die Vektoren tatsächlich extrahieren müssen.
Antoine Lizée
Nur so konnte ich eine Kolumne aus meinem Sparklyr-PDF herausholen. Pull funktionierte bei Version 0.7.8 nicht für mich.
Meep
16

@ Luke1018 schlug diese Lösung in einem der Kommentare vor:

Sie können auch den magrittrExpositionsoperator ( %$%) verwenden, um einen Vektor aus einem Datenrahmen zu ziehen.

Beispielsweise:

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

Ich dachte, es hätte eine eigene Antwort verdient.

rrs
quelle
Ich habe danach gesucht.
Diego-MX
Wie würde ich das tun, wenn ich nicht den Spaltennamen selbst übergeben möchte, sondern eine Zeichenfolgenvariable, die ihn enthält?
Mzuba
@mzuba tibble(x = 1:10, y = letters[1:10]) %>% select_("x") %>% unlist()und Sie könnten %>% unname()am Ende auch ein weiteres hinzufügen, wenn Sie möchten, aber für meine Zwecke habe ich nicht festgestellt, dass das letzte Rohrkettenglied notwendig ist. Sie können auch use.names = FALSEim unlist()Befehl angeben , was dasselbe tut wie das Hinzufügen unname()zur Rohrkette.
Mark White
1
@mzuba Ich würde pulljetzt den Befehl verwenden. Meine Lösung wurde vor dplyrVersion 0.6 geschrieben.
rrs
1
Beachten Sie, dass %$%auf jeder Liste funktioniert, während pull()nicht
wint3rschlaefer
2

Wenn Sie es gewohnt sind, eckige Klammern für die Indizierung zu verwenden, können Sie auch den üblichen Indizierungsansatz in einen Aufruf von deframe () einschließen , z.

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

Das und pull () sind beide ziemlich gute Möglichkeiten, eine Tibble-Spalte zu erhalten.

Keith Hughitt
quelle