Wyodrębnij kolumnę dplyr tbl jako wektor


175

Czy istnieje bardziej zwięzły sposób na pobranie jednej kolumny tabeli dplyr jako wektora z tabeli z zapleczem bazy danych (tj. Ramki / tabeli danych nie można bezpośrednio podzestawiać)?

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

To byłoby zbyt łatwe, więc

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

Ale wydaje się trochę niezdarne.


jest collect(iris2)$Speciesmniej niezdarny?
CJ Yetman

Odpowiedzi:


178

Z dplyr 0.7.0 możesz użyć, pullaby uzyskać wektor z 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

Zgodnie z komentarzem @nacnudus wygląda na to, że pullfunkcja została zaimplementowana w dplyr 0.6:

iris2 %>% pull(Species)

W przypadku starszych wersji dplyr, oto zgrabna funkcja, która sprawia, że ​​wyciąganie kolumny jest nieco ładniejsze (łatwiejsze do wpisania i czytelniejsze):

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

Dzięki temu możesz wykonać jedną z następujących czynności:

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

W rezultacie ...

 [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

Działa również dobrze z ramkami danych:

> 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

Dobry sposób na zrobienie tego w wersji 0.2 z dplyr:

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

Lub jeśli wolisz:

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

A jeśli Twój stół nie jest za duży, po prostu ...

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

2
Podoba mi się twoja funkcja ciągnięcia. Dodałbym tylko jedno uproszczenie dla przypadków, w których jest tylko jedna zmienna: 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]] }więc możesz iść ziris2 %>% pull()
Rappster

7
Możesz także użyć magrittroperatora ekspozycji ( %$%), aby wyciągnąć wektor z ramki danych. tj iris2 %>% select(Species) %>% collect() %$% Species.
seasmith

@ Luke1018 powinieneś utworzyć odpowiedź z tego komentarza
rrs

pull()zostanie zaimplementowany w dplyr w wersji 0.6 github.com/tidyverse/dplyr/commit/…
nacnudus

72

Możesz także użyć tego, unlistco uważam za łatwiejsze do odczytania, ponieważ nie musisz powtarzać nazwy kolumny ani określać indeksu.

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

1
Wydaje się, że jest to najbardziej wszechstronna metoda, ponieważ działa identycznie z wektorami i ramkami data.frames, tj. Umożliwia funkcje bardziej agnostyczne.
geoteoria

Szukałem odpowiedzi na to dokładne pytanie i unlistwłaśnie tego potrzebowałem. Dzięki!
Andrew Brēza,

unlistmoże również wyodrębniać wartości z wielu kolumn (łącząc wszystkie wartości w jeden wektor), ale dplyr::pullogranicza się do jednej kolumny.
filups

21

Skorzystałbym z extract2funkcji wygody z magrittr:

library(magrittr)
library(dplyr)

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

Czy chodziło Ci o użycie collect()między selecti extract2?
nacnudus

10
use_series(Species)jest jeszcze bardziej czytelny. Dzięki za powiadomienie mnie o tych funkcjach, istnieje kilka innych przydatnych, skąd one pochodzą.
nacnudus

20

Prawdopodobnie napisałbym:

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

Ponieważ dplyr jest przeznaczony do pracy z tabelami danych, nie ma lepszego sposobu na uzyskanie pojedynczej kolumny danych.


Nie mogę powiedzieć bardziej sprawiedliwie. Pojawił się interaktywnie w konsoli, gdy próbowałem użyć unikalnego (table $ column) do sprawdzenia fałszywych wartości.
nacnudus,

4
@nacnudus w tym przypadku możesz również zrobićgroup_by(column) %.% tally()
hadley,

12
Argument drop = TRUEdo dplyr::selectbyłby niesamowity w wielu przypadkach użycia, w których faktycznie musimy wyodrębnić wektory.
Antoine Lizée

To był jedyny sposób, w jaki mogłem wyciągnąć kolumnę z mojego Sparklyr sdf. Pull nie działał dla mnie w wersji 0.7.8.
Meep

16

@ Luke1018 zaproponował takie rozwiązanie w jednym z komentarzy:

Możesz także użyć magrittroperatora ekspozycji ( %$%), aby wyciągnąć wektor z ramki danych.

Na przykład:

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

Myślałem, że zasługuje na własną odpowiedź.


Szukałem tego.
Diego-MX

Jak mam to zrobić, jeśli chcę przekazać nie samą nazwę kolumny, ale zmienną łańcuchową, która ją zawiera?
mzuba

@mzuba tibble(x = 1:10, y = letters[1:10]) %>% select_("x") %>% unlist()i %>% unname()jeśli chcesz, możesz też dodać kolejny na końcu, ale dla moich celów nie znalazłem tego ostatniego ogniwa łańcucha rurowego za konieczne. Możesz również określić use.names = FALSEw unlist()poleceniu, które robi to samo, co dodanie unname()do łańcucha rur.
Mark White

1
@mzuba Teraz użyłbym pullpolecenia. Moje rozwiązanie zostało napisane przed dplyrwersją 0.6.
rrs

1
Zauważ, że %$%działa na każdej liście, pull()ale nie
wint3rschlaefer

2

Jeśli jesteś przyzwyczajony do używania nawiasów kwadratowych do indeksowania, inną opcją jest po prostu zawinięcie zwykłego podejścia do indeksowania wywołaniem funkcji deframe () , np .:

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

To i pull () to całkiem dobre sposoby na uzyskanie kolumny tibble.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.