Выбор строк из фрейма данных на основе значений в векторе

#r #filter #dplyr

#r #подмножество #r-faq

Вопрос:

У меня есть данные, похожие на это:

 dt <- structure(list(fct = structure(c(1L, 2L, 3L, 4L, 3L, 4L, 1L, 2L, 3L, 1L, 2L, 3L, 2L, 3L, 4L), .Label = c("a", "b", "c", "d"), class = "factor"), X = c(2L, 4L, 3L, 2L, 5L, 4L, 7L, 2L, 9L, 1L, 4L, 2L, 5L, 4L, 2L)), .Names = c("fct", "X"), class = "data.frame", row.names = c(NA, -15L))
 

Я хочу выбрать строки из этого фрейма данных на основе значений в fct переменной. Например, если я хочу выбрать строки, содержащие либо «a», либо «c», я могу сделать это:

 dt[dt$fct == 'a' | dt$fct == 'c', ]
 

что дает

 1    a 2
3    c 3
5    c 5
7    a 7
9    c 9
10   a 1
12   c 2
14   c 4
 

как и ожидалось. Но мои фактические данные более сложные, и я действительно хочу выбирать строки на основе значений в векторе, таких как

 vc <- c('a', 'c')
 

Итак, я попытался

 dt[dt$fct == vc, ]
 

но, конечно, это не работает. Я знаю, что мог бы закодировать что-нибудь, чтобы перебирать вектор, извлекать нужные строки и добавлять их в новый фрейм данных, но я надеялся, что есть более элегантный способ.

Итак, как я могу фильтровать / подмножествовать свои данные на основе содержимого вектора vc ?

Комментарии:

1. попробуйте: dt[dt$fct %in% vc,] в основном == для одного элемента и %in% для векторного сравнения.

Ответ №1:

Взгляните на ?"%in%" .

 dt[dt$fct %in% vc,]
   fct X
1    a 2
3    c 3
5    c 5
7    a 7
9    c 9
10   a 1
12   c 2
14   c 4
 

Вы также можете использовать ?is.element :

 dt[is.element(dt$fct, vc),]
 

Комментарии:

1. is.element это наиболее интуитивно понятно.

Ответ №2:

Аналогично приведенному выше, используя filter из dplyr :

 filter(df, fct %in% vc)
 

Ответ №3:

Другим вариантом было бы использовать data.table :

 library(data.table)
setDT(dt, key = 'fct')[J(vc)]  # or: setDT(dt, key = 'fct')[.(vc)]
 

что приводит к:

    fct X
1:   a 2
2:   a 7
3:   a 1
4:   c 3
5:   c 5
6:   c 9
7:   c 2
8:   c 4
 

Что это делает:

  • setDT(dt, key = 'fct') преобразует data.frame в a data.table (который является расширенной формой a data.frame ) с fct помощью столбца, установленного в качестве ключа.
  • Далее вы можете просто подмножество с vc вектором [J(vc)] с.

ПРИМЕЧАНИЕ: когда ключ является переменной фактора / символа, вы также можете использовать setDT(dt, key = 'fct')[vc] , но это не сработает, если vc это числовой вектор. When vc является числовым вектором и не заключен в J() or .() , vc будет работать как rowindex .

Более подробное объяснение концепции ключей и подмножеств можно найти в ключах виньетки и подмножестве на основе быстрого двоичного поиска.

Альтернатива, предложенная @Frank в комментариях:

 setDT(dt)[J(vc), on=.(fct)]
 

Если vc содержит значения, которых нет в dt , вам нужно добавить nomatch = 0 :

 setDT(dt, key = 'fct')[J(vc), nomatch = 0]
 

или:

 setDT(dt)[J(vc), on=.(fct), nomatch = 0]
 

Комментарии:

1. Я не могу заставить это работать, когда вектор и переменная в data.table являются числовыми. Есть идеи?

2. @GauravSinghal обновил ответ, метод в предыдущей версии работал для столбцов символов / коэффициентов; обновленный метод также работает для целых / числовых столбцов

3. @David есть ли способ изменить это, чтобы выбирать только там, где ftc НЕТ в vc?

4. @user2017023, да, например setDT(dt)[!(vc), on=.(fct)]