dplyr: Как фильтровать группы по критерию подгруппы

Мой вопрос похож на этот one, но критерии фильтра отличается.

> demo(dadmom,package="tidyr")

> library(tidyr)
> library(dplyr)

> dadmom <- foreign::read.dta("http://www.ats.ucla.edu/stat/stata/modules/dadmomw.dta")

> dadmom %>%
+   gather(key, value, named:incm) %>%
+   separate(key, c("variable", "type"), -2) %>%
+   spread(variable, value, convert = TRUE)
  famid type   inc name
1     1    d 30000 Bill
2     1    m 15000 Bess
3     2    d 22000  Art
4     2    m 18000  Amy
5     3    d 25000 Paul
6     3    m 50000  Pat

Легко выбрать семью с доходом мамы >20000, используя «дюймы» из исходной таблицы:

> dadmom
  famid named  incd namem  incm
1     1  Bill 30000  Bess 15000
2     2   Art 22000   Amy 18000
3     3  Paul 25000   Pat 50000

Вопрос: как вы это делаете из "прибранных" данных?


person Dong    schedule 24.03.2015    source источник
comment
Это возвращает только одну строку. Я хочу всю группу (m&d).   -  person Dong    schedule 24.03.2015


Ответы (1)


Вы можете добавить group_by и filter к кодам

#OP's code
d1 <- dadmom %>%
           gather(key, value, named:incm) %>%
           separate(key, c("variable", "type"), -2) %>%
           spread(variable, value, convert = TRUE)

 d1 %>% 
    group_by(famid) %>%
    filter(all(sum(type=='m' & inc > 15000)==sum(type=='m')))

#    famid type   inc name
# 1     2    d 22000  Art
# 2     2    m 18000  Amy
# 3     3    d 25000 Paul
# 4     3    m 50000  Pat

ПРИМЕЧАНИЕ. Вышеупомянутое также будет работать, когда в одном фамиде несколько букв m (немного более общий вариант).

Для обычных случаев одной пары «м/ж» на семью

 d1 %>%
     group_by(famid) %>% 
     filter(any(inc >15000 & type=='m'))
 #   famid type   inc name
 #1     2    d 22000  Art
 #2     2    m 18000  Amy
 #3     3    d 25000 Paul
 #4     3    m 50000  Pat

Кроме того, если вы хотите использовать data.table, melt из версии devel, то есть v1.9.5 может принимать несколько столбцов значений. Его можно установить с here.

 library(data.table)
 melt(setDT(dadmom), measure.vars=list(c(2,4), c(3,5)), 
    variable.name='type', value.name=c('name', 'inc'))[,
    type:=c('d', 'm')[type]][, .SD[any(type=='m' & inc >15000)] ,famid]
 #    famid type name   inc
 #1:     2    d  Art 22000
 #2:     2    m  Amy 18000
 #3:     3    d Paul 25000
 #4:     3    m  Pat 50000
person akrun    schedule 24.03.2015
comment
Спасибо. Я не был в курсе всего и вся. Являются ли они эффективными функциями? Я спрашиваю, потому что мои фактические данные будут иметь много групп и много строк внутри групп (хотя и очень регулярных, с фиксированным числом и последовательностью). - person Dong; 24.03.2015
comment
@ Дон, я так думаю. Насколько велик ваш набор данных? - person akrun; 24.03.2015
comment
Сейчас не большой. ~(7x200k) --› (7x400k) после уборки. На данный момент это примерно 100 000 групп — например, из group_by(famid), и по 4 строки в группе. Но как ширина, так и длина данных будут расти по мере того, как я буду собирать больше экспериментальных данных. - person Dong; 24.03.2015
comment
@Dong Просто мысль, если она станет большой, не лучше ли было бы подмножество до gather (хотя тесты не проводились) - person akrun; 25.03.2015