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.


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"

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

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)

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)  

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.


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.


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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.