Ekstrak kolom tbl dplyr sebagai vektor

175

Apakah ada cara yang lebih ringkas untuk mendapatkan satu kolom dplyr tbl sebagai vektor, dari tbl dengan database back-end (mis. Frame data / tabel tidak dapat diatur secara langsung)?

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

Itu akan terlalu mudah, jadi

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

Tapi sepertinya agak canggung.

nacnudus
sumber
adalah collect(iris2)$Specieskurang kikuk?
CJ Yetman

Jawaban:

178

Dengan dplyr 0.7.0, Anda dapat menggunakan pulluntuk mendapatkan vektor dari 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"
Lorenz Walthert
sumber
96

Sesuai komentar dari @nacnudus, sepertinya ada pullfungsi yang diterapkan di dplyr 0.6:

iris2 %>% pull(Species)

Untuk versi dplyr yang lebih lama, berikut adalah fungsi yang rapi untuk membuat mengeluarkan kolom sedikit lebih bagus (lebih mudah untuk mengetik, dan lebih mudah dibaca):

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

Ini memungkinkan Anda melakukan salah satu dari ini:

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

Yang menghasilkan...

 [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

Dan itu juga berfungsi dengan baik dengan bingkai data:

> 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

Cara yang bagus untuk melakukan ini di v0.2 dari dplyr:

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

Atau jika Anda lebih suka:

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

Atau jika meja Anda tidak terlalu besar, cukup ...

iris2 %>% collect %>% .[["Species"]]
Tommy O'Dell
sumber
2
Saya suka fungsi tarikan Anda. Saya hanya akan menambahkan satu penyederhanaan untuk kasus-kasus di mana hanya ada satu variabel: 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]] }sehingga Anda dapat pergi denganiris2 %>% pull()
Rappster
7
Anda juga dapat menggunakan magrittroperator eksposisi ( %$%) untuk menarik vektor dari bingkai data. yaitu iris2 %>% select(Species) %>% collect() %$% Species.
seasmith
@ Luke1018 Anda harus membuat jawaban dari komentar ini
rrs
pull()akan diimplementasikan dalam versi dplyr
nacnudus
72

Anda juga dapat menggunakan unlistyang menurut saya lebih mudah dibaca karena Anda tidak perlu mengulangi nama kolom atau menentukan indeks.

iris2 %>% select(Species) %>% unlist(use.names = FALSE)
StanislawSwierc
sumber
1
Ini tampaknya metode yang paling serbaguna karena berfungsi identik dengan vektor dan data.frame, yaitu memungkinkan fungsi menjadi lebih agnostik.
geotheory
Saya hanya mencari jawaban untuk pertanyaan yang tepat ini dan unlisttepat apa yang saya butuhkan. Terima kasih!
Andrew Brēza
unlistjuga dapat mengekstraksi nilai dari beberapa kolom (menggabungkan semua nilai ke dalam satu vektor), sementara dplyr::pullterbatas pada satu kolom.
filups21
21

Saya akan menggunakan extract2fungsi kenyamanan dari magrittr:

library(magrittr)
library(dplyr)

iris2 %>%
  select(Species) %>%
  extract2(1)  
Hugh
sumber
Apakah Anda bermaksud menggunakan collect()antara selectdan extract2?
nacnudus
10
use_series(Species)bahkan mungkin lebih mudah dibaca. Terima kasih telah memberi tahu saya tentang fungsi-fungsi ini, ada beberapa yang berguna dari mana datangnya.
nacnudus
20

Saya mungkin akan menulis:

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

Karena dplyr dirancang untuk bekerja dengan tbl data, tidak ada cara yang lebih baik untuk mendapatkan satu kolom data.

Hadley
sumber
Tidak bisa mengatakan lebih adil dari itu. Itu muncul secara interaktif di konsol ketika saya mencoba menggunakan unik (tabel $ kolom) untuk memeriksa nilai palsu.
nacnudus
4
@nacnudus untuk kasus yang juga bisa Anda lakukangroup_by(column) %.% tally()
hadley
12
Argumen drop = TRUEuntuk dplyr::selectmenjadi luar biasa untuk banyak kasus penggunaan di mana kita benar-benar perlu mengekstraksi vektor.
Antoine Lizée
Ini adalah satu-satunya cara saya bisa mendapatkan kolom dari sdf Sparklyr saya. Pull tidak berfungsi untuk saya di versi 0.7.8.
Meep
16

@ Luke1018 mengusulkan solusi ini di salah satu komentar:

Anda juga dapat menggunakan magrittroperator eksposisi ( %$%) untuk menarik vektor dari bingkai data.

Sebagai contoh:

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

Saya pikir itu pantas dijawab sendiri.

rrs
sumber
Saya mencari ini.
Diego-MX
Bagaimana saya melakukan ini jika saya ingin meneruskan bukan colname itu sendiri tetapi variabel string yang berisi itu?
mzuba
@ Mozuba tibble(x = 1:10, y = letters[1:10]) %>% select_("x") %>% unlist()dan Anda juga bisa menambahkan yang lain %>% unname()di akhir jika Anda mau, tetapi untuk tujuan saya, saya belum menemukan bahwa link rantai pipa terakhir diperlukan. Anda juga bisa menentukan use.names = FALSEdalam unlist()perintah, yang melakukan hal yang sama seperti menambahkan unname()ke rantai pipa.
Mark White
1
@ mzuba Saya akan menggunakan pullperintah sekarang. Solusi saya ditulis sebelum dplyrversi 0.6.
rrs
1
Catatan yang %$%berfungsi pada daftar mana pun, sedangkan pull()tidak
wint3rschlaefer
2

Jika Anda terbiasa menggunakan tanda kurung siku untuk pengindeksan, opsi lain adalah dengan hanya membungkus pendekatan pengindeksan biasa dalam panggilan untuk melakukan deframe () , misalnya:

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

Itu dan tarik () keduanya cara yang cukup bagus untuk mendapatkan kolom tibble.

Keith Hughitt
sumber