Извлечь столбец dplyr tbl как вектор


175

Есть ли более краткий способ получить один столбец таблицы dplyr в качестве вектора из таблицы с базой данных (т. Е. Фрейм / таблица данных не может быть поднабором напрямую)?

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

Это было бы слишком легко, так

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

Но это кажется немного неуклюжим.


является collect(iris2)$Speciesменее неуклюжим?
CJ Йетман

Ответы:


178

С dplyr 0.7.0, вы можете использовать, pullчтобы получить вектор из 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

Согласно комментарию @nacnudus, похоже, что pullфункция была реализована в dplyr 0.6:

iris2 %>% pull(Species)

Для более старых версий dplyr, вот изящная функция, которая делает вытягивание столбца более приятным (легче набирать и легче читать):

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

Это позволяет вам выполнить одно из следующих действий:

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

В результате чего...

 [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

И это также прекрасно работает с фреймами данных:

> 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

Хороший способ сделать это в v0.2 из dplyr:

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

Или, если вы предпочитаете:

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

Или, если ваш стол не слишком большой, просто ...

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

2
Мне нравится ваша функция тяги. Я бы просто добавил одно упрощение для случаев, когда есть только одна переменная: 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]] }так что вы можете пойти сiris2 %>% pull()
Rappster

7
Вы также можете использовать magrittrоператор экспозиции ( %$%), чтобы извлечь вектор из фрейма данных. то есть iris2 %>% select(Species) %>% collect() %$% Species.
Судья

@ Luke1018 вы должны создать ответ из этого комментария
РРП

pull()будет осуществляться в dplyr версии 0,6 github.com/tidyverse/dplyr/commit/...
nacnudus

72

Вы также можете использовать то, unlistчто мне легче читать, потому что вам не нужно повторять имя столбца или указывать индекс.

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

1
Это кажется наиболее универсальным методом, так как он работает одинаково с векторами и data.frames, то есть он позволяет функциям быть более независимыми.
геотеория

Я просто искал ответ на этот точный вопрос и unlistименно то, что мне было нужно. Спасибо!
Андрей Бреза

unlistтакже может извлекать значения из нескольких столбцов (объединяя все значения в один вектор), при dplyr::pullэтом ограничивается одним столбцом.
filups21

21

Я бы использовал extract2удобную функцию из magrittr:

library(magrittr)
library(dplyr)

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

Вы имели в виду использовать collect()между selectи extract2?
Накнудус

10
use_series(Species)возможно, даже более читабельным. Спасибо, что предупредили меня об этих функциях, есть несколько других полезных, откуда это пришло.
Накнудус

20

Я бы наверное написал:

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

Поскольку dplyr предназначен для работы с таблицами данных, лучшего способа получить один столбец данных не существует.


Не могу сказать справедливее, чем это. Он возник в интерактивном режиме в консоли, когда я попытался использовать уникальный (таблица $ column) для проверки на ложные значения.
Накнудус

4
@nacnudus для этого случая вы также можете сделатьgroup_by(column) %.% tally()
Хэдли

12
Аргумент drop = TRUEбыл dplyr::selectбы удивительным для довольно многих случаев использования, когда нам действительно нужно извлечь векторы.
Антуан Лизе

Это был единственный способ получить колонку из моего Sparklyr sdf. Pull не работал для меня на версии 0.7.8.
Meep

16

@ Luke1018 предложил это решение в одном из комментариев:

Вы также можете использовать magrittrоператор экспозиции ( %$%), чтобы извлечь вектор из фрейма данных.

Например:

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

Я думал, что это заслуживает своего собственного ответа.


Я искал это.
Diego-MX

Как бы я это сделал, если я хочу передать не само имя colname, а строковую переменную, которая его содержит?
Мзуба

@mzuba, tibble(x = 1:10, y = letters[1:10]) %>% select_("x") %>% unlist()и вы также можете добавить еще один %>% unname()в конце, если хотите, но для моих целей я не нашел нужного последнего звена цепи труб. Вы также можете указать use.names = FALSEв unlist()команде, которая делает то же самое, что и добавление unname()в цепочку каналов.
Марк Уайт

1
@mzuba Я бы использовал pullкоманду сейчас. Мое решение было написано до dplyrверсии 0.6.
РРП

1
Обратите внимание, что %$%работает в любом списке, а pull()не
wint3rschlaefer

3

Если вы привыкли использовать квадратные скобки для индексации, другой вариант - просто обернуть обычный подход к индексированию в вызове deframe () , например:

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

Это и pull () являются довольно хорошими способами получить столбец tibble.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.