Função semelhante a group_by quando os grupos não são mutuamente excludentes

Eu gostaria de criar uma função em R, semelhante adplyrégroup_by função, que quando combinada comsummarise pode fornecer estatísticas resumidas para um conjunto de dados em quea associação ao grupo não é mutuamente exclusiva. Ou seja, as observações podem pertencer a vários grupos. Uma maneira de pensar sobre isso pode ser considerar as tags; as observações podem pertencer a uma ou mais tags que podem se sobrepor.

Por exemplo, pegue R'sesoph conjunto de dados (https://stat.ethz.ch/R-manual/R-devel/library/datasets/html/esoph.html) documentando um estudo caso-controle de câncer de esôfago. Suponha que eu esteja interessado no número e na proporção de casos de câncer em geral e por 'etiqueta', onde as etiquetas têm: 65 anos ou mais; 80+ g / dia de álcool; 20+ gm / dia de tabaco; e um grupo de 'alto risco' em que os três critérios anteriores foram atendidos. Vamos transformar o conjunto de dados em formato longo (um participante por linha) e depois adicionar essas tags (colunas lógicas) ao conjunto de dados:

library('dplyr')
data(esoph)
esophlong = bind_rows(esoph %>% .[rep(seq_len(nrow(.)), .$ncases), 1:3] %>% mutate(case=1),
                      esoph %>% .[rep(seq_len(nrow(.)), .$ncontrols), 1:3] %>% mutate(case=0)
            ) %>% 
            mutate(highage=(agegp %in% c('65-74','75+')),
                   highalc=(alcgp %in% c('80-119','120+')),
                   hightob=(tobgp %in% c('20-29','30+')),
                   highrisk=(highage & highalc & hightob)
            )

Minha abordagem usual é criar um conjunto de dados em que cada observação seja duplicada para cada tag a que pertence e, em seguida,summarise este conjunto de dados:

esophdup = bind_rows(esophlong %>% filter(highage) %>% mutate(tag='age>=65'),
                     esophlong %>% filter(highalc) %>% mutate(tag='alc>=80'),
                     esophlong %>% filter(hightob) %>% mutate(tag='tob>=20'),
                     esophlong %>% filter(highrisk) %>% mutate(tag='high risk'),
                     esophlong %>% filter() %>% mutate(tag='all')
           ) %>%
           mutate(tag=factor(tag, levels = unique(.$tag)))

summary = esophdup %>%
          group_by(tag) %>%
          summarise(n=n(), ncases=sum(case), case.rate=mean(case))

Essa abordagem é ineficiente para grandes conjuntos de dados ou para um grande número de tags, e geralmente ficarei sem memória para armazená-lo.

Uma alternativa ésummarise cada tag separadamente e vincule esses conjuntos de dados de resumo posteriormente, da seguinte maneira:

summary.age = esophlong %>%
              filter(highage) %>%
              summarise(n=n(), ncases=sum(case), case.rate=mean(case)) %>%
              mutate(tag='age>=65')

summary.alc = esophlong %>%
              filter(highalc) %>%
              summarise(n=n(), ncases=sum(case), case.rate=mean(case)) %>%
              mutate(tag='alc>=80')

summary.tob = esophlong %>%
              filter(hightob) %>%
              summarise(n=n(), ncases=sum(case), case.rate=mean(case)) %>%
              mutate(tag='tob>=20')

summary.highrisk = esophlong %>%
              filter(highrisk) %>%
              summarise(n=n(), ncases=sum(case), case.rate=mean(case)) %>%
              mutate(tag='high risk')

summary.all = esophlong %>%
              summarise(n=n(), ncases=sum(case), case.rate=mean(case)) %>%
              mutate(tag='all')

summary=bind_rows(summary.age,summary.alc,summary.tob,summary.highrisk,summary.all)  

Essa abordagem é demorada e tediosa quando tenho um grande número de tags ou desejo reutilizá-las frequentemente para diferentes medidas de resumo em um projeto.

A função que tenho em mente, digamosgroup_by_tags(data, key, ...), que inclui um argumento para especificar o nome da coluna de agrupamento, deve funcionar da seguinte maneira:

summary = esophlong %>% 
          group_by_tags(key='tags',
                        'age>=65'=highage,
                        'alc>=80'=highalc,
                        'tob>=20'=hightob,
                        'high risk'=highrisk,
                        'all ages'=1
          ) %>%
          summarise(n=n(), ncases=sum(case), case.rate=mean(case))

com o conjunto de dados de resumo parecido com este:

> summary
       tags     n ncases case.rate
1   age>=65   273     68 0.2490842
2   alc>=80   301     96 0.3189369
3   tob>=20   278     64 0.2302158
4 high risk    11      5 0.4545455
5       all  1175    200 0.1702128

Melhor ainda, poderia levar variáveis do tipo "fator" e também "lógicas" para resumir, por exemplo, cada faixa etária individualmente, as pessoas com mais de 65 anos e todos:

summaryage = esophlong %>% 
          group_by_tags(key='Age.group',
                        agegp,
                        '65+'=(agegp %in% c('65-74','75+')),
                        'all'=1                 
          ) %>%
          summarise(n=n(), ncases=sum(case), case.rate=mean(case))

>summaryage
  Age.group     n ncases case.rate
1     25-34   117      1 0.0085470
2     35-44   208      9 0.0432692
3     45-54   259     46 0.1776062
4     55-64   318     76 0.2389937
5     65-74   216     55 0.2546296
6       75+    57     13 0.2280702
7       65+   273     68 0.2490842
8       all  1175    200 0.1702128

Talvez não seja possível com... e, em vez disso, pode ser necessário passar um vetor / lista de nomes de colunas para as tags.

Alguma ideia?

EDIT: para ficar claro, a solução deve usar as definições de tags / grupos e as estatísticas de resumo necessárias como argumentos, em vez de serem incorporadas à própria função. Ou em duas etapasdata %>% group_by_tags(tags) %>% summarise_tags(stats) ou uma etapadata %>% summary_tags(tags,stats) processo.

questionAnswers(5)

yourAnswerToTheQuestion