Извлечь столбец 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.

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

nacnudus
источник
является 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)
StanislawSwierc
источник
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 предназначен для работы с таблицами данных, лучшего способа получить один столбец данных не существует.

Hadley
источник
Не могу сказать справедливее, чем это. Он возник в интерактивном режиме в консоли, когда я попытался использовать уникальный (таблица $ 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.

Кит Хьюджитт
источник